Total Complexity | 28 |
Total Lines | 284 |
Duplicated Lines | 0 % |
Changes | 0 |
1 | <?php |
||
22 | class TypesTest extends \PHPUnit\Framework\TestCase |
||
23 | { |
||
24 | use EntityManagerTrait; |
||
25 | |||
26 | /** |
||
27 | * @var Types |
||
28 | */ |
||
29 | private $types; |
||
30 | |||
31 | public function setUp(): void |
||
32 | { |
||
33 | $this->setUpEntityManager(); |
||
34 | |||
35 | $mapping = [ |
||
36 | DateTime::class => DateTimeType::class, |
||
37 | stdClass::class => CustomType::class, |
||
38 | ]; |
||
39 | $this->types = new Types($this->entityManager, $mapping); |
||
40 | } |
||
41 | |||
42 | public function testBlogMapping(): void |
||
43 | { |
||
44 | $validator = new SchemaValidator($this->entityManager); |
||
45 | $errors = $validator->validateMapping(); |
||
46 | |||
47 | self::assertEmpty($errors, 'doctrine annotations should be valid'); |
||
48 | } |
||
49 | |||
50 | public function testGraphQLSchemaFromDocumentationMustBeValid(): void |
||
51 | { |
||
52 | $schema = new Schema([ |
||
53 | 'query' => new ObjectType([ |
||
54 | 'name' => 'query', |
||
55 | 'fields' => [ |
||
56 | 'users' => [ |
||
57 | 'type' => Type::listOf($this->types->get(User::class)), // Use automated ObjectType for output |
||
58 | 'resolve' => function ($root, $args): void { |
||
2 ignored issues
–
show
|
|||
59 | // call to repository... |
||
60 | }, |
||
61 | ], |
||
62 | 'posts' => [ |
||
63 | 'type' => Type::listOf($this->types->get(Post::class)), // Use automated ObjectType for output |
||
64 | 'resolve' => function ($root, $args): void { |
||
2 ignored issues
–
show
|
|||
65 | // call to repository... |
||
66 | }, |
||
67 | ], |
||
68 | ], |
||
69 | ]), |
||
70 | 'mutation' => new ObjectType([ |
||
71 | 'name' => 'mutation', |
||
72 | 'fields' => [ |
||
73 | 'createUser' => [ |
||
74 | 'type' => Type::nonNull($this->types->get(User::class)), |
||
75 | 'args' => [ |
||
76 | 'input' => Type::nonNull($this->types->getInput(User::class)), // Use automated InputObjectType for input |
||
77 | ], |
||
78 | 'resolve' => function ($root, $args): void { |
||
2 ignored issues
–
show
|
|||
79 | // create new user and flush... |
||
80 | }, |
||
81 | ], |
||
82 | 'updateUser' => [ |
||
83 | 'type' => Type::nonNull($this->types->get(User::class)), |
||
84 | 'args' => [ |
||
85 | 'id' => Type::nonNull(Type::id()), // Use standard API when needed |
||
86 | 'input' => $this->types->getInput(User::class), |
||
87 | ], |
||
88 | 'resolve' => function ($root, $args): void { |
||
2 ignored issues
–
show
|
|||
89 | // update existing user and flush... |
||
90 | }, |
||
91 | ], |
||
92 | 'createPost' => [ |
||
93 | 'type' => Type::nonNull($this->types->get(Post::class)), |
||
94 | 'args' => [ |
||
95 | 'input' => Type::nonNull($this->types->getInput(Post::class)), // Use automated InputObjectType for input |
||
96 | ], |
||
97 | 'resolve' => function ($root, $args): void { |
||
2 ignored issues
–
show
|
|||
98 | // create new post and flush... |
||
99 | }, |
||
100 | ], |
||
101 | 'updatePost' => [ |
||
102 | 'type' => Type::nonNull($this->types->get(Post::class)), |
||
103 | 'args' => [ |
||
104 | 'id' => Type::nonNull(Type::id()), // Use standard API when needed |
||
105 | 'input' => $this->types->getInput(Post::class), |
||
106 | ], |
||
107 | 'resolve' => function ($root, $args): void { |
||
2 ignored issues
–
show
|
|||
108 | // update existing post and flush... |
||
109 | }, |
||
110 | ], |
||
111 | ], |
||
112 | ]), |
||
113 | ]); |
||
114 | |||
115 | $schema->assertValid(); |
||
116 | self::assertTrue(true, 'passed validation successfully'); |
||
117 | } |
||
118 | |||
119 | public function testCanGetUserDefinedScalarTypes(): void |
||
120 | { |
||
121 | $bool = $this->types->get(BooleanType::class); |
||
122 | $status = $this->types->get(PostStatusType::class); |
||
123 | |||
124 | self::assertInstanceOf(BooleanType::class, $bool, 'must be a instance of bool'); |
||
125 | self::assertInstanceOf(PostStatusType::class, $status, 'must be an instance of post status'); |
||
126 | |||
127 | self::assertSame($bool, $this->types->get(BooleanType::class), 'must returns the same instance of bool'); |
||
128 | self::assertSame($status, $this->types->get(PostStatusType::class), 'must returns the same instance of post status'); |
||
129 | } |
||
130 | |||
131 | public function testCanGetUserMappedTypes(): void |
||
132 | { |
||
133 | $type = $this->types->get(stdClass::class); |
||
134 | |||
135 | self::assertInstanceOf(CustomType::class, $type, 'must be a instance of CustomType'); |
||
136 | self::assertSame($type, $this->types->get('customName')); |
||
137 | } |
||
138 | |||
139 | public function testCanGetTypesWithBackslashPrefix(): void |
||
140 | { |
||
141 | $type = $this->types->get(stdClass::class); |
||
142 | self::assertSame($type, $this->types->get('\stdClass')); |
||
143 | } |
||
144 | |||
145 | public function testCanGetOutputTypes(): void |
||
146 | { |
||
147 | $userType = $this->types->get(User::class); |
||
148 | |||
149 | $this->assertObjectType('data/UserOutput.php', $userType); |
||
150 | self::assertSame($userType, $this->types->get(User::class), 'must returns the same instance of user type'); |
||
151 | |||
152 | $postType = $this->types->get(Post::class); |
||
153 | $this->assertObjectType('data/PostOutput.php', $postType); |
||
154 | self::assertSame($postType, $this->types->get(Post::class), 'must returns the same instance of post type'); |
||
155 | } |
||
156 | |||
157 | public function testCanGetInputTypes(): void |
||
158 | { |
||
159 | $userType = $this->types->getInput(User::class); |
||
160 | $this->assertInputType('data/UserInput.php', $userType); |
||
161 | self::assertSame($userType, $this->types->getInput(User::class), 'must returns the same instance of user type'); |
||
162 | |||
163 | $postType = $this->types->getInput(Post::class); |
||
164 | $this->assertInputType('data/PostInput.php', $postType); |
||
165 | self::assertSame($postType, $this->types->getInput(Post::class), 'must returns the same instance of post type'); |
||
166 | } |
||
167 | |||
168 | private function assertType(string $expectedFile, Type $type, bool $assertArgs): void |
||
169 | { |
||
170 | $fields = []; |
||
171 | foreach ($type->getFields() as $field) { |
||
172 | $data = [ |
||
173 | 'name' => $field->name, |
||
174 | 'type' => $field->getType()->toString(), |
||
175 | 'description' => $field->description, |
||
176 | ]; |
||
177 | |||
178 | if ($assertArgs) { |
||
179 | $args = []; |
||
180 | foreach ($field->args as $arg) { |
||
181 | $args[] = [ |
||
182 | 'name' => $arg->name, |
||
183 | 'type' => $arg->getType()->toString(), |
||
184 | 'description' => $arg->description, |
||
185 | 'defaultValue' => $arg->defaultValue, |
||
186 | ]; |
||
187 | } |
||
188 | $data['args'] = $args; |
||
189 | } else { |
||
190 | $data['defaultValue'] = $field->defaultValue; |
||
191 | } |
||
192 | |||
193 | $fields[] = $data; |
||
194 | } |
||
195 | |||
196 | $actual = [ |
||
197 | 'name' => $type->name, |
||
198 | 'description' => $type->description, |
||
199 | 'fields' => $fields, |
||
200 | ]; |
||
201 | |||
202 | $expected = require $expectedFile; |
||
203 | self::assertEquals($expected, $actual, 'Should equals expectation from: ' . $expectedFile); |
||
204 | } |
||
205 | |||
206 | private function assertInputType(string $expectedFile, InputObjectType $type): void |
||
207 | { |
||
208 | $this->assertType($expectedFile, $type, false); |
||
209 | } |
||
210 | |||
211 | private function assertObjectType(string $expectedFile, ObjectType $type): void |
||
214 | } |
||
215 | |||
216 | public function testNonPublicGetterMustBeIgnored(): void |
||
217 | { |
||
218 | $actual = $this->types->get(Blog\Model\Special\IgnoredGetter::class); |
||
219 | $this->assertObjectType('data/IgnoredGetter.php', $actual); |
||
220 | } |
||
221 | |||
222 | public function testCanDeclareArrayOfEntity(): void |
||
223 | { |
||
224 | $actual = $this->types->get(Blog\Model\Special\ArrayOfEntity::class); |
||
225 | $this->assertObjectType('data/ArrayOfEntity.php', $actual); |
||
226 | } |
||
227 | |||
228 | public function testDefaultValuesInput(): void |
||
229 | { |
||
230 | $actual = $this->types->getInput(Blog\Model\Special\DefaultValue::class); |
||
231 | $this->assertInputType('data/DefaultValueInput.php', $actual); |
||
232 | } |
||
233 | |||
234 | public function testDefaultValuesPartialInput(): void |
||
235 | { |
||
236 | $actual = $this->types->getPartialInput(Blog\Model\Special\DefaultValue::class); |
||
237 | $this->assertInputType('data/DefaultValuePartialInput.php', $actual); |
||
238 | } |
||
239 | |||
240 | public function testDefaultValuesOutput(): void |
||
241 | { |
||
242 | $actual = $this->types->get(Blog\Model\Special\DefaultValue::class); |
||
243 | $this->assertObjectType('data/DefaultValue.php', $actual); |
||
244 | } |
||
245 | |||
246 | public function testFieldWithoutTypeMustThrow(): void |
||
251 | } |
||
252 | |||
253 | public function testFieldReturningCollectionWithoutTypeMustThrow(): void |
||
254 | { |
||
255 | $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.'); |
||
256 | $type = $this->types->get(Blog\Model\Special\NoTypeCollection::class); |
||
257 | $type->getFields(); |
||
258 | } |
||
259 | |||
260 | public function testCannotGetInvalidType(): void |
||
261 | { |
||
262 | $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.'); |
||
263 | $this->types->get(\DateTimeImmutable::class); |
||
264 | } |
||
265 | |||
266 | public function testArgumentWithoutTypeMustThrow(): void |
||
267 | { |
||
268 | $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.'); |
||
269 | $type = $this->types->get(Blog\Model\Special\NoTypeArgument::class); |
||
270 | $type->getFields(); |
||
271 | } |
||
272 | |||
273 | public function testInputWithoutTypeMustThrow(): void |
||
274 | { |
||
275 | $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.'); |
||
276 | $type = $this->types->getInput(Blog\Model\Special\NoTypeInput::class); |
||
277 | $type->getFields(); |
||
278 | } |
||
279 | |||
280 | public function testFieldWithExtraArgumentMustThrow(): void |
||
285 | } |
||
286 | |||
287 | public function testFieldWithArrayArgumentMustThrow(): void |
||
288 | { |
||
289 | $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.'); |
||
290 | $type = $this->types->get(Blog\Model\Special\ArrayArgument::class); |
||
291 | $type->getFields(); |
||
292 | } |
||
293 | |||
294 | public function testFieldWithObjectTypeArgumentMustThrow(): void |
||
299 | } |
||
300 | |||
301 | public function testCanGetMappedTypesEitherByMappedPhpClassOrDirectTypeClass(): void |
||
306 | } |
||
307 | } |
||
308 |
This check looks for parameters that have been defined for a function or method, but which are not used in the method body.