More tests

This commit is contained in:
Toby Zerner 2019-11-16 11:51:27 +10:30
parent d889701ec6
commit 8a4a09bfeb
9 changed files with 360 additions and 54 deletions

View File

@ -32,7 +32,11 @@ class Delete implements RequestHandlerInterface
run_callbacks($schema->getListeners('deleting'), [$this->model, $request]);
$this->resource->getAdapter()->delete($this->model);
if ($deleter = $this->resource->getSchema()->getDelete()) {
$deleter($this->model, $request);
} else {
$this->resource->getAdapter()->delete($this->model);
}
run_callbacks($schema->getListeners('deleted'), [$this->model, $request]);

View File

@ -13,7 +13,6 @@ namespace Tobyz\Tests\JsonApiServer;
use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ResponseInterface;
use Zend\Diactoros\ServerRequest;
use Zend\Diactoros\Uri;

View File

@ -2,6 +2,7 @@
namespace Tobyz\Tests\JsonApiServer;
use Closure;
use Tobyz\JsonApiServer\Adapter\AdapterInterface;
use Tobyz\JsonApiServer\Schema\Attribute;
use Tobyz\JsonApiServer\Schema\Field;
@ -52,12 +53,12 @@ class MockAdapter implements AdapterInterface
return $model->{$this->getProperty($attribute)} ?? 'default';
}
public function getHasOne($model, HasOne $relationship)
public function getHasOne($model, HasOne $relationship, array $fields = null)
{
return $model->{$this->getProperty($relationship)} ?? null;
}
public function getHasMany($model, HasMany $relationship): array
public function getHasMany($model, HasMany $relationship, array $fields = null): array
{
return $model->{$this->getProperty($relationship)} ?? [];
}
@ -121,7 +122,7 @@ class MockAdapter implements AdapterInterface
$query->paginate[] = [$limit, $offset];
}
public function load(array $models, array $relationships): void
public function load(array $models, array $relationships, Closure $scope): void
{
foreach ($models as $model) {
$model->load[] = $relationships;

View File

@ -12,6 +12,7 @@
namespace Tobyz\Tests\JsonApiServer\feature;
use Tobyz\JsonApiServer\JsonApi;
use Tobyz\JsonApiServer\Schema\Type;
use Tobyz\Tests\JsonApiServer\AbstractTestCase;
use Tobyz\Tests\JsonApiServer\MockAdapter;
@ -31,21 +32,58 @@ class CountabilityTest extends AbstractTestCase
{
$this->api = new JsonApi('http://example.com');
$this->adapter = new MockAdapter();
$models = [];
for ($i = 1; $i <= 100; $i++) {
$models[] = (object) ['type' => 'users', 'id' => $i];
}
$this->adapter = new MockAdapter($models, 'users');
}
public function test_total_number_of_resources_and_last_pagination_link_is_included_by_default()
{
$this->markTestIncomplete();
$this->api->resource('users', $this->adapter);
$response = $this->api->handle(
$this->buildRequest('GET', '/users')
);
$document = json_decode($response->getBody(), true);
$this->assertArrayHasKey('last', $document['links'] ?? []);
$this->assertEquals(100, $document['meta']['total'] ?? null);
}
public function test_types_can_be_made_uncountable()
{
$this->markTestIncomplete();
$this->api->resource('users', $this->adapter, function (Type $type) {
$type->uncountable();
});
$response = $this->api->handle(
$this->buildRequest('GET', '/users')
);
$document = json_decode($response->getBody(), true);
$this->assertArrayNotHasKey('last', $document['links'] ?? []);
$this->assertArrayNotHasKey('total', $document['meta'] ?? []);
}
public function test_types_can_be_made_countable()
{
$this->markTestIncomplete();
$this->api->resource('users', $this->adapter, function (Type $type) {
$type->uncountable();
$type->countable();
});
$response = $this->api->handle(
$this->buildRequest('GET', '/users')
);
$document = json_decode($response->getBody(), true);
$this->assertArrayHasKey('last', $document['links'] ?? []);
$this->assertEquals(100, $document['meta']['total'] ?? null);
}
}

View File

@ -11,7 +11,11 @@
namespace Tobyz\Tests\JsonApiServer\feature;
use Psr\Http\Message\ServerRequestInterface;
use Tobyz\JsonApiServer\Adapter\AdapterInterface;
use Tobyz\JsonApiServer\Exception\ForbiddenException;
use Tobyz\JsonApiServer\JsonApi;
use Tobyz\JsonApiServer\Schema\Type;
use Tobyz\Tests\JsonApiServer\AbstractTestCase;
use Tobyz\Tests\JsonApiServer\MockAdapter;
@ -22,58 +26,181 @@ class CreateTest extends AbstractTestCase
*/
private $api;
/**
* @var MockAdapter
*/
private $adapter;
public function setUp(): void
{
$this->api = new JsonApi('http://example.com');
}
$this->adapter = new MockAdapter();
protected function createResource(array $data = [])
{
return $this->api->handle(
$this->buildRequest('POST', '/users')
->withParsedBody([
'data' => array_merge([
'type' => 'users',
'id' => '1',
], $data)
])
);
}
public function test_resources_are_not_creatable_by_default()
{
$this->markTestIncomplete();
$this->api->resource('users', new MockAdapter());
$this->expectException(ForbiddenException::class);
$this->createResource();
}
public function test_resource_creation_can_be_explicitly_enabled()
{
$this->markTestIncomplete();
$this->api->resource('users', new MockAdapter(), function (Type $type) {
$type->creatable();
});
$response = $this->createResource();
$this->assertEquals(201, $response->getStatusCode());
}
public function test_resource_creation_can_be_conditionally_enabled()
{
$this->markTestIncomplete();
$this->api->resource('users', new MockAdapter(), function (Type $type) {
$type->creatable(function () {
return true;
});
});
$response = $this->createResource();
$this->assertEquals(201, $response->getStatusCode());
}
public function test_resource_creation_can_be_explicitly_disabled()
{
$this->markTestIncomplete();
$this->api->resource('users', new MockAdapter(), function (Type $type) {
$type->notCreatable();
});
$this->expectException(ForbiddenException::class);
$this->createResource();
}
public function test_resource_creation_can_be_conditionally_disabled()
{
$this->markTestIncomplete();
$this->api->resource('users', new MockAdapter(), function (Type $type) {
$type->creatable(function () {
return false;
});
});
$this->expectException(ForbiddenException::class);
$this->createResource();
}
public function test_new_models_are_supplied_by_the_adapter()
public function test_resource_creatable_callback_receives_correct_parameters()
{
$this->markTestIncomplete();
$called = false;
$this->api->resource('users', new MockAdapter(), function (Type $type) use (&$called) {
$type->creatable(function ($request) use (&$called) {
$this->assertInstanceOf(ServerRequestInterface::class, $request);
return $called = true;
});
});
$this->createResource();
$this->assertTrue($called);
}
public function test_new_models_are_supplied_and_saved_by_the_adapter()
{
$adapter = $this->prophesize(AdapterInterface::class);
$adapter->create()->willReturn($createdModel = (object) []);
$adapter->save($createdModel)->shouldBeCalled();
$adapter->getId($createdModel)->willReturn('1');
$this->api->resource('users', $adapter->reveal(), function (Type $type) {
$type->creatable();
});
$this->createResource();
}
public function test_resources_can_provide_custom_models()
{
$this->markTestIncomplete();
$createdModel = (object) [];
$adapter = $this->prophesize(AdapterInterface::class);
$adapter->create()->shouldNotBeCalled();
$adapter->save($createdModel)->shouldBeCalled();
$adapter->getId($createdModel)->willReturn('1');
$this->api->resource('users', $adapter->reveal(), function (Type $type) use ($createdModel) {
$type->creatable();
$type->create(function ($request) use ($createdModel) {
$this->assertInstanceOf(ServerRequestInterface::class, $request);
return $createdModel;
});
});
$this->createResource();
}
public function test_creating_a_resource_calls_the_save_adapter_method()
public function test_resources_can_provide_custom_savers()
{
$this->markTestIncomplete();
$called = false;
$adapter = $this->prophesize(AdapterInterface::class);
$adapter->create()->willReturn($createdModel = (object) []);
$adapter->save($createdModel)->shouldNotBeCalled();
$adapter->getId($createdModel)->willReturn('1');
$this->api->resource('users', $adapter->reveal(), function (Type $type) use ($createdModel, &$called) {
$type->creatable();
$type->save(function ($model, $request) use ($createdModel, &$called) {
$model->id = '1';
$this->assertSame($createdModel, $model);
$this->assertInstanceOf(ServerRequestInterface::class, $request);
return $called = true;
});
});
$this->createResource();
$this->assertTrue($called);
}
// saver...
// listeners...
public function test_resources_can_have_creation_listeners()
{
$called = 0;
$adapter = $this->prophesize(AdapterInterface::class);
$adapter->create()->willReturn($createdModel = (object) []);
$adapter->getId($createdModel)->willReturn('1');
$this->api->resource('users', $adapter->reveal(), function (Type $type) use ($adapter, $createdModel, &$called) {
$type->creatable();
$type->creating(function ($model, $request) use ($adapter, $createdModel, &$called) {
$this->assertSame($createdModel, $model);
$this->assertInstanceOf(ServerRequestInterface::class, $request);
$adapter->save($createdModel)->shouldNotHaveBeenCalled();
$called++;
});
$type->created(function ($model, $request) use ($adapter, $createdModel, &$called) {
$this->assertSame($createdModel, $model);
$this->assertInstanceOf(ServerRequestInterface::class, $request);
$adapter->save($createdModel)->shouldHaveBeenCalled();
$called++;
});
});
$this->createResource();
$this->assertEquals(2, $called);
}
}

