1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/******************************************************************************* |
4
|
|
|
* This file is part of the GraphQL Bundle package. |
5
|
|
|
* |
6
|
|
|
* (c) YnloUltratech <[email protected]> |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
******************************************************************************/ |
11
|
|
|
|
12
|
|
|
namespace Ynlo\GraphQLBundle\Test; |
13
|
|
|
|
14
|
|
|
use Doctrine\Common\DataFixtures\ReferenceRepository; |
15
|
|
|
use PHPUnit\Util\Blacklist; |
16
|
|
|
use Symfony\Bundle\FrameworkBundle\Client; |
17
|
|
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; |
18
|
|
|
use Symfony\Component\HttpFoundation\Request; |
19
|
|
|
use Symfony\Component\HttpFoundation\Response; |
20
|
|
|
use Ynlo\GraphQLBundle\Definition\Registry\DefinitionRegistry; |
21
|
|
|
use Ynlo\GraphQLBundle\Model\ID; |
22
|
|
|
use Ynlo\GraphQLBundle\Model\NodeInterface; |
23
|
|
|
use Ynlo\GraphQLBundle\Test\Assert\DoctrineAssertTrait; |
24
|
|
|
use Ynlo\GraphQLBundle\Test\Assert\JsonAssertTrait; |
25
|
|
|
use Ynlo\GraphQLBundle\Test\Assert\ResponseAssertTrait; |
26
|
|
|
use Ynlo\GraphQLBundle\Test\FixtureLoader\FixtureLoader; |
27
|
|
|
use Ynlo\GraphQLBundle\Test\Helper\DoctrineHelperTrait; |
28
|
|
|
use Ynlo\GraphQLBundle\Test\Helper\JsonHelperTrait; |
29
|
|
|
use Ynlo\GraphQLBundle\Test\Helper\ResponseHelperTrait; |
30
|
|
|
use Ynlo\GraphQLBundle\Util\IDEncoder; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* @deprecated in favor of Behat tests |
34
|
|
|
*/ |
35
|
|
|
class ApiTestCase extends WebTestCase |
36
|
|
|
{ |
37
|
|
|
// helpers |
38
|
|
|
use DoctrineHelperTrait; |
|
|
|
|
39
|
|
|
use JsonHelperTrait; |
|
|
|
|
40
|
|
|
use ResponseHelperTrait; |
|
|
|
|
41
|
|
|
|
42
|
|
|
// asserts |
43
|
|
|
use DoctrineAssertTrait; |
|
|
|
|
44
|
|
|
use JsonAssertTrait; |
|
|
|
|
45
|
|
|
use ResponseAssertTrait; |
|
|
|
|
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* @var ReferenceRepository |
49
|
|
|
*/ |
50
|
|
|
protected static $referenceRepository; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @var Client |
54
|
|
|
*/ |
55
|
|
|
protected static $client; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* Whether to insulate each request or not. |
59
|
|
|
* The request ran into a separate process to avoid |
60
|
|
|
* any conflict (cache, container, doctrine etc..) with previous requests. |
61
|
|
|
* |
62
|
|
|
* NOTE: should be disabled for debugging |
63
|
|
|
* |
64
|
|
|
* @var bool |
65
|
|
|
*/ |
66
|
|
|
protected static $insulateRequests = false; |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* Endpoint where the API is available, e.g. /api |
70
|
|
|
* |
71
|
|
|
* @var string |
72
|
|
|
*/ |
73
|
|
|
protected static $endpoint = ''; |
74
|
|
|
|
75
|
|
|
private static $lastQuery; |
76
|
|
|
|
77
|
|
|
private static $lastQueryExecutionTime = 0; |
78
|
|
|
|
79
|
|
|
public function __construct(string $name = null, array $data = [], string $dataName = '') |
80
|
|
|
{ |
81
|
|
|
parent::__construct($name, $data, $dataName); |
82
|
|
|
|
83
|
|
|
Blacklist::$blacklistedClassNames['Ynlo\GraphQLBundle\Test\ApiTestCase'] = 1; |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
final public static function setUpBeforeClass() |
87
|
|
|
{ |
88
|
|
|
static::$client = null; |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
final public function setUp() |
92
|
|
|
{ |
93
|
|
|
parent::setUp(); |
94
|
|
|
|
95
|
|
|
self::$lastQuery = null; |
96
|
|
|
self::$lastQueryExecutionTime = 0; |
97
|
|
|
|
98
|
|
|
static::loadFixtures(); |
99
|
|
|
$this->before(); |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* This method is called before a test is executed. |
104
|
|
|
*/ |
105
|
|
|
public function before() |
106
|
|
|
{ |
107
|
|
|
|
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
/** |
111
|
|
|
* {@inheritdoc} |
112
|
|
|
*/ |
113
|
|
|
final protected function tearDown() |
114
|
|
|
{ |
115
|
|
|
parent::tearDown(); |
116
|
|
|
static::$client = null; |
117
|
|
|
$this->after(); |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
/** |
121
|
|
|
* This method is called after a test is executed. |
122
|
|
|
*/ |
123
|
|
|
public function after() |
124
|
|
|
{ |
125
|
|
|
|
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
protected static function createClient(array $options = [], array $server = []) |
129
|
|
|
{ |
130
|
|
|
return static::$client = parent::createClient($options, $server); |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
protected static function getClient(): Client |
134
|
|
|
{ |
135
|
|
|
return static::$client ?? static::createClient(); |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
protected static function loadFixtures($classNames = []) |
139
|
|
|
{ |
140
|
|
|
/** @var Client $client */ |
141
|
|
|
$client = static::getClient(); |
142
|
|
|
$container = $client->getContainer(); |
143
|
|
|
if ($container) { |
144
|
|
|
$fixtureLoader = new FixtureLoader($container, $container->get('doctrine')); |
|
|
|
|
145
|
|
|
static::$referenceRepository = $fixtureLoader->loadFixtures($classNames); |
146
|
|
|
} |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
protected static function getFixtureReference(string $name) |
150
|
|
|
{ |
151
|
|
|
return self::$referenceRepository->getReference($name); |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
/** |
155
|
|
|
* @param string $query query or mutation in GraphQL format |
156
|
|
|
* @param array $variables array of variables |
157
|
|
|
* @param bool|null $insulate Whether to insulate the requests or not. Leave null to use default value. |
158
|
|
|
* The request ran into a separate process to avoid |
159
|
|
|
* any conflict (cache, container, doctrine etc..) with previous requests. |
160
|
|
|
* NOTE: should be disabled for debugging |
161
|
|
|
* |
162
|
|
|
* @return Response |
163
|
|
|
*/ |
164
|
|
|
protected static function send($query, array $variables = [], $insulate = null): Response |
165
|
|
|
{ |
166
|
|
|
self::$lastQuery = ['query' => $query, 'variables' => $variables]; |
167
|
|
|
|
168
|
|
|
if (null === $insulate) { |
169
|
|
|
$insulate = static::$insulateRequests; |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
$client = static::getClient(); |
173
|
|
|
$client->insulate($insulate); |
174
|
|
|
|
175
|
|
|
$client->request(Request::METHOD_POST, self::$endpoint, [], [], [], json_encode(self::$lastQuery)); |
176
|
|
|
|
177
|
|
|
return $client->getResponse(); |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
/** |
181
|
|
|
* Use this method to get the global ID of a existent fixture |
182
|
|
|
* |
183
|
|
|
* getFixtureGlobalId('user1') => VXNlcjox |
184
|
|
|
*/ |
185
|
|
|
protected static function getFixtureGlobalId(string $name): string |
186
|
|
|
{ |
187
|
|
|
$fixture = static::getFixtureReference($name); |
188
|
|
|
if ($fixture instanceof NodeInterface) { |
189
|
|
|
return static::encodeID($fixture); |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
throw new \RuntimeException(sprintf('The fixture must implements %s', NodeInterface::class)); |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
/** |
196
|
|
|
* Encode given id or node interface to global ID |
197
|
|
|
* |
198
|
|
|
* encodeID($user) => VXNlcjox |
199
|
|
|
* encodeID(1, 'User') => VXNlcjox |
200
|
|
|
* |
201
|
|
|
* @param string|NodeInterface $node id of the node or instance |
202
|
|
|
* @param string $nodeType required in case the first argument is scalar |
203
|
|
|
* |
204
|
|
|
* @return string |
205
|
|
|
*/ |
206
|
|
|
protected static function encodeID($node, $nodeType = null) |
207
|
|
|
{ |
208
|
|
|
if (!is_object($node) && !$nodeType) { |
209
|
|
|
throw new \RuntimeException('Node type is required when use scalar ID as node'); |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
if (!$node instanceof NodeInterface) { |
213
|
|
|
$nodeClass = static::getClient() |
214
|
|
|
->getContainer() |
215
|
|
|
->get(DefinitionRegistry::class) |
216
|
|
|
->getEndpoint() |
217
|
|
|
->getClassForType($nodeType); |
218
|
|
|
|
219
|
|
|
$node = self::getDoctrine()->getEntityManager()->getReference($nodeClass, $node); |
|
|
|
|
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
return IDEncoder::encode($node); |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
/** |
226
|
|
|
* Decode globalId to get type and real database id |
227
|
|
|
* |
228
|
|
|
* @deprecated since v1.1 use IDEncoder utility instead |
229
|
|
|
*/ |
230
|
|
|
protected static function decodeID(string $globalID): ID |
231
|
|
|
{ |
232
|
|
|
return ID::createFromString($globalID); |
|
|
|
|
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
/** |
236
|
|
|
* Print helpful debug information for latest executed query |
237
|
|
|
*/ |
238
|
|
|
protected static function debugLastQuery() |
239
|
|
|
{ |
240
|
|
|
if (self::$lastQuery) { |
241
|
|
|
$query = self::$lastQuery['query'] ?? null; |
242
|
|
|
|
243
|
|
|
$type = 'QUERY'; |
244
|
|
|
if (preg_match('/^\s*mutation/', $query)) { |
245
|
|
|
$type = 'MUTATION'; |
246
|
|
|
} |
247
|
|
|
|
248
|
|
|
$variables = self::$lastQuery['variables'] ?? null; |
249
|
|
|
|
250
|
|
|
print_r("\033[43m\n\n----------------------- $type ---------------------\n\n\033[0m"); |
251
|
|
|
print_r($query ?? null); |
252
|
|
|
print_r("\n\n"); |
253
|
|
|
print_r("\033[46m------------------- VARIABLES-----------------------\n\n\033[0m"); |
254
|
|
|
print_r(json_encode($variables, JSON_PRETTY_PRINT)); |
255
|
|
|
print_r("\n\n"); |
256
|
|
|
|
257
|
|
|
/** @var Response $response */ |
258
|
|
|
$response = static::getClient()->getResponse(); |
259
|
|
|
$bg = $response->getStatusCode() >= 400 ? 41: 42; |
260
|
|
|
print_r("\033[{$bg}m-------------------- RESPONSE ----------------------\n\n\033[0m"); |
261
|
|
|
print_r(sprintf("STATUS: [%s] %s \n", $response->getStatusCode(), Response::$statusTexts[$response->getStatusCode()] ?? 'Unknown Status')); |
262
|
|
|
print_r(sprintf("TIME: %s ms \n\n", self::$lastQueryExecutionTime)); |
263
|
|
|
|
264
|
|
|
$content = $response->getContent(); |
265
|
|
|
$json = @json_decode($content, true); |
266
|
|
|
if ($json) { |
267
|
|
|
print_r(json_encode($json, JSON_PRETTY_PRINT)); |
268
|
|
|
} else { |
269
|
|
|
print_r($content); |
270
|
|
|
} |
271
|
|
|
print_r("\n\n"); |
272
|
|
|
print_r("-----------------------------------------------------\n\n"); |
273
|
|
|
} else { |
274
|
|
|
throw new \RuntimeException('Does not exist any executed query on current test, try use this method after "send" the query.'); |
275
|
|
|
} |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
protected function runTest() |
279
|
|
|
{ |
280
|
|
|
try { |
281
|
|
|
parent::runTest(); |
282
|
|
|
} catch (\Exception $exception) { |
283
|
|
|
if (self::$lastQuery) { |
284
|
|
|
self::debugLastQuery(); |
285
|
|
|
} |
286
|
|
|
|
287
|
|
|
throw $exception; |
288
|
|
|
} |
289
|
|
|
} |
290
|
|
|
} |
291
|
|
|
|
292
|
|
|
|
This trait has been deprecated. The supplier of the trait has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the trait will be removed and what other trait to use instead.