From 269207eedb1d26b02ae76737f3d82e920a8fe624 Mon Sep 17 00:00:00 2001 From: Toby Zerner Date: Mon, 19 Aug 2019 12:02:30 +0200 Subject: [PATCH] wip --- README.md | 8 +- src/Adapter/EloquentAdapter.php | 3 +- src/Handler/Concerns/IncludesData.php | 1 - src/JsonApiResponse.php | 4 +- src/Schema/Field.php | 2 - src/Schema/Relationship.php | 12 +- src/Serializer.php | 2 +- tests/feature/AttributeFilterableTest.php | 107 ----- tests/feature/AttributeTest.php | 393 ------------------ tests/feature/BasicTest.php | 174 -------- tests/feature/CountabilityTest.php | 51 +++ tests/feature/CreateTest.php | 79 ++++ tests/feature/DeleteTest.php | 69 +++ tests/feature/FieldDefaultValuesTest.php | 49 +++ tests/feature/FieldFiltersTest.php | 59 +++ tests/feature/FieldGettersTest.php | 34 ++ tests/feature/FieldListenersTest.php | 29 ++ tests/feature/FieldSaversTest.php | 34 ++ tests/feature/FieldSettersTest.php | 39 ++ tests/feature/FieldValidationTest.php | 39 ++ tests/feature/FieldVisibilityTest.php | 38 +- ...tableTest.php => FieldWritabilityTest.php} | 51 +-- tests/feature/MetaTest.php | 46 ++ tests/feature/PaginationTest.php | 66 +++ tests/feature/RelationshipInclusionTest.php | 84 ++++ tests/feature/RelationshipLinkageTest.php | 39 ++ tests/feature/RelationshipLinksTest.php | 39 ++ tests/feature/RelationshipMetaTest.php | 46 ++ tests/feature/RelationshipTypesTest.php | 44 ++ tests/feature/ScopesTest.php | 59 +++ ...ributeSortableTest.php => SortingTest.php} | 51 ++- tests/feature/UpdateTest.php | 69 +++ .../specification/ContentNegotiationTest.php | 11 +- tests/specification/CreatingResourcesTest.php | 79 ++++ tests/specification/DeletingResourcesTest.php | 49 +++ tests/specification/FetchingResourcesTest.php | 74 ++++ tests/specification/JsonApiTest.php | 44 ++ tests/specification/OffsetPaginationTest.php | 85 ++++ tests/specification/QueryParametersTest.php | 44 ++ tests/specification/SparseFieldsetsTest.php | 64 +++ tests/specification/UpdatingResourcesTest.php | 84 ++++ tests/unit/{ => Http}/MediaTypesTest.php | 12 +- tests/unit/JsonApiTest.php | 27 ++ tests/unit/Schema/TypeTest.php | 43 ++ 44 files changed, 1659 insertions(+), 777 deletions(-) delete mode 100644 tests/feature/AttributeFilterableTest.php delete mode 100644 tests/feature/AttributeTest.php delete mode 100644 tests/feature/BasicTest.php create mode 100644 tests/feature/CountabilityTest.php create mode 100644 tests/feature/CreateTest.php create mode 100644 tests/feature/DeleteTest.php create mode 100644 tests/feature/FieldDefaultValuesTest.php create mode 100644 tests/feature/FieldFiltersTest.php create mode 100644 tests/feature/FieldGettersTest.php create mode 100644 tests/feature/FieldListenersTest.php create mode 100644 tests/feature/FieldSaversTest.php create mode 100644 tests/feature/FieldSettersTest.php create mode 100644 tests/feature/FieldValidationTest.php rename tests/feature/{AttributeWritableTest.php => FieldWritabilityTest.php} (80%) create mode 100644 tests/feature/MetaTest.php create mode 100644 tests/feature/PaginationTest.php create mode 100644 tests/feature/RelationshipInclusionTest.php create mode 100644 tests/feature/RelationshipLinkageTest.php create mode 100644 tests/feature/RelationshipLinksTest.php create mode 100644 tests/feature/RelationshipMetaTest.php create mode 100644 tests/feature/RelationshipTypesTest.php create mode 100644 tests/feature/ScopesTest.php rename tests/feature/{AttributeSortableTest.php => SortingTest.php} (80%) create mode 100644 tests/feature/UpdateTest.php create mode 100644 tests/specification/CreatingResourcesTest.php create mode 100644 tests/specification/DeletingResourcesTest.php create mode 100644 tests/specification/FetchingResourcesTest.php create mode 100644 tests/specification/JsonApiTest.php create mode 100644 tests/specification/OffsetPaginationTest.php create mode 100644 tests/specification/QueryParametersTest.php create mode 100644 tests/specification/SparseFieldsetsTest.php create mode 100644 tests/specification/UpdatingResourcesTest.php rename tests/unit/{ => Http}/MediaTypesTest.php (76%) create mode 100644 tests/unit/JsonApiTest.php create mode 100644 tests/unit/Schema/TypeTest.php diff --git a/README.md b/README.md index 7b5f388..3715697 100644 --- a/README.md +++ b/README.md @@ -101,10 +101,10 @@ Define an [attribute field](https://jsonapi.org/format/#document-resource-object $schema->attribute('firstName'); ``` -By default the attribute will correspond to the property on your model with the same name. (`EloquentAdapter` will `snake_case` it automatically for you.) If you'd like it to correspond to a different property, provide it as a second argument: +By default the attribute will correspond to the property on your model with the same name. (`EloquentAdapter` will `snake_case` it automatically for you.) If you'd like it to correspond to a different property, use the `property` method: ```php -$schema->attribute('firstName', 'fname'); +$schema->attribute('firstName')->property('fname'); ``` ### Relationships @@ -122,7 +122,7 @@ By default the [resource type](https://jsonapi.org/format/#document-resource-obj $schema->hasOne('author')->type('people'); ``` -Like attributes, the relationship will automatically read and write to the relation on your model with the same name. If you'd like it to correspond to a different relation, provide it as a third argument. +Like attributes, the relationship will automatically read and write to the relation on your model with the same name. If you'd like it to correspond to a different relation, use the `property` method. #### Relationship Links @@ -315,7 +315,7 @@ $schema->attribute('firstName') }); ``` -If your attribute corresponds to some other form of data storage rather than a simple property on your model, you can use the `save` method to provide a closure to be run _after_ your model is saved: +If your field corresponds to some other form of data storage rather than a simple property on your model, you can use the `save` method to provide a closure to be run _after_ your model is saved: ```php $schema->attribute('locale') diff --git a/src/Adapter/EloquentAdapter.php b/src/Adapter/EloquentAdapter.php index 4abe0b4..9d4cb33 100644 --- a/src/Adapter/EloquentAdapter.php +++ b/src/Adapter/EloquentAdapter.php @@ -74,7 +74,8 @@ class EloquentAdapter implements AdapterInterface $relation = $this->getRelation($model, $relationship); // If this is a belongs-to relation, we can simply return the value of - // the foreign key on the model. + // the foreign key on the model. Otherwise we will have to fetch the + // full related model and return its key. if ($relation instanceof BelongsTo) { return $model->{$relation->getForeignKeyName()}; } diff --git a/src/Handler/Concerns/IncludesData.php b/src/Handler/Concerns/IncludesData.php index 13b2bb3..a34a734 100644 --- a/src/Handler/Concerns/IncludesData.php +++ b/src/Handler/Concerns/IncludesData.php @@ -7,7 +7,6 @@ use Psr\Http\Message\ServerRequestInterface as Request; use function Tobyz\JsonApiServer\evaluate; use Tobyz\JsonApiServer\Exception\BadRequestException; use Tobyz\JsonApiServer\ResourceType; -use Tobyz\JsonApiServer\Schema\HasMany; use Tobyz\JsonApiServer\Schema\Relationship; trait IncludesData diff --git a/src/JsonApiResponse.php b/src/JsonApiResponse.php index 62e1814..85a1a01 100644 --- a/src/JsonApiResponse.php +++ b/src/JsonApiResponse.php @@ -8,9 +8,9 @@ class JsonApiResponse extends JsonResponse { public function __construct( $data, - $status = 200, + int $status = 200, array $headers = [], - $encodingOptions = self::DEFAULT_JSON_FLAGS + int $encodingOptions = self::DEFAULT_JSON_FLAGS ) { $headers['content-type'] = JsonApi::CONTENT_TYPE; diff --git a/src/Schema/Field.php b/src/Schema/Field.php index aacb63c..8dc2dda 100644 --- a/src/Schema/Field.php +++ b/src/Schema/Field.php @@ -166,6 +166,4 @@ abstract class Field { return $this->filterable; } - - } diff --git a/src/Schema/Relationship.php b/src/Schema/Relationship.php index 0fc9625..5bf8d01 100644 --- a/src/Schema/Relationship.php +++ b/src/Schema/Relationship.php @@ -48,12 +48,12 @@ abstract class Relationship extends Field return $this; } - public function notLoadable() - { - $this->loadable = false; - - return $this; - } + // public function notLoadable() + // { + // $this->loadable = false; + // + // return $this; + // } public function includable() { diff --git a/src/Serializer.php b/src/Serializer.php index dd2512d..5d8325f 100644 --- a/src/Serializer.php +++ b/src/Serializer.php @@ -17,7 +17,7 @@ use Tobyz\JsonApiServer\Adapter\AdapterInterface; use Tobyz\JsonApiServer\Schema\Attribute; use Tobyz\JsonApiServer\Schema\Relationship; -class Serializer +final class Serializer { protected $api; protected $request; diff --git a/tests/feature/AttributeFilterableTest.php b/tests/feature/AttributeFilterableTest.php deleted file mode 100644 index 0daa2b7..0000000 --- a/tests/feature/AttributeFilterableTest.php +++ /dev/null @@ -1,107 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -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; -use Tobyz\Tests\JsonApiServer\MockAdapter; - -class AttributeFilterableTest extends AbstractTestCase -{ - /** - * @var JsonApi - */ - private $api; - - /** - * @var MockAdapter - */ - private $adapter; - - public function setUp(): void - { - $this->api = new JsonApi('http://example.com'); - - $this->adapter = new MockAdapter(); - } - - public function test_attributes_are_not_filterable_by_default() - { - $this->api->resource('users', $this->adapter, function (Type $type) { - $type->attribute('field'); - }); - - $this->expectException(BadRequestException::class); - - $this->api->handle( - $this->buildRequest('GET', '/users') - ->withQueryParams(['filter' => ['field' => 'Toby']]) - ); - } - - public function test_attributes_can_be_filterable() - { - $attribute = null; - - $this->api->resource('users', $this->adapter, function (Type $type) use (&$attribute) { - $attribute = $type->attribute('name')->filterable(); - }); - - $this->api->handle( - $this->buildRequest('GET', '/users') - ->withQueryParams(['filter' => ['name' => 'Toby']]) - ); - - $this->assertContains([$attribute, 'Toby'], $this->adapter->query->filter); - } - - public function test_attributes_can_be_filterable_with_custom_logic() - { - $called = false; - - $this->api->resource('users', $this->adapter, function (Type $type) use (&$called) { - $type->attribute('name') - ->filterable(function ($query, $value, $request) use (&$called) { - $this->assertSame($this->adapter->query, $query); - $this->assertEquals('Toby', $value); - $this->assertInstanceOf(ServerRequestInterface::class, $request); - - $called = true; - }); - }); - - $this->api->handle( - $this->buildRequest('GET', '/users') - ->withQueryParams(['filter' => ['name' => 'Toby']]) - ); - - $this->assertTrue($called); - $this->assertTrue(empty($this->adapter->query->filter)); - } - - public function test_attributes_can_be_explicitly_not_filterable() - { - $this->api->resource('users', $this->adapter, function (Type $type) { - $type->attribute('name')->notFilterable(); - }); - - $this->expectException(BadRequestException::class); - - $this->api->handle( - $this->buildRequest('GET', '/users') - ->withQueryParams(['filter' => ['name' => 'Toby']]) - ); - } -} diff --git a/tests/feature/AttributeTest.php b/tests/feature/AttributeTest.php deleted file mode 100644 index a3b21bc..0000000 --- a/tests/feature/AttributeTest.php +++ /dev/null @@ -1,393 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Tobyz\Tests\JsonApiServer\feature; - -use JsonApiPhp\JsonApi\ErrorDocument; -use Psr\Http\Message\RequestInterface; -use Psr\Http\Message\ServerRequestInterface; -use Tobyz\JsonApiServer\ErrorProviderInterface; -use Tobyz\JsonApiServer\Exception\UnprocessableEntityException; -use Tobyz\JsonApiServer\JsonApi; -use Tobyz\JsonApiServer\Schema\Attribute; -use Tobyz\JsonApiServer\Schema\Type; -use Tobyz\Tests\JsonApiServer\AbstractTestCase; -use Tobyz\Tests\JsonApiServer\MockAdapter; - -class AttributeTest extends AbstractTestCase -{ - /** - * @var JsonApi - */ - private $api; - - /** - * @var MockAdapter - */ - private $adapter; - - public function setUp(): void - { - $this->api = new JsonApi('http://example.com'); - - $this->adapter = new MockAdapter([ - '1' => (object) ['id' => '1', 'name' => 'Toby', 'color' => 'yellow'], - '2' => (object) ['id' => '2', 'name' => 'Franz', 'color' => 'blue'], - ]); - } - - public function test_multiple_attributes() - { - $this->api->resource('users', $this->adapter, function (Type $type) { - $type->attribute('name'); - $type->attribute('color'); - }); - - $response = $this->api->handle( - $this->buildRequest('GET', '/users/1') - ); - - $this->assertJsonApiDocumentSubset([ - 'data' => [ - 'attributes' => [ - 'name' => 'Toby', - 'color' => 'yellow', - ], - ] - ], $response->getBody()); - } - - public function test_attributes_can_specify_a_property() - { - $this->api->resource('users', $this->adapter, function (Type $type) { - $type->attribute('name') - ->property('color'); - }); - - $response = $this->api->handle( - $this->buildRequest('GET', '/users/1') - ); - - $this->assertJsonApiDocumentSubset([ - 'data' => [ - 'attributes' => [ - 'name' => 'yellow', - ], - ] - ], $response->getBody()); - } - - public function test_attributes_can_have_getters() - { - $called = false; - - $this->api->resource('users', $this->adapter, function (Type $type) use (&$called) { - $type->attribute('name') - ->get('Toby'); - - $type->attribute('color') - ->get(function ($model, $request) use (&$called) { - $called = true; - - $this->assertSame($this->adapter->models['1'], $model); - $this->assertInstanceOf(RequestInterface::class, $request); - - return 'yellow'; - }); - }); - - $response = $this->api->handle( - $this->buildRequest('GET', '/users/1') - ); - - $this->assertTrue($called); - - $this->assertJsonApiDocumentSubset([ - 'data' => [ - 'attributes' => [ - 'name' => 'Toby', - 'color' => 'yellow', - ], - ] - ], $response->getBody()); - } - - public function test_attribute_setter_receives_correct_parameters() - { - $called = false; - - $this->api->resource('users', $this->adapter, function (Type $type) use (&$called) { - $type->updatable(); - $type->attribute('writable') - ->writable() - ->set(function ($model, $value, $request) use (&$called) { - $this->assertSame($this->adapter->models['1'], $model); - $this->assertEquals('value', $value); - $this->assertInstanceOf(RequestInterface::class, $request); - - $called = true; - }); - }); - - $this->api->handle( - $this->buildRequest('PATCH', '/users/1') - ->withParsedBody([ - 'data' => [ - 'type' => 'users', - 'id' => '1', - 'attributes' => [ - 'writable' => 'value', - ] - ] - ]) - ); - - $this->assertTrue($called); - } - - public function test_attribute_setter_precludes_adapter_action() - { - $this->api->resource('users', $this->adapter, function (Type $type) { - $type->updatable(); - $type->attribute('writable') - ->writable() - ->set(function () {}); - }); - - $this->api->handle( - $this->buildRequest('PATCH', '/users/1') - ->withParsedBody([ - 'data' => [ - 'type' => 'users', - 'id' => '1', - 'attributes' => [ - 'writable' => 'value', - ] - ] - ]) - ); - - $this->assertTrue(empty($this->adapter->models['1']->writable)); - } - - public function test_attribute_saver_receives_correct_parameters() - { - $called = false; - - $this->api->resource('users', $this->adapter, function (Type $type) use (&$called) { - $type->updatable(); - $type->attribute('writable') - ->writable() - ->save(function ($model, $value, $request) use (&$called) { - $this->assertSame($this->adapter->models['1'], $model); - $this->assertEquals('value', $value); - $this->assertInstanceOf(RequestInterface::class, $request); - - $called = true; - }); - }); - - $this->api->handle( - $this->buildRequest('PATCH', '/users/1') - ->withParsedBody([ - 'data' => [ - 'type' => 'users', - 'id' => '1', - 'attributes' => [ - 'writable' => 'value', - ] - ] - ]) - ); - - $this->assertTrue($called); - } - - public function test_attribute_saver_precludes_adapter_action() - { - $this->api->resource('users', $this->adapter, function (Type $type) { - $type->updatable(); - $type->attribute('writable') - ->writable() - ->save(function () {}); - }); - - $this->api->handle( - $this->buildRequest('PATCH', '/users/1') - ->withParsedBody([ - 'data' => [ - 'type' => 'users', - 'id' => '1', - 'attributes' => [ - 'writable' => 'value', - ] - ] - ]) - ); - - $this->assertTrue(empty($this->adapter->models['1']->writable)); - } - - public function test_attributes_can_run_callback_after_being_saved() - { - $called = false; - - $this->api->resource('users', $this->adapter, function (Type $type) use (&$called) { - $type->updatable(); - $type->attribute('writable') - ->writable() - ->saved(function ($model, $value, $request) use (&$called) { - $this->assertTrue($this->adapter->models['1']->saveWasCalled); - $this->assertSame($this->adapter->models['1'], $model); - $this->assertEquals('value', $value); - $this->assertInstanceOf(RequestInterface::class, $request); - - $called = true; - }); - }); - - $this->api->handle( - $this->buildRequest('PATCH', '/users/1') - ->withParsedBody([ - 'data' => [ - 'type' => 'users', - 'id' => '1', - 'attributes' => [ - 'writable' => 'value', - ] - ] - ]) - ); - - $this->assertTrue($called); - } - - public function test_attributes_can_have_default_values() - { - $this->api->resource('users', $this->adapter, function (Type $type) { - $type->creatable(); - - $type->attribute('name') - ->default('Toby'); - - $type->attribute('color') - ->default(function () { - return 'yellow'; - }); - }); - - $this->api->handle( - $this->buildRequest('POST', '/users') - ->withParsedBody([ - 'data' => [ - 'type' => 'users', - ] - ]) - ); - - $this->assertEquals('Toby', $this->adapter->createdModel->name); - $this->assertEquals('yellow', $this->adapter->createdModel->color); - } - - public function test_attribute_default_callback_receives_correct_parameters() - { - $this->api->resource('users', $this->adapter, function (Type $type) { - $type->creatable(); - $type->attribute('attribute') - ->default(function ($request) { - $this->assertInstanceOf(RequestInterface::class, $request); - }); - }); - - $this->api->handle( - $this->buildRequest('POST', '/users') - ->withParsedBody([ - 'data' => [ - 'type' => 'users', - ] - ]) - ); - } - - public function test_attribute_values_from_request_override_default_values() - { - $this->api->resource('users', $this->adapter, function (Type $type) { - $type->creatable(); - $type->attribute('name') - ->writable() - ->default('Toby'); - }); - - $this->api->handle( - $this->buildRequest('POST', '/users') - ->withParsedBody([ - 'data' => [ - 'type' => 'users', - 'attributes' => [ - 'name' => 'Franz', - ] - ] - ]) - ); - - $this->assertEquals('Franz', $this->adapter->createdModel->name); - } - - public function test_attributes_can_be_validated() - { - $this->api->resource('users', $this->adapter, function (Type $type) { - $type->creatable(); - - $type->attribute('name') - ->writable() - ->validate(function ($fail, $value, $model, $request, $field) { - $this->assertEquals('Toby', $value); - $this->assertSame($this->adapter->createdModel, $model); - $this->assertInstanceOf(ServerRequestInterface::class, $request); - $this->assertInstanceOf(Attribute::class, $field); - - $fail('detail'); - }); - }); - - $this->expectException(UnprocessableEntityException::class); - - try { - $this->api->handle( - $this->buildRequest('POST', '/users') - ->withParsedBody([ - 'data' => [ - 'type' => 'users', - 'attributes' => [ - 'name' => 'Toby', - ] - ] - ]) - ); - } catch (ErrorProviderInterface $e) { - $document = new ErrorDocument(...$e->getJsonApiErrors()); - - $this->assertArraySubset([ - 'errors' => [ - [ - 'status' => '422', - 'source' => [ - 'pointer' => '/data/attributes/name' - ], - 'detail' => 'detail' - ] - ] - ], json_decode(json_encode($document), true)); - - throw $e; - } - } -} diff --git a/tests/feature/BasicTest.php b/tests/feature/BasicTest.php deleted file mode 100644 index c0bebeb..0000000 --- a/tests/feature/BasicTest.php +++ /dev/null @@ -1,174 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Tobyz\Tests\JsonApiServer\feature; - -use Tobyz\JsonApiServer\JsonApi; -use Tobyz\JsonApiServer\Schema\Type; -use Tobyz\Tests\JsonApiServer\AbstractTestCase; -use Tobyz\Tests\JsonApiServer\MockAdapter; - -class BasicTest extends AbstractTestCase -{ - /** - * @var JsonApi - */ - private $api; - - public function setUp(): void - { - $this->api = new JsonApi('http://example.com'); - - $adapter = new MockAdapter([ - '1' => (object) [ - 'id' => '1', - 'name' => 'Toby', - ], - '2' => (object) [ - 'id' => '2', - 'name' => 'Franz', - ], - ]); - - $this->api->resource('users', $adapter, function (Type $type) { - $type->attribute('name')->writable(); - $type->creatable(); - $type->updatable(); - $type->deletable(); - }); - } - - public function test_show_resource() - { - $response = $this->api->handle( - $this->buildRequest('GET', '/users/1') - ); - - $this->assertEquals(200, $response->getStatusCode()); - - $this->assertJsonApiDocumentSubset([ - 'data' => [ - 'type' => 'users', - 'id' => '1', - 'attributes' => [ - 'name' => 'Toby' - ], - 'links' => [ - 'self' => 'http://example.com/users/1' - ] - ] - ], $response->getBody()); - } - - public function test_list_resources() - { - $response = $this->api->handle( - $this->buildRequest('GET', '/users') - ); - - $this->assertEquals(200, $response->getStatusCode()); - - $this->assertJsonApiDocumentSubset([ - 'data' => [ - [ - 'type' => 'users', - 'id' => '1', - 'attributes' => [ - 'name' => 'Toby' - ], - 'links' => [ - 'self' => 'http://example.com/users/1' - ] - ], - [ - 'type' => 'users', - 'id' => '2', - 'attributes' => [ - 'name' => 'Franz' - ], - 'links' => [ - 'self' => 'http://example.com/users/2' - ] - ] - ] - ], $response->getBody()); - } - - public function test_create_resource() - { - $response = $this->api->handle( - $this->buildRequest('POST', '/users') - ->withParsedBody([ - 'data' => [ - 'type' => 'users', - 'attributes' => [ - 'name' => 'Bob', - ], - ], - ]) - ); - - $this->assertEquals(201, $response->getStatusCode()); - - $this->assertJsonApiDocumentSubset([ - 'data' => [ - 'type' => 'users', - 'id' => '1', - 'attributes' => [ - 'name' => 'Bob', - ], - 'links' => [ - 'self' => 'http://example.com/users/1', - ], - ], - ], $response->getBody()); - } - - public function test_update_resource() - { - $response = $this->api->handle( - $this->buildRequest('PATCH', '/users/1') - ->withParsedBody([ - 'data' => [ - 'type' => 'users', - 'id' => '1', - 'attributes' => [ - 'name' => 'Bob', - ], - ], - ]) - ); - - $this->assertEquals(200, $response->getStatusCode()); - - $this->assertJsonApiDocumentSubset([ - 'data' => [ - 'type' => 'users', - 'id' => '1', - 'attributes' => [ - 'name' => 'Bob', - ], - 'links' => [ - 'self' => 'http://example.com/users/1', - ], - ], - ], $response->getBody()); - } - - public function test_delete_resource() - { - $response = $this->api->handle( - $this->buildRequest('DELETE', '/users/1') - ); - - $this->assertEquals(204, $response->getStatusCode()); - } -} diff --git a/tests/feature/CountabilityTest.php b/tests/feature/CountabilityTest.php new file mode 100644 index 0000000..4969d39 --- /dev/null +++ b/tests/feature/CountabilityTest.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\feature; + +use Tobyz\JsonApiServer\JsonApi; +use Tobyz\Tests\JsonApiServer\AbstractTestCase; +use Tobyz\Tests\JsonApiServer\MockAdapter; + +class CountabilityTest extends AbstractTestCase +{ + /** + * @var JsonApi + */ + private $api; + + /** + * @var MockAdapter + */ + private $adapter; + + public function setUp(): void + { + $this->api = new JsonApi('http://example.com'); + + $this->adapter = new MockAdapter(); + } + + public function test_total_number_of_resources_and_last_pagination_link_is_included_by_default() + { + $this->markTestIncomplete(); + } + + public function test_types_can_be_made_uncountable() + { + $this->markTestIncomplete(); + } + + public function test_types_can_be_made_countable() + { + $this->markTestIncomplete(); + } +} diff --git a/tests/feature/CreateTest.php b/tests/feature/CreateTest.php new file mode 100644 index 0000000..db90683 --- /dev/null +++ b/tests/feature/CreateTest.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\feature; + +use Tobyz\JsonApiServer\JsonApi; +use Tobyz\Tests\JsonApiServer\AbstractTestCase; +use Tobyz\Tests\JsonApiServer\MockAdapter; + +class CreateTest extends AbstractTestCase +{ + /** + * @var JsonApi + */ + private $api; + + /** + * @var MockAdapter + */ + private $adapter; + + public function setUp(): void + { + $this->api = new JsonApi('http://example.com'); + + $this->adapter = new MockAdapter(); + } + + public function test_resources_are_not_creatable_by_default() + { + $this->markTestIncomplete(); + } + + public function test_resource_creation_can_be_explicitly_enabled() + { + $this->markTestIncomplete(); + } + + public function test_resource_creation_can_be_conditionally_enabled() + { + $this->markTestIncomplete(); + } + + public function test_resource_creation_can_be_explicitly_disabled() + { + $this->markTestIncomplete(); + } + + public function test_resource_creation_can_be_conditionally_disabled() + { + $this->markTestIncomplete(); + } + + public function test_new_models_are_supplied_by_the_adapter() + { + $this->markTestIncomplete(); + } + + public function test_resources_can_provide_custom_models() + { + $this->markTestIncomplete(); + } + + public function test_creating_a_resource_calls_the_save_adapter_method() + { + $this->markTestIncomplete(); + } + + // saver... + // listeners... +} diff --git a/tests/feature/DeleteTest.php b/tests/feature/DeleteTest.php new file mode 100644 index 0000000..9d77b9f --- /dev/null +++ b/tests/feature/DeleteTest.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\feature; + +use Tobyz\JsonApiServer\JsonApi; +use Tobyz\Tests\JsonApiServer\AbstractTestCase; +use Tobyz\Tests\JsonApiServer\MockAdapter; + +class DeleteTest extends AbstractTestCase +{ + /** + * @var JsonApi + */ + private $api; + + /** + * @var MockAdapter + */ + private $adapter; + + public function setUp(): void + { + $this->api = new JsonApi('http://example.com'); + + $this->adapter = new MockAdapter(); + } + + public function test_resources_are_not_deletable_by_default() + { + $this->markTestIncomplete(); + } + + public function test_resource_deletion_can_be_explicitly_enabled() + { + $this->markTestIncomplete(); + } + + public function test_resource_deletion_can_be_conditionally_enabled() + { + $this->markTestIncomplete(); + } + + public function test_resource_deletion_can_be_explicitly_disabled() + { + $this->markTestIncomplete(); + } + + public function test_resource_deletion_can_be_conditionally_disabled() + { + $this->markTestIncomplete(); + } + + public function test_deleting_a_resource_calls_the_delete_adapter_method() + { + $this->markTestIncomplete(); + } + + // deleter... + // listeners... +} diff --git a/tests/feature/FieldDefaultValuesTest.php b/tests/feature/FieldDefaultValuesTest.php new file mode 100644 index 0000000..6c426b7 --- /dev/null +++ b/tests/feature/FieldDefaultValuesTest.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\feature; + +use Tobyz\Tests\JsonApiServer\AbstractTestCase; + +class FieldDefaultValuesTest extends AbstractTestCase +{ + public function setUp(): void + { + + } + + public function test_attributes_have_no_default_value_by_default() + { + $this->markTestIncomplete(); + } + + public function test_attributes_can_have_default_values() + { + $this->markTestIncomplete(); + } + + public function test_attributes_can_have_default_value_closures() + { + $this->markTestIncomplete(); + } + + public function test_attribute_default_value_callback_receives_correct_parameters() + { + $this->markTestIncomplete(); + } + + public function test_attribute_values_from_request_override_default_values() + { + $this->markTestIncomplete(); + } + + // to_one, to_many... +} diff --git a/tests/feature/FieldFiltersTest.php b/tests/feature/FieldFiltersTest.php new file mode 100644 index 0000000..059036c --- /dev/null +++ b/tests/feature/FieldFiltersTest.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\feature; + +use Tobyz\Tests\JsonApiServer\AbstractTestCase; + +class FieldFiltersTest extends AbstractTestCase +{ + public function setUp(): void + { + + } + + public function test_resources_can_be_filtered_by_id() + { + $this->markTestIncomplete(); + } + + public function test_attributes_are_not_filterable_by_default() + { + $this->markTestIncomplete(); + } + + public function test_attributes_can_be_explicitly_not_filterable() + { + $this->markTestIncomplete(); + } + + public function test_attributes_can_be_filterable_by_their_value() + { + $this->markTestIncomplete(); + } + + public function test_attributes_can_be_filterable_with_custom_logic() + { + $this->markTestIncomplete(); + } + + public function test_attributes_filterable_callback_receives_correct_parameters() + { + $this->markTestIncomplete(); + } + + // to_one, to_many... + + public function test_types_can_have_custom_filters() + { + $this->markTestIncomplete(); + } +} diff --git a/tests/feature/FieldGettersTest.php b/tests/feature/FieldGettersTest.php new file mode 100644 index 0000000..bd1b550 --- /dev/null +++ b/tests/feature/FieldGettersTest.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\feature; + +use Tobyz\Tests\JsonApiServer\AbstractTestCase; + +class FieldGettersTest extends AbstractTestCase +{ + public function setUp(): void + { + + } + + public function test_attribute_values_are_retrieved_via_the_adapter_by_default() + { + $this->markTestIncomplete(); + } + + public function test_attribute_getters_allow_a_custom_value_to_be_used() + { + $this->markTestIncomplete(); + } + + // to_one, to_many... +} diff --git a/tests/feature/FieldListenersTest.php b/tests/feature/FieldListenersTest.php new file mode 100644 index 0000000..2d027ad --- /dev/null +++ b/tests/feature/FieldListenersTest.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\feature; + +use Tobyz\Tests\JsonApiServer\AbstractTestCase; + +class FieldListenersTest extends AbstractTestCase +{ + public function setUp(): void + { + + } + + public function test_attributes_can_run_callback_after_being_saved() + { + $this->markTestIncomplete(); + } + + // to_one, to_many... +} diff --git a/tests/feature/FieldSaversTest.php b/tests/feature/FieldSaversTest.php new file mode 100644 index 0000000..9d44455 --- /dev/null +++ b/tests/feature/FieldSaversTest.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\feature; + +use Tobyz\Tests\JsonApiServer\AbstractTestCase; + +class FieldSaversTest extends AbstractTestCase +{ + public function setUp(): void + { + + } + + public function test_attribute_savers_allow_custom_save_logic_to_be_performed_after_the_model_is_saved() + { + $this->markTestIncomplete(); + } + + public function test_attribute_savers_prevent_the_default_adapter_setter() + { + $this->markTestIncomplete(); + } + + // to_one, to_many... +} diff --git a/tests/feature/FieldSettersTest.php b/tests/feature/FieldSettersTest.php new file mode 100644 index 0000000..a780c32 --- /dev/null +++ b/tests/feature/FieldSettersTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\feature; + +use Tobyz\Tests\JsonApiServer\AbstractTestCase; + +class FieldSettersTest extends AbstractTestCase +{ + public function setUp(): void + { + + } + + public function test_attributes_are_set_via_the_adapter_by_default() + { + $this->markTestIncomplete(); + } + + public function test_attribute_setters_allow_the_model_to_be_modified_before_it_is_saved() + { + $this->markTestIncomplete(); + } + + public function test_attribute_setters_prevent_the_default_adapter_setter() + { + $this->markTestIncomplete(); + } + + // to_one, to_many... +} diff --git a/tests/feature/FieldValidationTest.php b/tests/feature/FieldValidationTest.php new file mode 100644 index 0000000..0876d64 --- /dev/null +++ b/tests/feature/FieldValidationTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\feature; + +use Tobyz\Tests\JsonApiServer\AbstractTestCase; + +class FieldValidationTest extends AbstractTestCase +{ + public function setUp(): void + { + + } + + public function test_attributes_can_define_multiple_validators() + { + $this->markTestIncomplete(); + } + + public function test_attribute_validators_receive_correct_parameters() + { + $this->markTestIncomplete(); + } + + public function test_attribute_validation_errors_contain_correct_information() + { + $this->markTestIncomplete(); + } + + // to_one, to_many... +} diff --git a/tests/feature/FieldVisibilityTest.php b/tests/feature/FieldVisibilityTest.php index 2247b97..0ede2c4 100644 --- a/tests/feature/FieldVisibilityTest.php +++ b/tests/feature/FieldVisibilityTest.php @@ -12,6 +12,7 @@ namespace Tobyz\Tests\JsonApiServer\feature; use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseInterface; use Tobyz\JsonApiServer\JsonApi; use Tobyz\JsonApiServer\Schema\Type; use Tobyz\Tests\JsonApiServer\AbstractTestCase; @@ -38,12 +39,10 @@ class FieldVisibilityTest extends AbstractTestCase ]); } - public function test_fields_are_visible_by_default() + public function test_attributes_are_visible_by_default() { $this->api->resource('users', new MockAdapter, function (Type $type) { - $type->attribute('visibleAttribute'); - $type->hasOne('visibleHasOne'); - $type->hasMany('visibleHasMany'); + $type->attribute('visible'); }); $response = $this->api->handle( @@ -52,15 +51,14 @@ class FieldVisibilityTest extends AbstractTestCase $document = json_decode($response->getBody(), true); $attributes = $document['data']['attributes'] ?? []; - $relationships = $document['data']['relationships'] ?? []; - $this->assertArrayHasKey('visibleAttribute', $attributes); - $this->assertArrayHasKey('visibleHasOne', $relationships); - $this->assertArrayHasKey('visibleHasMany', $relationships); + $this->assertArrayHasKey('visible', $attributes); } - public function test_fields_can_be_explicitly_visible() + public function test_attributes_can_be_explicitly_visible() { + $this->markTestIncomplete(); + $this->api->resource('users', new MockAdapter, function (Type $type) { $type->attribute('visibleAttribute')->visible(); $type->hasOne('visibleHasOne')->visible(); @@ -80,8 +78,10 @@ class FieldVisibilityTest extends AbstractTestCase $this->assertArrayHasKey('visibleHasMany', $relationships); } - public function test_fields_can_be_conditionally_visible() + public function test_attributes_can_be_conditionally_visible() { + $this->markTestIncomplete(); + $this->api->resource('users', new MockAdapter, function (Type $type) { $type->attribute('visibleAttribute') ->visible(function () { return true; }); @@ -119,8 +119,10 @@ class FieldVisibilityTest extends AbstractTestCase $this->assertArrayNotHasKey('hiddenHasMany', $relationships); } - public function test_visible_callback_receives_correct_parameters() + public function test_attribute_visible_callback_receives_correct_parameters() { + $this->markTestIncomplete(); + $called = 0; $this->api->resource('users', $this->adapter, function (Type $type) use (&$called) { @@ -147,8 +149,10 @@ class FieldVisibilityTest extends AbstractTestCase $this->assertEquals(3, $called); } - public function test_fields_can_be_explicitly_hidden() + public function test_attributes_can_be_explicitly_hidden() { + $this->markTestIncomplete(); + $this->api->resource('users', new MockAdapter, function (Type $type) { $type->attribute('hiddenAttribute')->hidden(); $type->hasOne('hiddenHasOne')->hidden(); @@ -168,8 +172,10 @@ class FieldVisibilityTest extends AbstractTestCase $this->assertArrayNotHasKey('hiddenHasMany', $relationships); } - public function test_fields_can_be_conditionally_hidden() + public function test_attributes_can_be_conditionally_hidden() { + $this->markTestIncomplete(); + $this->api->resource('users', new MockAdapter, function (Type $type) { $type->attribute('visibleAttribute') ->hidden(function () { return false; }); @@ -207,8 +213,10 @@ class FieldVisibilityTest extends AbstractTestCase $this->assertArrayNotHasKey('hiddenHasMany', $relationships); } - public function test_hidden_callback_receives_correct_parameters() + public function test_attribute_hidden_callback_receives_correct_parameters() { + $this->markTestIncomplete(); + $called = 0; $this->api->resource('users', $this->adapter, function (Type $type) use (&$called) { @@ -234,4 +242,6 @@ class FieldVisibilityTest extends AbstractTestCase $this->assertEquals(3, $called); } + + // to_one, to_many... } diff --git a/tests/feature/AttributeWritableTest.php b/tests/feature/FieldWritabilityTest.php similarity index 80% rename from tests/feature/AttributeWritableTest.php rename to tests/feature/FieldWritabilityTest.php index 371ebf7..a79711b 100644 --- a/tests/feature/AttributeWritableTest.php +++ b/tests/feature/FieldWritabilityTest.php @@ -19,7 +19,7 @@ use Tobyz\JsonApiServer\Schema\Type; use Tobyz\Tests\JsonApiServer\AbstractTestCase; use Tobyz\Tests\JsonApiServer\MockAdapter; -class AttributeWritableTest extends AbstractTestCase +class FieldWritabilityTest extends AbstractTestCase { /** * @var JsonApi @@ -112,30 +112,6 @@ class AttributeWritableTest extends AbstractTestCase $this->assertEquals('value', $this->adapter->models['1']->writable); } - public function test_attributes_can_be_conditionally_not_writable() - { - $this->api->resource('users', $this->adapter, function (Type $type) { - $type->updatable(); - $type->attribute('writable') - ->writable(function () { return false; }); - }); - - $this->expectException(BadRequestException::class); - - $this->api->handle( - $this->buildRequest('PATCH', '/users/1') - ->withParsedBody([ - 'data' => [ - 'type' => 'users', - 'id' => '1', - 'attributes' => [ - 'writable' => 'value', - ] - ] - ]) - ); - } - public function test_attribute_writable_callback_receives_correct_parameters() { $called = false; @@ -247,28 +223,5 @@ class AttributeWritableTest extends AbstractTestCase $this->assertTrue($called); } - public function test_attributes_can_be_conditionally_not_readonly() - { - $this->api->resource('users', $this->adapter, function (Type $type) { - $type->updatable(); - $type->attribute('writable') - ->readonly(function () { return false; }); - }); - - $response = $this->api->handle( - $this->buildRequest('PATCH', '/users/1') - ->withParsedBody([ - 'data' => [ - 'type' => 'users', - 'id' => '1', - 'attributes' => [ - 'writable' => 'value', - ] - ] - ]) - ); - - $this->assertEquals(200, $response->getStatusCode()); - $this->assertEquals('value', $this->adapter->models['1']->writable); - } + // to_one, to_many... } diff --git a/tests/feature/MetaTest.php b/tests/feature/MetaTest.php new file mode 100644 index 0000000..d25474a --- /dev/null +++ b/tests/feature/MetaTest.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\feature; + +use Tobyz\JsonApiServer\JsonApi; +use Tobyz\Tests\JsonApiServer\AbstractTestCase; +use Tobyz\Tests\JsonApiServer\MockAdapter; + +class MetaTest extends AbstractTestCase +{ + /** + * @var JsonApi + */ + 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() + { + $this->markTestIncomplete(); + } + + public function test_meta_fields_can_be_added_to_the_document_with_a_closure() + { + $this->markTestIncomplete(); + } +} diff --git a/tests/feature/PaginationTest.php b/tests/feature/PaginationTest.php new file mode 100644 index 0000000..5f18ba2 --- /dev/null +++ b/tests/feature/PaginationTest.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\feature; + +use Tobyz\JsonApiServer\JsonApi; +use Tobyz\Tests\JsonApiServer\AbstractTestCase; +use Tobyz\Tests\JsonApiServer\MockAdapter; + +class PaginationTest extends AbstractTestCase +{ + /** + * @var JsonApi + */ + private $api; + + /** + * @var MockAdapter + */ + private $adapter; + + public function setUp(): void + { + $this->api = new JsonApi('http://example.com'); + + $this->adapter = new MockAdapter(); + } + + public function test_resource_collections_are_paginated_to_20_records_by_default() + { + $this->markTestIncomplete(); + } + + public function test_types_can_specify_the_default_number_of_resources_per_page() + { + $this->markTestIncomplete(); + } + + public function test_types_can_disable_pagination_by_default() + { + $this->markTestIncomplete(); + } + + public function test_the_maximum_limit_is_50_by_default() + { + $this->markTestIncomplete(); + } + + public function test_types_can_specify_the_maximum_limit() + { + $this->markTestIncomplete(); + } + + public function test_types_can_remove_the_maximum_limit() + { + $this->markTestIncomplete(); + } +} diff --git a/tests/feature/RelationshipInclusionTest.php b/tests/feature/RelationshipInclusionTest.php new file mode 100644 index 0000000..1cf24d3 --- /dev/null +++ b/tests/feature/RelationshipInclusionTest.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\feature; + +use Tobyz\Tests\JsonApiServer\AbstractTestCase; + +class RelationshipInclusionTest extends AbstractTestCase +{ + public function setUp(): void + { + + } + + public function test_to_one_relationships_are_not_includable_by_default() + { + $this->markTestIncomplete(); + } + + public function test_to_one_relationships_can_be_made_includable() + { + $this->markTestIncomplete(); + } + + public function test_to_one_relationships_can_be_made_not_includable() + { + $this->markTestIncomplete(); + } + + public function test_included_to_one_relationships_are_preloaded_via_the_adapter() + { + $this->markTestIncomplete(); + } + + public function test_to_one_relationships_can_have_custom_preloaders() + { + $this->markTestIncomplete(); + } + + // to_many... + + public function test_multiple_relationships_can_be_included() + { + $this->markTestIncomplete(); + } + + public function test_nested_relationships_can_be_included() + { + $this->markTestIncomplete(); + } + + public function test_nested_relationships_include_intermediate_resources() + { + $this->markTestIncomplete(); + } + + public function test_relationships_can_be_included_on_single_resource_requests() + { + $this->markTestIncomplete(); + } + + public function test_relationships_can_be_included_on_resource_listing_requests() + { + $this->markTestIncomplete(); + } + + public function test_relationships_can_be_included_on_create_requests() + { + $this->markTestIncomplete(); + } + + public function test_relationships_can_be_included_on_update_requests() + { + $this->markTestIncomplete(); + } +} diff --git a/tests/feature/RelationshipLinkageTest.php b/tests/feature/RelationshipLinkageTest.php new file mode 100644 index 0000000..2289507 --- /dev/null +++ b/tests/feature/RelationshipLinkageTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\feature; + +use Tobyz\Tests\JsonApiServer\AbstractTestCase; + +class RelationshipLinkageTest extends AbstractTestCase +{ + public function setUp(): void + { + + } + + public function test_to_one_relationships_do_not_show_linkage_by_default() + { + $this->markTestIncomplete(); + } + + public function test_to_one_relationship_linkage_can_be_enabled() + { + $this->markTestIncomplete(); + } + + public function test_to_one_relationships_linkage_can_be_re_disabled() + { + $this->markTestIncomplete(); + } + + // to_many... +} diff --git a/tests/feature/RelationshipLinksTest.php b/tests/feature/RelationshipLinksTest.php new file mode 100644 index 0000000..f02ef3c --- /dev/null +++ b/tests/feature/RelationshipLinksTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\feature; + +use Tobyz\Tests\JsonApiServer\AbstractTestCase; + +class RelationshipLinksTest extends AbstractTestCase +{ + public function setUp(): void + { + + } + + public function test_to_one_relationships_have_self_and_related_links_by_default() + { + $this->markTestIncomplete(); + } + + public function test_to_one_relationship_links_can_be_disabled() + { + $this->markTestIncomplete(); + } + + public function test_to_one_relationships_links_can_be_re_enabled() + { + $this->markTestIncomplete(); + } + + // to_many... +} diff --git a/tests/feature/RelationshipMetaTest.php b/tests/feature/RelationshipMetaTest.php new file mode 100644 index 0000000..863a4ab --- /dev/null +++ b/tests/feature/RelationshipMetaTest.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\feature; + +use Tobyz\JsonApiServer\JsonApi; +use Tobyz\Tests\JsonApiServer\AbstractTestCase; +use Tobyz\Tests\JsonApiServer\MockAdapter; + +class RelationshipMetaTest extends AbstractTestCase +{ + /** + * @var JsonApi + */ + 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_a_relationship_with_a_value() + { + $this->markTestIncomplete(); + } + + public function test_meta_fields_can_be_added_to_a_relationship_with_a_closure() + { + $this->markTestIncomplete(); + } +} diff --git a/tests/feature/RelationshipTypesTest.php b/tests/feature/RelationshipTypesTest.php new file mode 100644 index 0000000..a8fff29 --- /dev/null +++ b/tests/feature/RelationshipTypesTest.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\feature; + +use Tobyz\Tests\JsonApiServer\AbstractTestCase; + +class RelationshipTypesTest extends AbstractTestCase +{ + public function setUp(): void + { + + } + + public function test_to_one_relationship_type_is_inferred_from_relationship_name() + { + $this->markTestIncomplete(); + } + + public function test_to_one_relationships_can_specify_a_type() + { + $this->markTestIncomplete(); + } + + public function test_to_one_relationships_can_be_polymorphic() + { + $this->markTestIncomplete(); + } + + public function test_nested_includes_cannot_be_requested_on_polymorphic_to_one_relationships() + { + $this->markTestIncomplete(); + } + + // to_many... +} diff --git a/tests/feature/ScopesTest.php b/tests/feature/ScopesTest.php new file mode 100644 index 0000000..e6f71a4 --- /dev/null +++ b/tests/feature/ScopesTest.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +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; +use Tobyz\Tests\JsonApiServer\MockAdapter; + +class ScopesTest extends AbstractTestCase +{ + /** + * @var JsonApi + */ + private $api; + + /** + * @var MockAdapter + */ + private $adapter; + + public function setUp(): void + { + $this->api = new JsonApi('http://example.com'); + + $this->adapter = new MockAdapter(); + } + + public function test_scopes_are_applied_to_the_resource_listing_query() + { + $this->markTestIncomplete(); + } + + public function test_scopes_are_applied_to_the_show_resource_query() + { + $this->markTestIncomplete(); + } + + public function test_scopes_are_applied_to_the_update_resource_query() + { + $this->markTestIncomplete(); + } + + public function test_scopes_are_applied_to_the_delete_resource_query() + { + $this->markTestIncomplete(); + } +} diff --git a/tests/feature/AttributeSortableTest.php b/tests/feature/SortingTest.php similarity index 80% rename from tests/feature/AttributeSortableTest.php rename to tests/feature/SortingTest.php index 3bd290a..914ce7d 100644 --- a/tests/feature/AttributeSortableTest.php +++ b/tests/feature/SortingTest.php @@ -18,7 +18,7 @@ use Tobyz\JsonApiServer\Schema\Type; use Tobyz\Tests\JsonApiServer\AbstractTestCase; use Tobyz\Tests\JsonApiServer\MockAdapter; -class AttributeSortableTest extends AbstractTestCase +class SortingTest extends AbstractTestCase { /** * @var JsonApi @@ -37,7 +37,21 @@ class AttributeSortableTest extends AbstractTestCase $this->adapter = new MockAdapter(); } - public function test_attributes_can_be_sortable() + public function test_attributes_are_not_sortable_by_default() + { + $this->api->resource('users', $this->adapter, function (Type $type) { + $type->attribute('name'); + }); + + $this->expectException(BadRequestException::class); + + $this->api->handle( + $this->buildRequest('GET', '/users') + ->withQueryParams(['sort' => 'name']) + ); + } + + public function test_attributes_can_be_sortable_by_their_value() { $attribute = null; @@ -77,18 +91,9 @@ class AttributeSortableTest extends AbstractTestCase $this->assertTrue(empty($this->adapter->query->sort)); } - public function test_attributes_are_not_sortable_by_default() + public function test_attribute_sortable_callback_receives_correct_parameters() { - $this->api->resource('users', $this->adapter, function (Type $type) { - $type->attribute('name'); - }); - - $this->expectException(BadRequestException::class); - - $this->api->handle( - $this->buildRequest('GET', '/users') - ->withQueryParams(['sort' => 'name']) - ); + $this->markTestIncomplete(); } public function test_attributes_can_be_explicitly_not_sortable() @@ -104,4 +109,24 @@ class AttributeSortableTest extends AbstractTestCase ->withQueryParams(['sort' => 'name']) ); } + + public function test_types_can_have_custom_sort_fields() + { + $this->markTestIncomplete(); + } + + public function test_types_can_have_a_default_sort() + { + $this->markTestIncomplete(); + } + + public function test_multiple_sort_fields_can_be_requested() + { + $this->markTestIncomplete(); + } + + public function test_sort_fields_can_be_descending_with_minus_prefix() + { + $this->markTestIncomplete(); + } } diff --git a/tests/feature/UpdateTest.php b/tests/feature/UpdateTest.php new file mode 100644 index 0000000..d45905e --- /dev/null +++ b/tests/feature/UpdateTest.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\feature; + +use Tobyz\JsonApiServer\JsonApi; +use Tobyz\Tests\JsonApiServer\AbstractTestCase; +use Tobyz\Tests\JsonApiServer\MockAdapter; + +class UpdateTest extends AbstractTestCase +{ + /** + * @var JsonApi + */ + private $api; + + /** + * @var MockAdapter + */ + private $adapter; + + public function setUp(): void + { + $this->api = new JsonApi('http://example.com'); + + $this->adapter = new MockAdapter(); + } + + public function test_resources_are_not_updatable_by_default() + { + $this->markTestIncomplete(); + } + + public function test_resource_updating_can_be_explicitly_enabled() + { + $this->markTestIncomplete(); + } + + public function test_resource_updating_can_be_conditionally_enabled() + { + $this->markTestIncomplete(); + } + + public function test_resource_updating_can_be_explicitly_disabled() + { + $this->markTestIncomplete(); + } + + public function test_resource_updating_can_be_conditionally_disabled() + { + $this->markTestIncomplete(); + } + + public function test_updating_a_resource_calls_the_save_adapter_method() + { + $this->markTestIncomplete(); + } + + // saver... + // listeners... +} diff --git a/tests/specification/ContentNegotiationTest.php b/tests/specification/ContentNegotiationTest.php index b24d51e..655c344 100644 --- a/tests/specification/ContentNegotiationTest.php +++ b/tests/specification/ContentNegotiationTest.php @@ -18,6 +18,9 @@ use Tobyz\JsonApiServer\Schema\Type; use Tobyz\Tests\JsonApiServer\AbstractTestCase; use Tobyz\Tests\JsonApiServer\MockAdapter; +/** + * @see https://jsonapi.org/format/#content-negotiation + */ class ContentNegotiationTest extends AbstractTestCase { /** @@ -33,7 +36,7 @@ class ContentNegotiationTest extends AbstractTestCase }); } - public function testJsonApiContentTypeIsReturned() + public function test_json_api_content_type_is_returned() { $response = $this->api->handle( $this->buildRequest('GET', '/users/1') @@ -45,7 +48,7 @@ class ContentNegotiationTest extends AbstractTestCase ); } - public function testErrorWhenValidRequestContentTypeHasParameters() + public function test_error_when_valid_request_content_type_has_parameters() { $request = $this->buildRequest('PATCH', '/users/1') ->withHeader('Content-Type', 'application/vnd.api+json;profile="http://example.com/last-modified"'); @@ -55,7 +58,7 @@ class ContentNegotiationTest extends AbstractTestCase $this->api->handle($request); } - public function testErrorWhenAllValidAcceptsHaveParameters() + public function test_error_when_all_valid_accepts_have_parameters() { $request = $this->buildRequest('GET', '/users/1') ->withHeader('Accept', 'application/vnd.api+json;profile="http://example.com/last-modified", application/vnd.api+json;profile="http://example.com/versioning"'); @@ -65,7 +68,7 @@ class ContentNegotiationTest extends AbstractTestCase $this->api->handle($request); } - public function testSuccessWhenOnlySomeAcceptsHaveParameters() + public function test_success_when_only_some_accepts_have_parameters() { $response = $this->api->handle( $this->buildRequest('GET', '/users/1') diff --git a/tests/specification/CreatingResourcesTest.php b/tests/specification/CreatingResourcesTest.php new file mode 100644 index 0000000..05294e1 --- /dev/null +++ b/tests/specification/CreatingResourcesTest.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\specification; + +use Tobyz\JsonApiServer\JsonApi; +use Tobyz\Tests\JsonApiServer\AbstractTestCase; +use Tobyz\Tests\JsonApiServer\MockAdapter; + +/** + * @see https://jsonapi.org/format/1.0/#crud-creating + */ +class CreatingResourcesTest extends AbstractTestCase +{ + /** + * @var JsonApi + */ + private $api; + + /** + * @var MockAdapter + */ + private $adapter; + + public function setUp(): void + { + $this->api = new JsonApi('http://example.com'); + + $this->adapter = new MockAdapter(); + } + + public function test_bad_request_error_if_body_does_not_contain_data_type() + { + $this->markTestIncomplete(); + } + + public function test_bad_request_error_if_relationship_does_not_contain_data() + { + $this->markTestIncomplete(); + } + + public function test_forbidden_error_if_client_generated_id_provided() + { + $this->markTestIncomplete(); + } + + public function test_created_response_if_resource_successfully_created() + { + $this->markTestIncomplete(); + } + + public function test_created_response_includes_created_data() + { + $this->markTestIncomplete(); + } + + public function test_created_response_includes_location_header_and_matches_self_link() + { + $this->markTestIncomplete(); + } + + public function test_not_found_error_if_references_resource_that_does_not_exist() + { + $this->markTestIncomplete(); + } + + public function test_conflict_error_if_type_does_not_match_endpoint() + { + $this->markTestIncomplete(); + } +} diff --git a/tests/specification/DeletingResourcesTest.php b/tests/specification/DeletingResourcesTest.php new file mode 100644 index 0000000..2e20aa8 --- /dev/null +++ b/tests/specification/DeletingResourcesTest.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\specification; + +use Tobyz\JsonApiServer\JsonApi; +use Tobyz\Tests\JsonApiServer\AbstractTestCase; +use Tobyz\Tests\JsonApiServer\MockAdapter; + +/** + * @see https://jsonapi.org/format/1.0/#crud-deleting + */ +class DeletingResourcesTest extends AbstractTestCase +{ + /** + * @var JsonApi + */ + private $api; + + /** + * @var MockAdapter + */ + private $adapter; + + public function setUp(): void + { + $this->api = new JsonApi('http://example.com'); + + $this->adapter = new MockAdapter(); + } + + public function test_no_content_response_if_resource_successfully_deleted() + { + $this->markTestIncomplete(); + } + + public function test_not_found_error_if_resource_does_not_exist() + { + $this->markTestIncomplete(); + } +} diff --git a/tests/specification/FetchingResourcesTest.php b/tests/specification/FetchingResourcesTest.php new file mode 100644 index 0000000..314b76e --- /dev/null +++ b/tests/specification/FetchingResourcesTest.php @@ -0,0 +1,74 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\specification; + +use Tobyz\JsonApiServer\JsonApi; +use Tobyz\Tests\JsonApiServer\AbstractTestCase; +use Tobyz\Tests\JsonApiServer\MockAdapter; + +/** + * @see https://jsonapi.org/format/#fetching-resources + */ +class FetchingResourcesTest extends AbstractTestCase +{ + /** + * @var JsonApi + */ + private $api; + + /** + * @var MockAdapter + */ + private $adapter; + + public function setUp(): void + { + $this->api = new JsonApi('http://example.com'); + + $this->adapter = new MockAdapter(); + } + + public function test_data_for_resource_collection_is_array_of_resource_objects() + { + $this->markTestIncomplete(); + } + + public function test_data_for_empty_resource_collection_is_empty_array() + { + $this->markTestIncomplete(); + } + + public function test_data_for_individual_resource_is_resource_object() + { + $this->markTestIncomplete(); + } + + public function test_not_found_error_if_resource_type_does_not_exist() + { + $this->markTestIncomplete(); + } + + public function test_not_found_error_if_resource_does_not_exist() + { + $this->markTestIncomplete(); + } + + public function test_resource_collection_document_contains_self_link() + { + $this->markTestIncomplete(); + } + + public function test_resource_document_contains_self_link() + { + $this->markTestIncomplete(); + } +} diff --git a/tests/specification/JsonApiTest.php b/tests/specification/JsonApiTest.php new file mode 100644 index 0000000..1cdbf2c --- /dev/null +++ b/tests/specification/JsonApiTest.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\specification; + +use Tobyz\JsonApiServer\JsonApi; +use Tobyz\Tests\JsonApiServer\AbstractTestCase; +use Tobyz\Tests\JsonApiServer\MockAdapter; + +/** + * @see https://jsonapi.org/format/#document-jsonapi-object + */ +class JsonApiTest extends AbstractTestCase +{ + /** + * @var JsonApi + */ + private $api; + + /** + * @var MockAdapter + */ + private $adapter; + + public function setUp(): void + { + $this->api = new JsonApi('http://example.com'); + + $this->adapter = new MockAdapter(); + } + + public function test_document_includes_jsonapi_member_with_version_1_0() + { + $this->markTestIncomplete(); + } +} diff --git a/tests/specification/OffsetPaginationTest.php b/tests/specification/OffsetPaginationTest.php new file mode 100644 index 0000000..d26bc96 --- /dev/null +++ b/tests/specification/OffsetPaginationTest.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\specification; + +use Tobyz\JsonApiServer\JsonApi; +use Tobyz\Tests\JsonApiServer\AbstractTestCase; +use Tobyz\Tests\JsonApiServer\MockAdapter; + +/** + * @see https://jsonapi.org/format/1.0/#fetching-pagination + * @todo Create a profile for offset pagination strategy + */ +class OffsetPaginationTest extends AbstractTestCase +{ + /** + * @var JsonApi + */ + private $api; + + /** + * @var MockAdapter + */ + private $adapter; + + public function setUp(): void + { + $this->api = new JsonApi('http://example.com'); + + $this->adapter = new MockAdapter(); + } + + public function test_can_request_limit_on_resource_collection() + { + $this->markTestIncomplete(); + } + + public function test_can_request_offset_on_resource_collection() + { + $this->markTestIncomplete(); + } + + public function test_first_pagination_link_is_correct() + { + $this->markTestIncomplete(); + } + + public function test_last_pagination_link_is_correct() + { + $this->markTestIncomplete(); + } + + public function test_next_pagination_link_is_correct() + { + $this->markTestIncomplete(); + } + + public function test_next_pagination_link_is_not_included_on_last_page() + { + $this->markTestIncomplete(); + } + + public function test_prev_pagination_link_is_correct() + { + $this->markTestIncomplete(); + } + + public function test_prev_pagination_link_is_not_included_on_last_page() + { + $this->markTestIncomplete(); + } + + public function test_pagination_links_retain_other_query_parameters() + { + $this->markTestIncomplete(); + } +} diff --git a/tests/specification/QueryParametersTest.php b/tests/specification/QueryParametersTest.php new file mode 100644 index 0000000..8ab7989 --- /dev/null +++ b/tests/specification/QueryParametersTest.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\specification; + +use Tobyz\JsonApiServer\JsonApi; +use Tobyz\Tests\JsonApiServer\AbstractTestCase; +use Tobyz\Tests\JsonApiServer\MockAdapter; + +/** + * @see https://jsonapi.org/format/#query-parameters + */ +class QueryParametersTest extends AbstractTestCase +{ + /** + * @var JsonApi + */ + private $api; + + /** + * @var MockAdapter + */ + private $adapter; + + public function setUp(): void + { + $this->api = new JsonApi('http://example.com'); + + $this->adapter = new MockAdapter(); + } + + public function test_bad_request_error_if_unknown_query_parameters() + { + $this->markTestIncomplete(); + } +} diff --git a/tests/specification/SparseFieldsetsTest.php b/tests/specification/SparseFieldsetsTest.php new file mode 100644 index 0000000..8ebd22b --- /dev/null +++ b/tests/specification/SparseFieldsetsTest.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\specification; + +use Tobyz\JsonApiServer\JsonApi; +use Tobyz\Tests\JsonApiServer\AbstractTestCase; +use Tobyz\Tests\JsonApiServer\MockAdapter; + +/** + * @see https://jsonapi.org/format/1.0/#fetching-sparse-fieldsets + */ +class SparseFieldsetsTest extends AbstractTestCase +{ + /** + * @var JsonApi + */ + private $api; + + /** + * @var MockAdapter + */ + private $adapter; + + public function setUp(): void + { + $this->api = new JsonApi('http://example.com'); + + $this->adapter = new MockAdapter(); + } + + public function test_can_request_sparse_fieldsets_for_a_type() + { + $this->markTestIncomplete(); + } + + public function test_can_request_sparse_fieldsets_for_multiple_types() + { + $this->markTestIncomplete(); + } + + public function test_can_request_sparse_fieldsets_on_resource_collections() + { + $this->markTestIncomplete(); + } + + public function test_can_request_sparse_fieldsets_on_create() + { + $this->markTestIncomplete(); + } + + public function test_can_request_sparse_fieldsets_on_update() + { + $this->markTestIncomplete(); + } +} diff --git a/tests/specification/UpdatingResourcesTest.php b/tests/specification/UpdatingResourcesTest.php new file mode 100644 index 0000000..68daff2 --- /dev/null +++ b/tests/specification/UpdatingResourcesTest.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\specification; + +use Tobyz\JsonApiServer\JsonApi; +use Tobyz\Tests\JsonApiServer\AbstractTestCase; +use Tobyz\Tests\JsonApiServer\MockAdapter; + +/** + * @see https://jsonapi.org/format/1.0/#crud-updating + */ +class UpdatingResourcesTest extends AbstractTestCase +{ + /** + * @var JsonApi + */ + private $api; + + /** + * @var MockAdapter + */ + private $adapter; + + public function setUp(): void + { + $this->api = new JsonApi('http://example.com'); + + $this->adapter = new MockAdapter(); + } + + public function test_bad_request_error_if_body_does_not_contain_data_type_and_id() + { + $this->markTestIncomplete(); + } + + public function test_only_included_attributes_are_processed() + { + $this->markTestIncomplete(); + } + + public function test_only_included_relationships_are_processed() + { + $this->markTestIncomplete(); + } + + public function test_bad_request_error_if_relationship_does_not_contain_data() + { + $this->markTestIncomplete(); + } + + public function test_ok_response_if_resource_successfully_updated() + { + $this->markTestIncomplete(); + } + + public function test_ok_response_includes_updated_data() + { + $this->markTestIncomplete(); + } + + public function test_not_found_error_if_resource_does_not_exist() + { + $this->markTestIncomplete(); + } + + public function test_not_found_error_if_references_resource_that_does_not_exist() + { + $this->markTestIncomplete(); + } + + public function test_conflict_error_if_type_and_id_does_not_match_endpoint() + { + $this->markTestIncomplete(); + } +} diff --git a/tests/unit/MediaTypesTest.php b/tests/unit/Http/MediaTypesTest.php similarity index 76% rename from tests/unit/MediaTypesTest.php rename to tests/unit/Http/MediaTypesTest.php index 8200ba4..b4b9bcb 100644 --- a/tests/unit/MediaTypesTest.php +++ b/tests/unit/Http/MediaTypesTest.php @@ -16,7 +16,7 @@ use Tobyz\JsonApiServer\Http\MediaTypes; class MediaTypesTest extends TestCase { - public function testContainsOnExactMatch() + public function test_contains_on_exact_match() { $header = new MediaTypes('application/json'); @@ -25,7 +25,7 @@ class MediaTypesTest extends TestCase ); } - public function testContainsDoesNotMatchWithExtraParameters() + public function test_contains_does_not_match_with_extra_parameters() { $header = new MediaTypes('application/json; profile=foo'); @@ -34,7 +34,7 @@ class MediaTypesTest extends TestCase ); } - public function testContainsMatchesWhenOnlyWeightIsProvided() + public function test_contains_matches_when_only_weight_is_provided() { $header = new MediaTypes('application/json; q=0.8'); @@ -43,7 +43,7 @@ class MediaTypesTest extends TestCase ); } - public function testContainsDoesNotMatchWithExtraParametersBeforeWeight() + public function test_contains_does_not_match_with_extra_parameters_before_weight() { $header = new MediaTypes('application/json; profile=foo; q=0.8'); @@ -52,7 +52,7 @@ class MediaTypesTest extends TestCase ); } - public function testContainsMatchesWithExtraParametersAfterWeight() + public function test_contains_matches_with_extra_parameters_after_weight() { $header = new MediaTypes('application/json; q=0.8; profile=foo'); @@ -61,7 +61,7 @@ class MediaTypesTest extends TestCase ); } - public function testContainsMatchesWhenOneOfMultipleMediaTypesIsValid() + public function test_contains_matches_when_one_of_multiple_media_types_is_valid() { $header = new MediaTypes('application/json; profile=foo, application/json; q=0.6'); diff --git a/tests/unit/JsonApiTest.php b/tests/unit/JsonApiTest.php new file mode 100644 index 0000000..da29a22 --- /dev/null +++ b/tests/unit/JsonApiTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\unit\Http; + +use PHPUnit\Framework\TestCase; + +class JsonApiTest extends TestCase +{ + public function test_error_converts_error_provider_to_json_api_response() + { + $this->markTestIncomplete(); + } + + public function test_error_converts_non_error_provider_to_internal_server_error() + { + $this->markTestIncomplete(); + } +} diff --git a/tests/unit/Schema/TypeTest.php b/tests/unit/Schema/TypeTest.php new file mode 100644 index 0000000..ff119fa --- /dev/null +++ b/tests/unit/Schema/TypeTest.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tobyz\Tests\JsonApiServer\unit\Schema; + +use PHPUnit\Framework\TestCase; +use Tobyz\JsonApiServer\Schema\Type; + +class TypeTest extends TestCase +{ + public function test_returns_an_existing_field_with_the_same_name_of_the_same_type() + { + $type = new Type; + + $attribute = $type->attribute('dogs'); + $attributeAgain = $type->attribute('dogs'); + $fields = $type->getFields(); + + $this->assertSame($attribute, $attributeAgain); + $this->assertEquals(1, count($fields)); + } + + public function test_overwrites_an_existing_field_with_the_same_name_of_a_different_type() + { + $type = new Type; + + $attribute = $type->attribute('dogs'); + $hasOne = $type->hasOne('dogs'); + $fields = $type->getFields(); + + $this->assertNotSame($attribute, $hasOne); + $this->assertEquals(1, count($fields)); + $this->assertSame($hasOne, $fields['dogs']); + } +}