From 55e200098756d0a0a5c2055ae099270fb0b0e290 Mon Sep 17 00:00:00 2001 From: Benedikt Franke Date: Fri, 1 Jul 2022 12:01:39 +0200 Subject: [PATCH] Improve error for missing required data (#56) --- CHANGELOG.md | 10 +++ README.md | 12 +-- examples/custom-types/sailor.php | 2 + examples/input/sailor.php | 2 + .../AllMembers/Members/Organization.php | 2 +- .../Operations/AllMembers/Members/User.php | 2 +- .../NodeMembers/Members/Organization.php | 2 +- .../Operations/NodeMembers/Members/User.php | 2 +- .../expected/Operations/NodeWithFragments.php | 8 +- .../NodeWithFragments/Node/Node/Node/Post.php | 2 +- .../NodeWithFragments/Node/Node/Node/Task.php | 2 +- .../NodeWithFragments/Node/Node/Node/User.php | 2 +- .../NodeWithFragments/Node/Node/Post.php | 8 +- .../NodeWithFragments/Node/Node/Task.php | 8 +- .../NodeWithFragments/Node/Node/User.php | 8 +- .../NodeWithFragments/Node/Post.php | 8 +- .../NodeWithFragments/Node/Task.php | 8 +- .../NodeWithFragments/Node/User.php | 8 +- .../NodeWithFragments/NodeWithFragments.php | 6 +- .../Operations/UserOrPost/Node/Post.php | 2 +- .../Operations/UserOrPost/Node/Task.php | 2 +- .../Operations/UserOrPost/Node/User.php | 2 +- .../Operations/UserOrPost/UserOrPost.php | 6 +- examples/polymorphic/sailor.php | 1 + examples/polymorphic/schema.graphql | 12 +-- .../polymorphic/src/nodeWithFragments.graphql | 8 +- examples/simple/sailor.php | 2 + src/Codegen/OperationGenerator.php | 10 +-- src/ObjectLike.php | 45 ++++++++--- tests/Integration/CustomTypesTest.php | 68 ++++++++++------- tests/Integration/InputTest.php | 12 +-- tests/Integration/PolymorphicTest.php | 74 ++++++++++--------- tests/Integration/SimpleTest.php | 50 +++++++------ tests/Unit/ObjectLikeTest.php | 27 ++++++- tests/Unit/ResultTest.php | 7 +- 35 files changed, 259 insertions(+), 171 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8083c04..c5246d50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## v0.21.1 + +### Changed + +- Improve validation error for missing fields or required data + +### Fixed + +- Add correct `__typename` in polymorphic types `make()` method + ## v0.21.0 ### Added diff --git a/README.md b/README.md index a2622973..6f2089c6 100644 --- a/README.md +++ b/README.md @@ -387,19 +387,19 @@ When registered, the mock captures all calls to `HelloSailor::execute()`. Use it to build up expectations for what calls it should receive and mock returned results: ```php +$hello = 'Hello, Sailor!'; + $mock ->expects('execute') ->once() ->with('Sailor') - ->andReturn(HelloSailorResult::fromStdClass((object) [ - 'data' => (object) [ - 'hello' => 'Hello, Sailor!', - ], - ])); + ->andReturn(HelloSailorResult::fromData( + HelloSailor\HelloSailor::make($hello), + )); $result = HelloSailor::execute('Sailor')->errorFree(); -self::assertSame('Hello, Sailor!', $result->data->hello); +self::assertSame($hello, $result->data->hello); ``` Subsequent calls to `::mock()` will return the initially registered mock instance. diff --git a/examples/custom-types/sailor.php b/examples/custom-types/sailor.php index bf3dc8fa..e870f6d9 100644 --- a/examples/custom-types/sailor.php +++ b/examples/custom-types/sailor.php @@ -38,7 +38,9 @@ public function makeClient(): Client $mockClient->responseMocks[] = static function (): Response { return Response::fromStdClass((object) [ 'data' => (object) [ + '__typename' => 'Query', 'singleObject' => (object) [ + '__typename' => 'SomeObject', 'value' => 42, ], ], diff --git a/examples/input/sailor.php b/examples/input/sailor.php index 08a55c17..7addcc6b 100644 --- a/examples/input/sailor.php +++ b/examples/input/sailor.php @@ -34,7 +34,9 @@ public function makeClient(): Client $mockClient->responseMocks[] = static function (): Response { return Response::fromStdClass((object) [ 'data' => (object) [ + '__typename' => 'Query', 'singleObject' => (object) [ + '__typename' => 'SomeObject', 'value' => 42, ], ], diff --git a/examples/polymorphic/expected/Operations/AllMembers/Members/Organization.php b/examples/polymorphic/expected/Operations/AllMembers/Members/Organization.php index ce40eb1e..52f36b8f 100644 --- a/examples/polymorphic/expected/Operations/AllMembers/Members/Organization.php +++ b/examples/polymorphic/expected/Operations/AllMembers/Members/Organization.php @@ -20,7 +20,7 @@ public static function make($code): self if ($code !== self::UNDEFINED) { $instance->code = $code; } - $instance->__typename = 'Member'; + $instance->__typename = 'Organization'; return $instance; } diff --git a/examples/polymorphic/expected/Operations/AllMembers/Members/User.php b/examples/polymorphic/expected/Operations/AllMembers/Members/User.php index 1faf90f4..8b6220f4 100644 --- a/examples/polymorphic/expected/Operations/AllMembers/Members/User.php +++ b/examples/polymorphic/expected/Operations/AllMembers/Members/User.php @@ -17,7 +17,7 @@ public static function make($name = 'Special default value that allows Sailor to { $instance = new self; - $instance->__typename = 'Member'; + $instance->__typename = 'User'; if ($name !== self::UNDEFINED) { $instance->name = $name; } diff --git a/examples/polymorphic/expected/Operations/NodeMembers/Members/Organization.php b/examples/polymorphic/expected/Operations/NodeMembers/Members/Organization.php index 2893e716..8f588137 100644 --- a/examples/polymorphic/expected/Operations/NodeMembers/Members/Organization.php +++ b/examples/polymorphic/expected/Operations/NodeMembers/Members/Organization.php @@ -13,7 +13,7 @@ public static function make(): self { $instance = new self; - $instance->__typename = 'Member'; + $instance->__typename = 'Organization'; return $instance; } diff --git a/examples/polymorphic/expected/Operations/NodeMembers/Members/User.php b/examples/polymorphic/expected/Operations/NodeMembers/Members/User.php index 76985ba8..d6736d5d 100644 --- a/examples/polymorphic/expected/Operations/NodeMembers/Members/User.php +++ b/examples/polymorphic/expected/Operations/NodeMembers/Members/User.php @@ -20,7 +20,7 @@ public static function make($id): self if ($id !== self::UNDEFINED) { $instance->id = $id; } - $instance->__typename = 'Member'; + $instance->__typename = 'User'; return $instance; } diff --git a/examples/polymorphic/expected/Operations/NodeWithFragments.php b/examples/polymorphic/expected/Operations/NodeWithFragments.php index d76f9616..ce91de52 100644 --- a/examples/polymorphic/expected/Operations/NodeWithFragments.php +++ b/examples/polymorphic/expected/Operations/NodeWithFragments.php @@ -44,6 +44,10 @@ public static function document(): string } } } + ... on Post { + id + title + } ... on Task { done node { @@ -56,10 +60,6 @@ public static function document(): string } } } - ... on Post { - id - title - } } }'; } diff --git a/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Node/Node/Post.php b/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Node/Node/Post.php index 30fc1360..e75bb255 100644 --- a/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Node/Node/Post.php +++ b/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Node/Node/Post.php @@ -20,7 +20,7 @@ public static function make($id): self if ($id !== self::UNDEFINED) { $instance->id = $id; } - $instance->__typename = 'Node'; + $instance->__typename = 'Post'; return $instance; } diff --git a/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Node/Node/Task.php b/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Node/Node/Task.php index 0d4e675f..863f27c1 100644 --- a/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Node/Node/Task.php +++ b/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Node/Node/Task.php @@ -20,7 +20,7 @@ public static function make($id): self if ($id !== self::UNDEFINED) { $instance->id = $id; } - $instance->__typename = 'Node'; + $instance->__typename = 'Task'; return $instance; } diff --git a/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Node/Node/User.php b/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Node/Node/User.php index ca90afe0..dbe1af23 100644 --- a/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Node/Node/User.php +++ b/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Node/Node/User.php @@ -24,7 +24,7 @@ public static function make( if ($id !== self::UNDEFINED) { $instance->id = $id; } - $instance->__typename = 'Node'; + $instance->__typename = 'User'; if ($name !== self::UNDEFINED) { $instance->name = $name; } diff --git a/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Node/Post.php b/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Node/Post.php index e5fb30e9..9be487a3 100644 --- a/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Node/Post.php +++ b/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Node/Post.php @@ -6,18 +6,18 @@ /** * @property string $__typename - * @property \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\Task|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\Post|null $node + * @property \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\Post|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\Task|null $node */ class Post extends \Spawnia\Sailor\ObjectLike { /** - * @param \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\Task|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\Post|null $node + * @param \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\Post|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\Task|null $node */ public static function make($node = 'Special default value that allows Sailor to differentiate between explicitly passing null and not passing a value at all.'): self { $instance = new self; - $instance->__typename = 'Node'; + $instance->__typename = 'Post'; if ($node !== self::UNDEFINED) { $instance->node = $node; } @@ -33,8 +33,8 @@ protected function converters(): array '__typename' => new \Spawnia\Sailor\Convert\NonNullConverter(new \Spawnia\Sailor\Convert\StringConverter), 'node' => new \Spawnia\Sailor\Convert\NullConverter(new \Spawnia\Sailor\Convert\PolymorphicConverter([ 'User' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Node\\Node\\User', - 'Task' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Node\\Node\\Task', 'Post' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Node\\Node\\Post', + 'Task' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Node\\Node\\Task', ])), ]; } diff --git a/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Node/Task.php b/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Node/Task.php index d60f269b..f48ba6d2 100644 --- a/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Node/Task.php +++ b/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Node/Task.php @@ -6,18 +6,18 @@ /** * @property string $__typename - * @property \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\Task|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\Post|null $node + * @property \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\Post|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\Task|null $node */ class Task extends \Spawnia\Sailor\ObjectLike { /** - * @param \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\Task|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\Post|null $node + * @param \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\Post|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\Task|null $node */ public static function make($node = 'Special default value that allows Sailor to differentiate between explicitly passing null and not passing a value at all.'): self { $instance = new self; - $instance->__typename = 'Node'; + $instance->__typename = 'Task'; if ($node !== self::UNDEFINED) { $instance->node = $node; } @@ -33,8 +33,8 @@ protected function converters(): array '__typename' => new \Spawnia\Sailor\Convert\NonNullConverter(new \Spawnia\Sailor\Convert\StringConverter), 'node' => new \Spawnia\Sailor\Convert\NullConverter(new \Spawnia\Sailor\Convert\PolymorphicConverter([ 'User' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Node\\Node\\User', - 'Task' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Node\\Node\\Task', 'Post' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Node\\Node\\Post', + 'Task' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Node\\Node\\Task', ])), ]; } diff --git a/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Node/User.php b/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Node/User.php index ae7a89f9..43c9c6d3 100644 --- a/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Node/User.php +++ b/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Node/User.php @@ -6,18 +6,18 @@ /** * @property string $__typename - * @property \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\Task|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\Post|null $node + * @property \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\Post|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\Task|null $node */ class User extends \Spawnia\Sailor\ObjectLike { /** - * @param \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\Task|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\Post|null $node + * @param \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\Post|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Node\Task|null $node */ public static function make($node = 'Special default value that allows Sailor to differentiate between explicitly passing null and not passing a value at all.'): self { $instance = new self; - $instance->__typename = 'Node'; + $instance->__typename = 'User'; if ($node !== self::UNDEFINED) { $instance->node = $node; } @@ -33,8 +33,8 @@ protected function converters(): array '__typename' => new \Spawnia\Sailor\Convert\NonNullConverter(new \Spawnia\Sailor\Convert\StringConverter), 'node' => new \Spawnia\Sailor\Convert\NullConverter(new \Spawnia\Sailor\Convert\PolymorphicConverter([ 'User' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Node\\Node\\User', - 'Task' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Node\\Node\\Task', 'Post' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Node\\Node\\Post', + 'Task' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Node\\Node\\Task', ])), ]; } diff --git a/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Post.php b/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Post.php index cca6b64e..dbe186a5 100644 --- a/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Post.php +++ b/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Post.php @@ -7,14 +7,14 @@ /** * @property string $id * @property string $__typename - * @property \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Task|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Post|null $node + * @property \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Post|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Task|null $node * @property string|null $title */ class Post extends \Spawnia\Sailor\ObjectLike { /** * @param string $id - * @param \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Task|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Post|null $node + * @param \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Post|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Task|null $node * @param string|null $title */ public static function make( @@ -27,7 +27,7 @@ public static function make( if ($id !== self::UNDEFINED) { $instance->id = $id; } - $instance->__typename = 'Node'; + $instance->__typename = 'Post'; if ($node !== self::UNDEFINED) { $instance->node = $node; } @@ -47,8 +47,8 @@ protected function converters(): array '__typename' => new \Spawnia\Sailor\Convert\NonNullConverter(new \Spawnia\Sailor\Convert\StringConverter), 'node' => new \Spawnia\Sailor\Convert\NullConverter(new \Spawnia\Sailor\Convert\PolymorphicConverter([ 'User' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Node\\User', - 'Task' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Node\\Task', 'Post' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Node\\Post', + 'Task' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Node\\Task', ])), 'title' => new \Spawnia\Sailor\Convert\NullConverter(new \Spawnia\Sailor\Convert\StringConverter), ]; diff --git a/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Task.php b/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Task.php index 2775b1e8..16bd670e 100644 --- a/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Task.php +++ b/examples/polymorphic/expected/Operations/NodeWithFragments/Node/Task.php @@ -7,13 +7,13 @@ /** * @property bool $done * @property string $__typename - * @property \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Task|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Post|null $node + * @property \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Post|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Task|null $node */ class Task extends \Spawnia\Sailor\ObjectLike { /** * @param bool $done - * @param \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Task|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Post|null $node + * @param \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Post|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Task|null $node */ public static function make( $done, @@ -24,7 +24,7 @@ public static function make( if ($done !== self::UNDEFINED) { $instance->done = $done; } - $instance->__typename = 'Node'; + $instance->__typename = 'Task'; if ($node !== self::UNDEFINED) { $instance->node = $node; } @@ -41,8 +41,8 @@ protected function converters(): array '__typename' => new \Spawnia\Sailor\Convert\NonNullConverter(new \Spawnia\Sailor\Convert\StringConverter), 'node' => new \Spawnia\Sailor\Convert\NullConverter(new \Spawnia\Sailor\Convert\PolymorphicConverter([ 'User' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Node\\User', - 'Task' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Node\\Task', 'Post' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Node\\Post', + 'Task' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Node\\Task', ])), ]; } diff --git a/examples/polymorphic/expected/Operations/NodeWithFragments/Node/User.php b/examples/polymorphic/expected/Operations/NodeWithFragments/Node/User.php index b8543245..b141c69a 100644 --- a/examples/polymorphic/expected/Operations/NodeWithFragments/Node/User.php +++ b/examples/polymorphic/expected/Operations/NodeWithFragments/Node/User.php @@ -6,18 +6,18 @@ /** * @property string $__typename - * @property \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Task|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Post|null $node + * @property \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Post|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Task|null $node */ class User extends \Spawnia\Sailor\ObjectLike { /** - * @param \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Task|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Post|null $node + * @param \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Post|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Node\Task|null $node */ public static function make($node = 'Special default value that allows Sailor to differentiate between explicitly passing null and not passing a value at all.'): self { $instance = new self; - $instance->__typename = 'Node'; + $instance->__typename = 'User'; if ($node !== self::UNDEFINED) { $instance->node = $node; } @@ -33,8 +33,8 @@ protected function converters(): array '__typename' => new \Spawnia\Sailor\Convert\NonNullConverter(new \Spawnia\Sailor\Convert\StringConverter), 'node' => new \Spawnia\Sailor\Convert\NullConverter(new \Spawnia\Sailor\Convert\PolymorphicConverter([ 'User' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Node\\User', - 'Task' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Node\\Task', 'Post' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Node\\Post', + 'Task' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Node\\Task', ])), ]; } diff --git a/examples/polymorphic/expected/Operations/NodeWithFragments/NodeWithFragments.php b/examples/polymorphic/expected/Operations/NodeWithFragments/NodeWithFragments.php index 9aa6929c..7d8ec703 100644 --- a/examples/polymorphic/expected/Operations/NodeWithFragments/NodeWithFragments.php +++ b/examples/polymorphic/expected/Operations/NodeWithFragments/NodeWithFragments.php @@ -5,13 +5,13 @@ namespace Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments; /** - * @property \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Task|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Post $node + * @property \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Post|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Task $node * @property string $__typename */ class NodeWithFragments extends \Spawnia\Sailor\ObjectLike { /** - * @param \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Task|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Post $node + * @param \Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\User|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Post|\Spawnia\Sailor\Polymorphic\Operations\NodeWithFragments\Node\Task $node */ public static function make($node): self { @@ -32,8 +32,8 @@ protected function converters(): array return $converters ??= [ 'node' => new \Spawnia\Sailor\Convert\NonNullConverter(new \Spawnia\Sailor\Convert\PolymorphicConverter([ 'User' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\User', - 'Task' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Task', 'Post' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Post', + 'Task' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\NodeWithFragments\\Node\\Task', ])), '__typename' => new \Spawnia\Sailor\Convert\NonNullConverter(new \Spawnia\Sailor\Convert\StringConverter), ]; diff --git a/examples/polymorphic/expected/Operations/UserOrPost/Node/Post.php b/examples/polymorphic/expected/Operations/UserOrPost/Node/Post.php index bbca360d..bfd66ee3 100644 --- a/examples/polymorphic/expected/Operations/UserOrPost/Node/Post.php +++ b/examples/polymorphic/expected/Operations/UserOrPost/Node/Post.php @@ -24,7 +24,7 @@ public static function make( if ($id !== self::UNDEFINED) { $instance->id = $id; } - $instance->__typename = 'Node'; + $instance->__typename = 'Post'; if ($title !== self::UNDEFINED) { $instance->title = $title; } diff --git a/examples/polymorphic/expected/Operations/UserOrPost/Node/Task.php b/examples/polymorphic/expected/Operations/UserOrPost/Node/Task.php index 33c4df5b..412a79bc 100644 --- a/examples/polymorphic/expected/Operations/UserOrPost/Node/Task.php +++ b/examples/polymorphic/expected/Operations/UserOrPost/Node/Task.php @@ -20,7 +20,7 @@ public static function make($id): self if ($id !== self::UNDEFINED) { $instance->id = $id; } - $instance->__typename = 'Node'; + $instance->__typename = 'Task'; return $instance; } diff --git a/examples/polymorphic/expected/Operations/UserOrPost/Node/User.php b/examples/polymorphic/expected/Operations/UserOrPost/Node/User.php index baacb663..8ed0388e 100644 --- a/examples/polymorphic/expected/Operations/UserOrPost/Node/User.php +++ b/examples/polymorphic/expected/Operations/UserOrPost/Node/User.php @@ -24,7 +24,7 @@ public static function make( if ($id !== self::UNDEFINED) { $instance->id = $id; } - $instance->__typename = 'Node'; + $instance->__typename = 'User'; if ($name !== self::UNDEFINED) { $instance->name = $name; } diff --git a/examples/polymorphic/expected/Operations/UserOrPost/UserOrPost.php b/examples/polymorphic/expected/Operations/UserOrPost/UserOrPost.php index 883f4ab9..5bdc0abf 100644 --- a/examples/polymorphic/expected/Operations/UserOrPost/UserOrPost.php +++ b/examples/polymorphic/expected/Operations/UserOrPost/UserOrPost.php @@ -5,13 +5,13 @@ namespace Spawnia\Sailor\Polymorphic\Operations\UserOrPost; /** - * @property \Spawnia\Sailor\Polymorphic\Operations\UserOrPost\Node\User|\Spawnia\Sailor\Polymorphic\Operations\UserOrPost\Node\Task|\Spawnia\Sailor\Polymorphic\Operations\UserOrPost\Node\Post $node + * @property \Spawnia\Sailor\Polymorphic\Operations\UserOrPost\Node\User|\Spawnia\Sailor\Polymorphic\Operations\UserOrPost\Node\Post|\Spawnia\Sailor\Polymorphic\Operations\UserOrPost\Node\Task $node * @property string $__typename */ class UserOrPost extends \Spawnia\Sailor\ObjectLike { /** - * @param \Spawnia\Sailor\Polymorphic\Operations\UserOrPost\Node\User|\Spawnia\Sailor\Polymorphic\Operations\UserOrPost\Node\Task|\Spawnia\Sailor\Polymorphic\Operations\UserOrPost\Node\Post $node + * @param \Spawnia\Sailor\Polymorphic\Operations\UserOrPost\Node\User|\Spawnia\Sailor\Polymorphic\Operations\UserOrPost\Node\Post|\Spawnia\Sailor\Polymorphic\Operations\UserOrPost\Node\Task $node */ public static function make($node): self { @@ -32,8 +32,8 @@ protected function converters(): array return $converters ??= [ 'node' => new \Spawnia\Sailor\Convert\NonNullConverter(new \Spawnia\Sailor\Convert\PolymorphicConverter([ 'User' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\UserOrPost\\Node\\User', - 'Task' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\UserOrPost\\Node\\Task', 'Post' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\UserOrPost\\Node\\Post', + 'Task' => '\\Spawnia\\Sailor\\Polymorphic\\Operations\\UserOrPost\\Node\\Task', ])), '__typename' => new \Spawnia\Sailor\Convert\NonNullConverter(new \Spawnia\Sailor\Convert\StringConverter), ]; diff --git a/examples/polymorphic/sailor.php b/examples/polymorphic/sailor.php index 4e9e9f3a..11d7bb44 100644 --- a/examples/polymorphic/sailor.php +++ b/examples/polymorphic/sailor.php @@ -34,6 +34,7 @@ public function makeClient(): Client $mockClient->responseMocks[] = static function (): Response { return Response::fromStdClass((object) [ 'data' => (object) [ + '__typename' => 'Query', 'node' => (object) [ '__typename' => 'User', 'id' => '1', diff --git a/examples/polymorphic/schema.graphql b/examples/polymorphic/schema.graphql index 5d462bd0..e29667eb 100644 --- a/examples/polymorphic/schema.graphql +++ b/examples/polymorphic/schema.graphql @@ -8,21 +8,21 @@ interface Node { node: Node } -type Post implements Node { +type User implements Node { id: ID! - title: String + name: String node: Node } -type Task implements Node { +type Post implements Node { id: ID! - done: Boolean! + title: String node: Node } -type User implements Node { +type Task implements Node { id: ID! - name: String + done: Boolean! node: Node } diff --git a/examples/polymorphic/src/nodeWithFragments.graphql b/examples/polymorphic/src/nodeWithFragments.graphql index d0c023f3..cb439dea 100644 --- a/examples/polymorphic/src/nodeWithFragments.graphql +++ b/examples/polymorphic/src/nodeWithFragments.graphql @@ -8,6 +8,10 @@ query NodeWithFragments($id: ID!) { } } } + ... on Post { + id + title + } ... on Task { done node { @@ -18,9 +22,5 @@ query NodeWithFragments($id: ID!) { } } } - ... on Post { - id - title - } } } diff --git a/examples/simple/sailor.php b/examples/simple/sailor.php index 668784d1..d1c06cee 100644 --- a/examples/simple/sailor.php +++ b/examples/simple/sailor.php @@ -34,7 +34,9 @@ public function makeClient(): Client $mockClient->responseMocks[] = static function (): Response { return Response::fromStdClass((object) [ 'data' => (object) [ + '__typename' => 'Query', 'singleObject' => (object) [ + '__typename' => 'SomeObject', 'value' => 42, ], ], diff --git a/src/Codegen/OperationGenerator.php b/src/Codegen/OperationGenerator.php index 14c62476..2dc3586f 100644 --- a/src/Codegen/OperationGenerator.php +++ b/src/Codegen/OperationGenerator.php @@ -287,11 +287,6 @@ public function generate(): iterable throw new \Exception("Unable to determine parent type of field {$fieldName}"); } - // Eases instantiation of mocked results - $defaultValue = Introspection::TYPE_NAME_FIELD_NAME === $fieldName - ? $parentType->name - : null; - foreach ($selectionClasses as $name => $selection) { $selectionType = $this->schema->getType($name); if (null === $selectionType) { @@ -299,6 +294,11 @@ public function generate(): iterable } if (TypeComparators::isTypeSubTypeOf($this->schema, $selectionType, $parentType)) { + // Eases instantiation of mocked results + $defaultValue = Introspection::TYPE_NAME_FIELD_NAME === $fieldName + ? $selectionType->name + : null; + $selection->addProperty( $fieldName, $type, diff --git a/src/ObjectLike.php b/src/ObjectLike.php index 2eefb470..ae20d182 100644 --- a/src/ObjectLike.php +++ b/src/ObjectLike.php @@ -26,6 +26,8 @@ abstract protected function converters(): array; /** * Construct a new instance of itself using plain data. * + * For mocking test data, prefer make(). + * * @return static */ public static function fromStdClass(stdClass $data): self @@ -34,7 +36,7 @@ public static function fromStdClass(stdClass $data): self } /** - * Convert itself to a stdClass. + * Represent itself as plain data. */ public function toStdClass(): stdClass { @@ -71,12 +73,10 @@ public function toGraphQL($value): stdClass if (! $value instanceof static) { $class = static::class; $notClass = gettype($value); - throw new InvalidArgumentException("Expected instanceof {$class}, got: {$notClass}"); } $serializable = new stdClass(); - foreach ($value->properties as $name => $property) { $serializable->{$name} = $this->converter($name)->toGraphQL($property); } @@ -90,15 +90,32 @@ public function toGraphQL($value): stdClass public function fromGraphQL($value): self { if (! $value instanceof stdClass) { - throw new InvalidArgumentException('Expected stdClass, got: ' . gettype($value)); + $endpoint = static::endpoint(); + $notStdClass = gettype($value); + throw new InvalidArgumentException("{$endpoint}: Expected stdClass, got: {$notStdClass}"); } $instance = new static(); + $converters = $this->converters(); + foreach ($converters as $name => $converter) { + if (! property_exists($value, $name)) { + $endpoint = static::endpoint(); + throw new InvalidDataException("{$endpoint}: Missing field {$name}."); + } + + try { + $instance->properties[$name] = $converter->fromGraphQL($value->{$name}); + unset($value->{$name}); + } catch (\Throwable $e) { + $endpoint = static::endpoint(); + throw new InvalidDataException("{$endpoint}: Invalid value for field {$name}. {$e->getMessage()}"); + } + } + // @phpstan-ignore-next-line iteration over object foreach ($value as $name => $property) { - // @phpstan-ignore-next-line variable property access - $instance->{$name} = $this->converter($name)->fromGraphQL($property); + throw static::unknownProperty($name, $converters); } return $instance; @@ -108,12 +125,20 @@ protected function converter(string $name): TypeConverter { $converters = $this->converters(); if (! isset($converters[$name])) { - $endpoint = static::endpoint(); - $availableProperties = implode(', ', array_keys($converters)); - - throw new InvalidDataException("{$endpoint}: Unknown property {$name}, available properties: {$availableProperties}."); + throw static::unknownProperty($name, $converters); } return $converters[$name]; } + + /** + * @param array $converters + */ + protected static function unknownProperty(string $name, array $converters): InvalidDataException + { + $endpoint = static::endpoint(); + $availableProperties = implode(', ', array_keys($converters)); + + return new InvalidDataException("{$endpoint}: Unknown property {$name}, available properties: {$availableProperties}."); + } } diff --git a/tests/Integration/CustomTypesTest.php b/tests/Integration/CustomTypesTest.php index 590bf2f8..4af53eae 100644 --- a/tests/Integration/CustomTypesTest.php +++ b/tests/Integration/CustomTypesTest.php @@ -27,11 +27,12 @@ public function testDefaultEnum(): void ->expects('execute') ->once() ->with($value) - ->andReturn(MyDefaultEnumQuery\MyDefaultEnumQueryResult::fromStdClass((object) [ - 'data' => (object) [ - 'withDefaultEnum' => $value, - ], - ])); + ->andReturn(MyDefaultEnumQuery\MyDefaultEnumQueryResult::fromData( + MyDefaultEnumQuery\MyDefaultEnumQuery::make( + /* withDefaultEnum: */ + $value, + ) + )); $result = MyDefaultEnumQuery::execute($value)->errorFree(); self::assertSame($value, $result->data->withDefaultEnum); @@ -45,11 +46,12 @@ public function testCustomEnum(): void ->expects('execute') ->once() ->with($value) - ->andReturn(MyCustomEnumQuery\MyCustomEnumQueryResult::fromStdClass((object) [ - 'data' => (object) [ - 'withCustomEnum' => $value->value, - ], - ])); + ->andReturn(MyCustomEnumQuery\MyCustomEnumQueryResult::fromData( + MyCustomEnumQuery\MyCustomEnumQuery::make( + /* withCustomEnum: */ + $value, + ) + )); $result = MyCustomEnumQuery::execute($value)->errorFree(); @@ -93,11 +95,12 @@ public function testBenSampoEnum(): void ->expects('execute') ->once() ->with($value) - ->andReturn(MyBenSampoEnumQuery\MyBenSampoEnumQueryResult::fromStdClass((object) [ - 'data' => (object) [ - 'withBenSampoEnum' => $value->value, - ], - ])); + ->andReturn(MyBenSampoEnumQuery\MyBenSampoEnumQueryResult::fromData( + MyBenSampoEnumQuery\MyBenSampoEnumQuery::make( + /* withBenSampoEnum: */ + $value, + ), + )); $result = MyBenSampoEnumQuery::execute($value)->errorFree(); @@ -111,28 +114,37 @@ public function testEnumInput(): void $custom = new CustomEnum(CustomEnum::B); $default = DefaultEnum::B; - $input = new EnumInput(); - $input->custom = $custom; - $input->default = $default; + $input = EnumInput::make( + /* default: */ + $default, + /* custom: */ + $custom, + ); MyEnumInputQuery::mock() ->expects('execute') ->once() ->with($input) - ->andReturn(MyEnumInputQuery\MyEnumInputQueryResult::fromStdClass((object) [ - 'data' => (object) [ - 'withEnumInput' => $input->toStdClass(), - ], - ])); - - $result = MyEnumInputQuery::execute($input)->errorFree(); + ->andReturn(MyEnumInputQuery\MyEnumInputQueryResult::fromData( + MyEnumInputQuery\MyEnumInputQuery::make( + /* withEnumInput: */ + MyEnumInputQuery\WithEnumInput\EnumObject::make( + /* custom: */ + $custom, + /* default: */ + $default, + ) + ), + )); + + $result = MyEnumInputQuery::execute($input) + ->errorFree(); $enumObject = $result->data->withEnumInput; self::assertNotNull($enumObject); $customEnum = $enumObject->custom; self::assertInstanceOf(CustomEnum::class, $customEnum); - self::assertSame($input->custom->value, $customEnum->value); - - self::assertSame($input->default, $enumObject->default); + self::assertSame($custom->value, $customEnum->value); + self::assertSame($default, $enumObject->default); } } diff --git a/tests/Integration/InputTest.php b/tests/Integration/InputTest.php index 928b9107..73baa4f1 100644 --- a/tests/Integration/InputTest.php +++ b/tests/Integration/InputTest.php @@ -23,12 +23,14 @@ public function testSomeInput(): void TakeSomeInput::mock() ->expects('execute') ->once() + // @phpstan-ignore-next-line loose comparison ->withArgs(fn (SomeInput $input): bool => $input == $someInput) - ->andReturn(TakeSomeInput\TakeSomeInputResult::fromStdClass((object) [ - 'data' => (object) [ - 'takeSomeInput' => $answer, - ], - ])); + ->andReturn(TakeSomeInput\TakeSomeInputResult::fromData( + TakeSomeInput\TakeSomeInput::make( + /* takeSomeInput: */ + $answer, + ) + )); $result = TakeSomeInput::execute($someInput)->errorFree(); self::assertSame($answer, $result->data->takeSomeInput); diff --git a/tests/Integration/PolymorphicTest.php b/tests/Integration/PolymorphicTest.php index a248ae07..54b2e360 100644 --- a/tests/Integration/PolymorphicTest.php +++ b/tests/Integration/PolymorphicTest.php @@ -22,15 +22,17 @@ public function testUserOrPost(): void ->expects('execute') ->once() ->with($id) - ->andReturn(UserOrPostResult::fromStdClass((object) [ - 'data' => (object) [ - 'node' => (object) [ - '__typename' => 'User', - 'id' => $id, - 'name' => $name, - ], - ], - ])); + ->andReturn(UserOrPostResult::fromData( + UserOrPost\UserOrPost::make( + /* node: */ + UserOrPost\Node\User::make( + /* id: */ + $id, + /* name: */ + $name, + ) + ) + )); $result = UserOrPost::execute($id)->errorFree(); $user = $result->data->node; @@ -49,20 +51,21 @@ public function testAllMembers(): void ->expects('execute') ->once() ->with() - ->andReturn(AllMembersResult::fromStdClass((object) [ - 'data' => (object) [ - 'members' => [ - (object) [ - '__typename' => 'User', - 'name' => $name, - ], - (object) [ - '__typename' => 'Organization', - 'code' => $code, - ], - ], - ], - ])); + ->andReturn(AllMembersResult::fromData( + AllMembers\AllMembers::make( + /* members: */ + [ + AllMembers\Members\User::make( + /* name: */ + $name, + ), + AllMembers\Members\Organization::make( + /* code: */ + $code, + ), + ] + ) + )); $result = AllMembers::execute()->errorFree(); $members = $result->data->members; @@ -85,19 +88,18 @@ public function testNodeMembers(): void ->expects('execute') ->once() ->with() - ->andReturn(NodeMembersResult::fromStdClass((object) [ - 'data' => (object) [ - 'members' => [ - (object) [ - '__typename' => 'User', - 'id' => $id, - ], - (object) [ - '__typename' => 'Organization', - ], - ], - ], - ])); + ->andReturn(NodeMembersResult::fromData( + NodeMembers\NodeMembers::make( + /* members: */ + [ + NodeMembers\Members\User::make( + /* id: */ + $id, + ), + NodeMembers\Members\Organization::make(), + ] + ) + )); $result = NodeMembers::execute()->errorFree(); $members = $result->data->members; diff --git a/tests/Integration/SimpleTest.php b/tests/Integration/SimpleTest.php index 0e597dd6..9df67129 100644 --- a/tests/Integration/SimpleTest.php +++ b/tests/Integration/SimpleTest.php @@ -25,10 +25,12 @@ public function testRequest(): void ->once() ->withArgs(function (string $query, \stdClass $variables): bool { return $query === MyScalarQuery::document() + // @phpstan-ignore-next-line loose comparison && $variables == new \stdClass(); }) ->andReturn(Response::fromStdClass((object) [ 'data' => (object) [ + '__typename' => 'Query', 'scalarWithArg' => $value, ], ])); @@ -100,11 +102,12 @@ public function testMockResult(): void MyScalarQuery::mock() ->expects('execute') - ->andReturn(MyScalarQueryResult::fromStdClass((object) [ - 'data' => (object) [ - 'scalarWithArg' => $bar, - ], - ])); + ->andReturn(MyScalarQueryResult::fromData( + MyScalarQuery\MyScalarQuery::make( + /* scalarWithArg: */ + $bar + ) + )); self::assertSame($bar, MyScalarQuery::execute()->errorFree()->data->scalarWithArg); } @@ -144,15 +147,18 @@ public function testNestedObject(): void ->expects('execute') ->once() ->with() - ->andReturn(MyObjectNestedQueryResult::fromStdClass((object) [ - 'data' => (object) [ - 'singleObject' => (object) [ - 'nested' => (object) [ - 'value' => $value, - ], - ], - ], - ])); + ->andReturn(MyObjectNestedQueryResult::fromData( + MyObjectNestedQuery\MyObjectNestedQuery::make( + /* singleObject: */ + MyObjectNestedQuery\SingleObject\SomeObject::make( + /* nested: */ + MyObjectNestedQuery\SingleObject\Nested\SomeObject::make( + /* value: */ + $value + ) + ) + ) + )); $result = MyObjectNestedQuery::execute()->errorFree(); $object = $result->data->singleObject; @@ -169,13 +175,15 @@ public function testNestedObjectNull(): void ->expects('execute') ->once() ->with() - ->andReturn(MyObjectNestedQueryResult::fromStdClass((object) [ - 'data' => (object) [ - 'singleObject' => (object) [ - 'nested' => null, - ], - ], - ])); + ->andReturn(MyObjectNestedQueryResult::fromData( + MyObjectNestedQuery\MyObjectNestedQuery::make( + /* singleObject: */ + MyObjectNestedQuery\SingleObject\SomeObject::make( + /* nested: */ + null + ) + ) + )); $result = MyObjectNestedQuery::execute()->errorFree(); $object = $result->data->singleObject; diff --git a/tests/Unit/ObjectLikeTest.php b/tests/Unit/ObjectLikeTest.php index 8e0adfae..da1e3d56 100644 --- a/tests/Unit/ObjectLikeTest.php +++ b/tests/Unit/ObjectLikeTest.php @@ -12,6 +12,7 @@ public function testFromStdClass(): void { $bar = 'bar'; $foo = MyScalarQuery::fromStdClass((object) [ + '__typename' => 'Query', 'scalarWithArg' => $bar, ]); @@ -29,13 +30,33 @@ public function testMake(): void self::assertSame($bar, $foo->scalarWithArg); } - public function testWrongKey(): void + public function testExtraneousKey(): void { $this->expectExceptionObject(new InvalidDataException( - 'Unknown property nonExistent, available properties: __typename, scalarWithArg.' + 'simple: Unknown property nonExistent, available properties: __typename, scalarWithArg.' )); MyScalarQuery::fromStdClass((object) [ - 'nonExistent' => 'foo', + '__typename' => 'Query', + 'scalarWithArg' => 'foo', + 'nonExistent' => 'bar', + ]); + } + + public function testMissingField(): void + { + $this->expectExceptionObject(new InvalidDataException( + 'simple: Missing field __typename.' + )); + MyScalarQuery::fromStdClass((object) []); + } + + public function testMissingRequiredValue(): void + { + $this->expectExceptionObject(new InvalidDataException( + 'simple: Invalid value for field __typename. Expected non-null value, got null' + )); + MyScalarQuery::fromStdClass((object) [ + '__typename' => null, ]); } } diff --git a/tests/Unit/ResultTest.php b/tests/Unit/ResultTest.php index db4e473b..2a15f9a4 100644 --- a/tests/Unit/ResultTest.php +++ b/tests/Unit/ResultTest.php @@ -64,9 +64,10 @@ public function testErrorFree(bool $isClientSafe): void Configuration::setEndpointFor(MyScalarQueryResult::class, $endpoint); $result = new MyScalarQueryResult(); - $result->data = MyScalarQuery::fromStdClass((object) [ - 'scalarWithArg' => null, - ]); + $result->data = MyScalarQuery::make( + /* scalarWithArg: */ + null, + ); // No errors $result->errorFree();