View File

@ -11,7 +11,11 @@
namespace Tobyz\Tests\JsonApiServer\feature;
use Psr\Http\Message\ServerRequestInterface;
use Tobyz\JsonApiServer\Adapter\AdapterInterface;
use Tobyz\JsonApiServer\Exception\ForbiddenException;
use Tobyz\JsonApiServer\JsonApi;
use Tobyz\JsonApiServer\Schema\Type;
use Tobyz\Tests\JsonApiServer\AbstractTestCase;
use Tobyz\Tests\JsonApiServer\MockAdapter;
@ -22,48 +26,161 @@ class DeleteTest extends AbstractTestCase
*/
private $api;
/**
* @var MockAdapter
*/
private $adapter;
public function setUp(): void
{
$this->api = new JsonApi('http://example.com');
}
$this->adapter = new MockAdapter();
protected function deleteResource(array $data = [])
{
return $this->api->handle(
$this->buildRequest('DELETE', '/users/1')
);
}
public function test_resources_are_not_deletable_by_default()
{
$this->markTestIncomplete();
$this->api->resource('users', new MockAdapter());
$this->expectException(ForbiddenException::class);
$this->deleteResource();
}
public function test_resource_deletion_can_be_explicitly_enabled()
{
$this->markTestIncomplete();
$this->api->resource('users', new MockAdapter(), function (Type $type) {
$type->deletable();
});
$response = $this->deleteResource();
$this->assertEquals(204, $response->getStatusCode());
}
public function test_resource_deletion_can_be_conditionally_enabled()
{
$this->markTestIncomplete();
$this->api->resource('users', new MockAdapter(), function (Type $type) {
$type->deletable(function () {
return true;
});
});
$response = $this->deleteResource();
$this->assertEquals(204, $response->getStatusCode());
}
public function test_resource_deletion_can_be_explicitly_disabled()
{
$this->markTestIncomplete();
$this->api->resource('users', new MockAdapter(), function (Type $type) {
$type->notDeletable();
});
$this->expectException(ForbiddenException::class);
$this->deleteResource();
}
public function test_resource_deletion_can_be_conditionally_disabled()
{
$this->markTestIncomplete();
$this->api->resource('users', new MockAdapter(), function (Type $type) {
$type->deletable(function () {
return false;
});
});
$this->expectException(ForbiddenException::class);
$this->deleteResource();
}
public function test_resource_deletable_callback_receives_correct_parameters()
{
$called = false;
$adapter = $this->prophesize(AdapterInterface::class);
$adapter->query()->willReturn($query = (object) []);
$adapter->find($query, '1')->willReturn($deletingModel = (object) []);
$adapter->delete($deletingModel);
$this->api->resource('users', $adapter->reveal(), function (Type $type) use ($deletingModel, &$called) {
$type->deletable(function ($model, $request) use ($deletingModel, &$called) {
$this->assertSame($deletingModel, $model);
$this->assertInstanceOf(ServerRequestInterface::class, $request);
return $called = true;
});
});
$this->deleteResource();
$this->assertTrue($called);
}
public function test_deleting_a_resource_calls_the_delete_adapter_method()
{
$this->markTestIncomplete();
$adapter = $this->prophesize(AdapterInterface::class);
$adapter->query()->willReturn($query = (object) []);
$adapter->find($query, '1')->willReturn($model = (object) []);
$adapter->delete($model)->shouldBeCalled();
$this->api->resource('users', $adapter->reveal(), function (Type $type) {
$type->deletable();
});
$this->deleteResource();
}
// deleter...
// listeners...
public function test_resources_can_provide_custom_deleters()
{
$called = false;
$adapter = $this->prophesize(AdapterInterface::class);
$adapter->query()->willReturn($query = (object) []);
$adapter->find($query, '1')->willReturn($deletingModel = (object) []);
$adapter->delete($deletingModel)->shouldNotBeCalled();
$this->api->resource('users', $adapter->reveal(), function (Type $type) use ($deletingModel, &$called) {
$type->deletable();
$type->delete(function ($model, $request) use ($deletingModel, &$called) {
$this->assertSame($deletingModel, $model);
$this->assertInstanceOf(ServerRequestInterface::class, $request);
return $called = true;
});
});
$this->deleteResource();
$this->assertTrue($called);
}
public function test_resources_can_have_deletion_listeners()
{
$called = 0;
$adapter = $this->prophesize(AdapterInterface::class);
$adapter->query()->willReturn($query = (object) []);
$adapter->find($query, '1')->willReturn($deletingModel = (object) []);
$adapter->delete($deletingModel)->shouldBeCalled();
$this->api->resource('users', $adapter->reveal(), function (Type $type) use ($adapter, $deletingModel, &$called) {
$type->deletable();
$type->deleting(function ($model, $request) use ($adapter, $deletingModel, &$called) {
$this->assertSame($deletingModel, $model);
$this->assertInstanceOf(ServerRequestInterface::class, $request);
$adapter->delete($deletingModel)->shouldNotHaveBeenCalled();
$called++;
});
$type->deleted(function ($model, $request) use ($adapter, $deletingModel, &$called) {
$this->assertSame($deletingModel, $model);
$this->assertInstanceOf(ServerRequestInterface::class, $request);
$adapter->delete($deletingModel)->shouldHaveBeenCalled();
$called++;
});
});
$this->deleteResource();
$this->assertEquals(2, $called);
}
}

