Total Complexity | 33 |
Total Lines | 324 |
Duplicated Lines | 0 % |
Changes | 0 |
1 | <?php |
||
24 | class TypesTest extends \PHPUnit\Framework\TestCase |
||
25 | { |
||
26 | use EntityManagerTrait; |
||
27 | |||
28 | /** |
||
29 | * @var Types |
||
30 | */ |
||
31 | private $types; |
||
32 | |||
33 | public function setUp(): void |
||
34 | { |
||
35 | $this->setUpEntityManager(); |
||
36 | |||
37 | $customTypes = new ServiceManager([ |
||
38 | 'invokables' => [ |
||
39 | BooleanType::class => BooleanType::class, |
||
40 | DateTime::class => DateTimeType::class, |
||
41 | stdClass::class => CustomType::class, |
||
42 | 'PostStatus' => PostStatusType::class, |
||
43 | ], |
||
44 | ]); |
||
45 | |||
46 | $this->types = new Types($this->entityManager, $customTypes); |
||
47 | } |
||
48 | |||
49 | public function testBlogMapping(): void |
||
50 | { |
||
51 | $validator = new SchemaValidator($this->entityManager); |
||
52 | $errors = $validator->validateMapping(); |
||
53 | |||
54 | self::assertEmpty($errors, 'doctrine annotations should be valid'); |
||
55 | } |
||
56 | |||
57 | public function testGraphQLSchemaFromDocumentationMustBeValid(): void |
||
58 | { |
||
59 | $schema = new Schema([ |
||
60 | 'query' => new ObjectType([ |
||
61 | 'name' => 'query', |
||
62 | 'fields' => [ |
||
63 | 'users' => [ |
||
64 | 'type' => Type::listOf($this->types->getOutput(User::class)), // Use automated ObjectType for output |
||
65 | 'resolve' => function ($root, $args): void { |
||
2 ignored issues
–
show
|
|||
66 | // call to repository... |
||
67 | }, |
||
68 | ], |
||
69 | 'posts' => [ |
||
70 | 'type' => Type::listOf($this->types->getOutput(Post::class)), // Use automated ObjectType for output |
||
71 | 'resolve' => function ($root, $args): void { |
||
2 ignored issues
–
show
|
|||
72 | // call to repository... |
||
73 | }, |
||
74 | ], |
||
75 | ], |
||
76 | ]), |
||
77 | 'mutation' => new ObjectType([ |
||
78 | 'name' => 'mutation', |
||
79 | 'fields' => [ |
||
80 | 'createUser' => [ |
||
81 | 'type' => Type::nonNull($this->types->getOutput(User::class)), |
||
82 | 'args' => [ |
||
83 | 'input' => Type::nonNull($this->types->getInput(User::class)), // Use automated InputObjectType for input |
||
84 | ], |
||
85 | 'resolve' => function ($root, $args): void { |
||
2 ignored issues
–
show
|
|||
86 | // create new user and flush... |
||
87 | }, |
||
88 | ], |
||
89 | 'updateUser' => [ |
||
90 | 'type' => Type::nonNull($this->types->getOutput(User::class)), |
||
91 | 'args' => [ |
||
92 | 'id' => Type::nonNull(Type::id()), // Use standard API when needed |
||
93 | 'input' => $this->types->getInput(User::class), |
||
94 | ], |
||
95 | 'resolve' => function ($root, $args): void { |
||
2 ignored issues
–
show
|
|||
96 | // update existing user and flush... |
||
97 | }, |
||
98 | ], |
||
99 | 'createPost' => [ |
||
100 | 'type' => Type::nonNull($this->types->getOutput(Post::class)), |
||
101 | 'args' => [ |
||
102 | 'input' => Type::nonNull($this->types->getInput(Post::class)), // Use automated InputObjectType for input |
||
103 | ], |
||
104 | 'resolve' => function ($root, $args): void { |
||
2 ignored issues
–
show
|
|||
105 | // create new post and flush... |
||
106 | }, |
||
107 | ], |
||
108 | 'updatePost' => [ |
||
109 | 'type' => Type::nonNull($this->types->getOutput(Post::class)), |
||
110 | 'args' => [ |
||
111 | 'id' => Type::nonNull(Type::id()), // Use standard API when needed |
||
112 | 'input' => $this->types->getInput(Post::class), |
||
113 | ], |
||
114 | 'resolve' => function ($root, $args): void { |
||
2 ignored issues
–
show
|
|||
115 | // update existing post and flush... |
||
116 | }, |
||
117 | ], |
||
118 | ], |
||
119 | ]), |
||
120 | ]); |
||
121 | |||
122 | $schema->assertValid(); |
||
123 | self::assertTrue(true, 'passed validation successfully'); |
||
124 | } |
||
125 | |||
126 | public function testCanGetUserDefinedScalarTypes(): void |
||
127 | { |
||
128 | $bool = $this->types->get(BooleanType::class); |
||
129 | $status = $this->types->get(PostStatusType::class); |
||
130 | |||
131 | self::assertInstanceOf(BooleanType::class, $bool, 'must be a instance of bool'); |
||
132 | self::assertInstanceOf(PostStatusType::class, $status, 'must be an instance of post status'); |
||
133 | |||
134 | self::assertSame($bool, $this->types->get(BooleanType::class), 'must returns the same instance of bool'); |
||
135 | self::assertSame($status, $this->types->get(PostStatusType::class), 'must returns the same instance of post status'); |
||
136 | } |
||
137 | |||
138 | public function testCanGetUserMappedTypes(): void |
||
139 | { |
||
140 | $type = $this->types->get(stdClass::class); |
||
141 | |||
142 | self::assertInstanceOf(CustomType::class, $type, 'must be a instance of CustomType'); |
||
143 | self::assertSame($type, $this->types->get('customName')); |
||
144 | } |
||
145 | |||
146 | public function testCanGetTypesWithBackslashPrefix(): void |
||
147 | { |
||
148 | $type = $this->types->getOutput(Post::class); |
||
149 | self::assertSame($type, $this->types->getOutput('\\' . Post::class)); |
||
150 | } |
||
151 | |||
152 | public function testCanGetOutputTypes(): void |
||
153 | { |
||
154 | $userType = $this->types->getOutput(User::class); |
||
155 | |||
156 | $this->assertObjectType('data/UserOutput.php', $userType); |
||
157 | self::assertSame($userType, $this->types->getOutput(User::class), 'must returns the same instance of user type'); |
||
158 | |||
159 | $postType = $this->types->getOutput(Post::class); |
||
160 | $this->assertObjectType('data/PostOutput.php', $postType); |
||
161 | self::assertSame($postType, $this->types->getOutput(Post::class), 'must returns the same instance of post type'); |
||
162 | } |
||
163 | |||
164 | public function testCanGetInputTypes(): void |
||
165 | { |
||
166 | $userType = $this->types->getInput(User::class); |
||
167 | $this->assertInputType('data/UserInput.php', $userType); |
||
168 | self::assertSame($userType, $this->types->getInput(User::class), 'must returns the same instance of user type'); |
||
169 | |||
170 | $postType = $this->types->getInput(Post::class); |
||
171 | $this->assertInputType('data/PostInput.php', $postType); |
||
172 | self::assertSame($postType, $this->types->getInput(Post::class), 'must returns the same instance of post type'); |
||
173 | } |
||
174 | |||
175 | private function assertType(string $expectedFile, Type $type, bool $assertArgs): void |
||
176 | { |
||
177 | $fields = []; |
||
178 | foreach ($type->getFields() as $field) { |
||
179 | $data = [ |
||
180 | 'name' => $field->name, |
||
181 | 'type' => $field->getType()->toString(), |
||
182 | 'description' => $field->description, |
||
183 | ]; |
||
184 | |||
185 | if ($assertArgs) { |
||
186 | $args = []; |
||
187 | foreach ($field->args as $arg) { |
||
188 | $argData = [ |
||
189 | 'name' => $arg->name, |
||
190 | 'type' => $arg->getType()->toString(), |
||
191 | 'description' => $arg->description, |
||
192 | |||
193 | ]; |
||
194 | |||
195 | if ($arg->defaultValueExists()) { |
||
196 | $argData['defaultValue'] = $arg->defaultValue; |
||
197 | } |
||
198 | |||
199 | $args[] = $argData; |
||
200 | } |
||
201 | $data['args'] = $args; |
||
202 | } elseif ($field->defaultValueExists()) { |
||
203 | $data['defaultValue'] = $field->defaultValue; |
||
204 | } |
||
205 | |||
206 | $fields[] = $data; |
||
207 | } |
||
208 | |||
209 | $actual = [ |
||
210 | 'name' => $type->name, |
||
211 | 'description' => $type->description, |
||
212 | 'fields' => $fields, |
||
213 | ]; |
||
214 | |||
215 | $expected = require $expectedFile; |
||
216 | self::assertEquals($expected, $actual, 'Should equals expectation from: ' . $expectedFile); |
||
217 | } |
||
218 | |||
219 | private function assertInputType(string $expectedFile, InputObjectType $type): void |
||
220 | { |
||
221 | $this->assertType($expectedFile, $type, false); |
||
222 | } |
||
223 | |||
224 | private function assertObjectType(string $expectedFile, ObjectType $type): void |
||
227 | } |
||
228 | |||
229 | public function testNonPublicGetterMustBeIgnored(): void |
||
230 | { |
||
231 | $actual = $this->types->getOutput(Blog\Model\Special\IgnoredGetter::class); |
||
232 | $this->assertObjectType('data/IgnoredGetter.php', $actual); |
||
233 | } |
||
234 | |||
235 | public function testCanDeclareArrayOfEntity(): void |
||
236 | { |
||
237 | $actual = $this->types->getOutput(Blog\Model\Special\ArrayOfEntity::class); |
||
238 | $this->assertObjectType('data/ArrayOfEntity.php', $actual); |
||
239 | } |
||
240 | |||
241 | public function testDefaultValuesInput(): void |
||
242 | { |
||
243 | $actual = $this->types->getInput(Blog\Model\Special\DefaultValue::class); |
||
244 | $this->assertInputType('data/DefaultValueInput.php', $actual); |
||
245 | } |
||
246 | |||
247 | public function testDefaultValuesPartialInput(): void |
||
248 | { |
||
249 | $actual = $this->types->getPartialInput(Blog\Model\Special\DefaultValue::class); |
||
250 | $this->assertInputType('data/DefaultValuePartialInput.php', $actual); |
||
251 | } |
||
252 | |||
253 | public function testDefaultValuesOutput(): void |
||
254 | { |
||
255 | $actual = $this->types->getOutput(Blog\Model\Special\DefaultValue::class); |
||
256 | $this->assertObjectType('data/DefaultValue.php', $actual); |
||
257 | } |
||
258 | |||
259 | public function testFieldWithoutTypeMustThrow(): void |
||
264 | } |
||
265 | |||
266 | public function testFieldReturningCollectionWithoutTypeMustThrow(): void |
||
267 | { |
||
268 | $this->expectExceptionMessage('The method `GraphQLTests\Doctrine\Blog\Model\Special\NoTypeCollection::getFoos()` is type hinted with a return type of `Doctrine\Common\Collections\Collection`, but the entity contained in that collection could not be automatically detected. Either fix the type hint, fix the doctrine mapping, or specify the type with `@API\Field` annotation.'); |
||
269 | $type = $this->types->getOutput(Blog\Model\Special\NoTypeCollection::class); |
||
270 | $type->getFields(); |
||
271 | } |
||
272 | |||
273 | public function testCannotGetInvalidType(): void |
||
274 | { |
||
275 | $this->expectExceptionMessage('Given class name `DateTimeImmutable` is not a Doctrine entity. Either register a custom GraphQL type for `DateTimeImmutable` when instantiating `GraphQL\Doctrine\Types`, or change the usage of that class to something else.'); |
||
276 | $this->types->getOutput(\DateTimeImmutable::class); |
||
277 | } |
||
278 | |||
279 | public function testArgumentWithoutTypeMustThrow(): void |
||
280 | { |
||
281 | $this->expectExceptionMessage('Could not find type for parameter `$bar` for method `GraphQLTests\Doctrine\Blog\Model\Special\NoTypeArgument::getFoo()`. Either type hint the parameter, or specify the type with `@API\Argument` annotation.'); |
||
282 | $type = $this->types->getOutput(Blog\Model\Special\NoTypeArgument::class); |
||
283 | $type->getFields(); |
||
284 | } |
||
285 | |||
286 | public function testInputWithoutTypeMustThrow(): void |
||
287 | { |
||
288 | $this->expectExceptionMessage('Could not find type for parameter `$bar` for method `GraphQLTests\Doctrine\Blog\Model\Special\NoTypeInput::setFoo()`. Either type hint the parameter, or specify the type with `@API\Input` annotation.'); |
||
289 | $type = $this->types->getInput(Blog\Model\Special\NoTypeInput::class); |
||
290 | $type->getFields(); |
||
291 | } |
||
292 | |||
293 | public function testFieldWithExtraArgumentMustThrow(): void |
||
298 | } |
||
299 | |||
300 | public function testFieldWithArrayArgumentMustThrow(): void |
||
301 | { |
||
302 | $this->expectExceptionMessage('The parameter `$arg1` on method `GraphQLTests\Doctrine\Blog\Model\Special\ArrayArgument::getWithParams()` is type hinted as `array` and is not overridden via `@API\Argument` annotation. Either change the type hint or specify the type with `@API\Argument` annotation.'); |
||
303 | $type = $this->types->getOutput(Blog\Model\Special\ArrayArgument::class); |
||
304 | $type->getFields(); |
||
305 | } |
||
306 | |||
307 | public function testFieldWithObjectTypeArgumentMustThrow(): void |
||
308 | { |
||
309 | $this->expectExceptionMessage('Type for parameter `$user` for method `GraphQLTests\Doctrine\Blog\Model\Special\ObjectTypeArgument::getWithParams()` must be an instance of `GraphQL\Type\Definition\InputType`, but was `GraphQL\Type\Definition\ObjectType`. Use `@API\Argument` annotation to specify a custom InputType.'); |
||
310 | $type = $this->types->getOutput(Blog\Model\Special\ObjectTypeArgument::class); |
||
311 | $type->getFields(); |
||
312 | } |
||
313 | |||
314 | public function testCanGetMappedTypesEitherByMappedPhpClassOrDirectTypeClass(): void |
||
315 | { |
||
316 | $viaPhp = $this->types->get(DateTime::class); |
||
317 | $viaType = $this->types->get(DateTimeType::class); |
||
318 | self::assertSame($viaPhp, $viaType); |
||
319 | } |
||
320 | |||
321 | public function testDoctrineWithoutAnnotationDriverMustThrow(): void |
||
333 | } |
||
334 | |||
335 | public function testNonRegisteredCustomTypeMustThrow(): void |
||
336 | { |
||
337 | $this->expectExceptionMessage('No type registered with key `foo`. Either correct the usage, or register it in your custom types container when instantiating `GraphQL\Doctrine\Types`'); |
||
338 | $this->types->get('foo'); |
||
339 | } |
||
340 | |||
341 | public function testHas(): void |
||
348 | } |
||
349 | } |
||
350 |
This check looks for parameters that have been defined for a function or method, but which are not used in the method body.