View File

@ -78,7 +78,7 @@ class FieldVisibilityTest extends AbstractTestCase
$this->assertArrayHasKey('visibleHasMany', $relationships);
}
public function test_attributes_can_be_conditionally_visible()
public function test_fields_can_be_conditionally_visible()
{
$this->markTestIncomplete();

View File

@ -11,7 +11,9 @@
namespace Tobyz\Tests\JsonApiServer\feature;
use Psr\Http\Message\ServerRequestInterface;
use Tobyz\JsonApiServer\JsonApi;
use Tobyz\JsonApiServer\Schema\Type;
use Tobyz\Tests\JsonApiServer\AbstractTestCase;
use Tobyz\Tests\JsonApiServer\MockAdapter;
@ -22,25 +24,44 @@ class MetaTest extends AbstractTestCase
*/
private $api;
/**
* @var MockAdapter
*/
private $adapter;
public function setUp(): void
{
$this->api = new JsonApi('http://example.com');
$this->adapter = new MockAdapter();
}
public function test_meta_fields_can_be_added_to_the_document_with_a_value()
public function test_meta_fields_can_be_added_to_resources_with_a_value()
{
$this->markTestIncomplete();
$this->api->resource('users', new MockAdapter(), function (Type $type) {
$type->meta('foo', 'bar');
});
$response = $this->api->handle(
$this->buildRequest('GET', '/users/1')
);
$document = json_decode($response->getBody(), true);
$this->assertEquals(['foo' => 'bar'], $document['data']['meta']);
}
public function test_meta_fields_can_be_added_to_the_document_with_a_closure()
public function test_meta_fields_can_be_added_to_resources_with_a_closure()
{
$this->markTestIncomplete();
$adapter = new MockAdapter(['1' => (object) ['id' => '1']]);
$this->api->resource('users', $adapter, function (Type $type) use ($adapter) {
$type->meta('foo', function ($model, $request) use ($adapter) {
$this->assertSame($adapter->models['1'], $model);
$this->assertInstanceOf(ServerRequestInterface::class, $request);
return 'bar';
});
});
$response = $this->api->handle(
$this->buildRequest('GET', '/users/1')
);
$document = json_decode($response->getBody(), true);
$this->assertEquals('bar', $document['data']['meta']['foo']);
}
}

View File

@ -12,7 +12,6 @@
namespace Tobyz\Tests\JsonApiServer\feature;
use Psr\Http\Message\ServerRequestInterface;
use Tobyz\JsonApiServer\Exception\BadRequestException;
use Tobyz\JsonApiServer\JsonApi;
use Tobyz\JsonApiServer\Schema\Type;
use Tobyz\Tests\JsonApiServer\AbstractTestCase;