1 | <?php |
||||||
2 | |||||||
3 | declare(strict_types=1); |
||||||
4 | |||||||
5 | /* |
||||||
6 | * This file is part of the Liip/FunctionalTestBundle |
||||||
7 | * |
||||||
8 | * (c) Lukas Kahwe Smith <[email protected]> |
||||||
9 | * |
||||||
10 | * This source file is subject to the MIT license that is bundled |
||||||
11 | * with this source code in the file LICENSE. |
||||||
12 | */ |
||||||
13 | |||||||
14 | namespace Liip\FunctionalTestBundle\Test; |
||||||
15 | |||||||
16 | use Liip\FunctionalTestBundle\Utils\HttpAssertions; |
||||||
17 | use PHPUnit\Framework\MockObject\MockBuilder; |
||||||
18 | use Symfony\Bundle\FrameworkBundle\Client; |
||||||
19 | use Symfony\Bundle\FrameworkBundle\Console\Application; |
||||||
20 | use Symfony\Bundle\FrameworkBundle\KernelBrowser; |
||||||
21 | use Symfony\Bundle\FrameworkBundle\Test\WebTestCase as BaseWebTestCase; |
||||||
22 | use Symfony\Component\BrowserKit\Cookie; |
||||||
23 | use Symfony\Component\Console\Tester\CommandTester; |
||||||
24 | use Symfony\Component\DependencyInjection\ContainerInterface; |
||||||
25 | use Symfony\Component\DependencyInjection\ResettableContainerInterface; |
||||||
0 ignored issues
–
show
|
|||||||
26 | use Symfony\Component\DomCrawler\Crawler; |
||||||
27 | use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException; |
||||||
28 | use Symfony\Component\HttpFoundation\Request; |
||||||
29 | use Symfony\Component\HttpFoundation\RequestStack; |
||||||
30 | use Symfony\Component\HttpFoundation\Response; |
||||||
31 | use Symfony\Component\HttpFoundation\Session\Session; |
||||||
32 | use Symfony\Component\HttpFoundation\Session\SessionInterface; |
||||||
33 | use Symfony\Component\HttpKernel\KernelInterface; |
||||||
34 | use Symfony\Component\Routing\Generator\UrlGeneratorInterface; |
||||||
35 | use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; |
||||||
36 | use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; |
||||||
37 | use Symfony\Component\Security\Core\User\UserInterface; |
||||||
38 | |||||||
39 | if (!class_exists(Client::class)) { |
||||||
40 | class_alias(KernelBrowser::class, Client::class); |
||||||
41 | } |
||||||
42 | |||||||
43 | /** |
||||||
44 | * @author Lea Haensenberger |
||||||
45 | * @author Lukas Kahwe Smith <[email protected]> |
||||||
46 | * @author Benjamin Eberlei <[email protected]> |
||||||
47 | * |
||||||
48 | * @method ContainerInterface getContainer() |
||||||
49 | * |
||||||
50 | * @property string $environment; |
||||||
51 | */ |
||||||
52 | abstract class WebTestCase extends BaseWebTestCase |
||||||
53 | { |
||||||
54 | protected static $env = 'test'; |
||||||
55 | |||||||
56 | protected $containers; |
||||||
57 | |||||||
58 | // 5 * 1024 * 1024 KB |
||||||
59 | protected $maxMemory = 5242880; |
||||||
60 | |||||||
61 | // RUN COMMAND |
||||||
62 | protected $verbosityLevel; |
||||||
63 | |||||||
64 | protected $decorated; |
||||||
65 | |||||||
66 | /** |
||||||
67 | * @var array|null |
||||||
68 | */ |
||||||
69 | private $inputs = null; |
||||||
70 | |||||||
71 | /** |
||||||
72 | * @var array |
||||||
73 | */ |
||||||
74 | private $firewallLogins = []; |
||||||
75 | |||||||
76 | /** |
||||||
77 | * Creates a mock object of a service identified by its id. |
||||||
78 | */ |
||||||
79 | protected function getServiceMockBuilder(string $id): MockBuilder |
||||||
80 | { |
||||||
81 | $service = $this->getContainer()->get($id); |
||||||
82 | $class = \get_class($service); |
||||||
0 ignored issues
–
show
It seems like
$service can also be of type null ; however, parameter $object of get_class() does only seem to accept object , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
83 | |||||||
84 | return $this->getMockBuilder($class)->disableOriginalConstructor(); |
||||||
85 | } |
||||||
86 | |||||||
87 | /** |
||||||
88 | * Builds up the environment to run the given command. |
||||||
89 | */ |
||||||
90 | 12 | protected function runCommand(string $name, array $params = [], bool $reuseKernel = false): CommandTester |
|||||
91 | { |
||||||
92 | 12 | if (!$reuseKernel) { |
|||||
93 | 12 | if (null !== static::$kernel) { |
|||||
94 | 1 | static::ensureKernelShutdown(); |
|||||
95 | } |
||||||
96 | |||||||
97 | 12 | $kernel = static::bootKernel(['environment' => static::$env]); |
|||||
98 | 12 | $kernel->boot(); |
|||||
99 | } else { |
||||||
100 | 1 | $kernel = $this->getContainer()->get('kernel'); |
|||||
101 | } |
||||||
102 | |||||||
103 | 12 | $application = new Application($kernel); |
|||||
0 ignored issues
–
show
It seems like
$kernel can also be of type null ; however, parameter $kernel of Symfony\Bundle\Framework...lication::__construct() does only seem to accept Symfony\Component\HttpKernel\KernelInterface , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
104 | |||||||
105 | $options = [ |
||||||
106 | 12 | 'interactive' => false, |
|||||
107 | 12 | 'decorated' => $this->getDecorated(), |
|||||
108 | 12 | 'verbosity' => $this->getVerbosityLevel(), |
|||||
109 | ]; |
||||||
110 | |||||||
111 | 11 | $command = $application->find($name); |
|||||
112 | 11 | $commandTester = new CommandTester($command); |
|||||
113 | |||||||
114 | 11 | if (null !== $inputs = $this->getInputs()) { |
|||||
115 | 1 | $commandTester->setInputs($inputs); |
|||||
116 | 1 | $options['interactive'] = true; |
|||||
117 | 1 | $this->inputs = null; |
|||||
118 | } |
||||||
119 | |||||||
120 | 11 | $commandTester->execute( |
|||||
121 | 11 | array_merge(['command' => $command->getName()], $params), |
|||||
122 | 11 | $options |
|||||
123 | ); |
||||||
124 | |||||||
125 | 11 | return $commandTester; |
|||||
126 | } |
||||||
127 | |||||||
128 | /** |
||||||
129 | * Retrieves the output verbosity level. |
||||||
130 | * |
||||||
131 | * @see \Symfony\Component\Console\Output\OutputInterface for available levels |
||||||
132 | * |
||||||
133 | * @throws \OutOfBoundsException If the set value isn't accepted |
||||||
134 | */ |
||||||
135 | 12 | protected function getVerbosityLevel(): int |
|||||
136 | { |
||||||
137 | // If `null`, is not yet set |
||||||
138 | 12 | if (null === $this->verbosityLevel) { |
|||||
139 | // Set the global verbosity level that is set as NORMAL by the TreeBuilder in Configuration |
||||||
140 | 6 | $level = strtoupper($this->getContainer()->getParameter('liip_functional_test.command_verbosity')); |
|||||
141 | 6 | $verbosity = '\Symfony\Component\Console\Output\StreamOutput::VERBOSITY_'.$level; |
|||||
142 | |||||||
143 | 6 | $this->verbosityLevel = \constant($verbosity); |
|||||
144 | } |
||||||
145 | |||||||
146 | // If string, it is set by the developer, so check that the value is an accepted one |
||||||
147 | 12 | if (\is_string($this->verbosityLevel)) { |
|||||
148 | 6 | $level = strtoupper($this->verbosityLevel); |
|||||
149 | 6 | $verbosity = '\Symfony\Component\Console\Output\StreamOutput::VERBOSITY_'.$level; |
|||||
150 | |||||||
151 | 6 | if (!\defined($verbosity)) { |
|||||
152 | 1 | throw new \OutOfBoundsException(sprintf('The set value "%s" for verbosityLevel is not valid. Accepted are: "quiet", "normal", "verbose", "very_verbose" and "debug".', $level)); |
|||||
153 | } |
||||||
154 | |||||||
155 | 5 | $this->verbosityLevel = \constant($verbosity); |
|||||
156 | } |
||||||
157 | |||||||
158 | 11 | return $this->verbosityLevel; |
|||||
159 | } |
||||||
160 | |||||||
161 | 6 | public function setVerbosityLevel($level): void |
|||||
162 | { |
||||||
163 | 6 | $this->verbosityLevel = $level; |
|||||
164 | 6 | } |
|||||
165 | |||||||
166 | 1 | protected function setInputs(array $inputs): void |
|||||
167 | { |
||||||
168 | 1 | $this->inputs = $inputs; |
|||||
169 | 1 | } |
|||||
170 | |||||||
171 | 11 | protected function getInputs(): ?array |
|||||
172 | { |
||||||
173 | 11 | return $this->inputs; |
|||||
174 | } |
||||||
175 | |||||||
176 | /** |
||||||
177 | * Set verbosity for Symfony 3.4+. |
||||||
178 | * |
||||||
179 | * @see https://github.com/symfony/symfony/pull/24425 |
||||||
180 | * |
||||||
181 | * @param $level |
||||||
182 | */ |
||||||
183 | private function setVerbosityLevelEnv($level): void |
||||||
184 | { |
||||||
185 | putenv('SHELL_VERBOSITY='.$level); |
||||||
186 | } |
||||||
187 | |||||||
188 | /** |
||||||
189 | * Retrieves the flag indicating if the output should be decorated or not. |
||||||
190 | */ |
||||||
191 | 12 | protected function getDecorated(): bool |
|||||
192 | { |
||||||
193 | 12 | if (null === $this->decorated) { |
|||||
194 | // Set the global decoration flag that is set to `true` by the TreeBuilder in Configuration |
||||||
195 | 6 | $this->decorated = $this->getContainer()->getParameter('liip_functional_test.command_decoration'); |
|||||
196 | } |
||||||
197 | |||||||
198 | // Check the local decorated flag |
||||||
199 | 12 | if (false === \is_bool($this->decorated)) { |
|||||
200 | throw new \OutOfBoundsException(sprintf('`WebTestCase::decorated` has to be `bool`. "%s" given.', \gettype($this->decorated))); |
||||||
201 | } |
||||||
202 | |||||||
203 | 12 | return $this->decorated; |
|||||
204 | } |
||||||
205 | |||||||
206 | 6 | public function isDecorated(bool $decorated): void |
|||||
207 | { |
||||||
208 | 6 | $this->decorated = $decorated; |
|||||
209 | 6 | } |
|||||
210 | |||||||
211 | /** |
||||||
212 | * Get an instance of the dependency injection container. |
||||||
213 | * (this creates a kernel *without* parameters). |
||||||
214 | */ |
||||||
215 | 10 | private function getDependencyInjectionContainer(): ContainerInterface |
|||||
216 | { |
||||||
217 | 10 | $cacheKey = static::$env; |
|||||
218 | 10 | if (empty($this->containers[$cacheKey])) { |
|||||
219 | 10 | $kernel = static::createKernel([ |
|||||
220 | 10 | 'environment' => static::$env, |
|||||
221 | ]); |
||||||
222 | 10 | $kernel->boot(); |
|||||
223 | |||||||
224 | 10 | $container = $kernel->getContainer(); |
|||||
225 | 10 | if ($container->has('test.service_container')) { |
|||||
226 | 10 | $this->containers[$cacheKey] = $container->get('test.service_container'); |
|||||
227 | } else { |
||||||
228 | $this->containers[$cacheKey] = $container; |
||||||
229 | } |
||||||
230 | } |
||||||
231 | |||||||
232 | 10 | return $this->containers[$cacheKey]; |
|||||
233 | } |
||||||
234 | |||||||
235 | 26 | protected static function createKernel(array $options = []): KernelInterface |
|||||
236 | { |
||||||
237 | 26 | if (!isset($options['environment'])) { |
|||||
238 | $options['environment'] = static::$env; |
||||||
239 | } |
||||||
240 | |||||||
241 | 26 | return parent::createKernel($options); |
|||||
242 | } |
||||||
243 | |||||||
244 | /** |
||||||
245 | * Keep support of Symfony < 5.3. |
||||||
246 | */ |
||||||
247 | 10 | public function __call(string $name, $arguments) |
|||||
248 | { |
||||||
249 | 10 | if ('getContainer' === $name) { |
|||||
250 | 10 | return $this->getDependencyInjectionContainer(); |
|||||
251 | } |
||||||
252 | |||||||
253 | throw new \Exception("Method {$name} is not supported."); |
||||||
254 | } |
||||||
255 | |||||||
256 | /** |
||||||
257 | * @deprecated |
||||||
258 | */ |
||||||
259 | 1 | public function __set($name, $value): void |
|||||
260 | { |
||||||
261 | 1 | if ('environment' !== $name) { |
|||||
262 | throw new \Exception(sprintf('There is no property with name "%s"', $name)); |
||||||
263 | } |
||||||
264 | |||||||
265 | 1 | @trigger_error('Setting "environment" property is deprecated, please use static::$env.', \E_USER_DEPRECATED); |
|||||
266 | |||||||
267 | 1 | static::$env = $value; |
|||||
268 | 1 | } |
|||||
269 | |||||||
270 | /** |
||||||
271 | * @deprecated |
||||||
272 | */ |
||||||
273 | public function __isset($name) |
||||||
274 | { |
||||||
275 | if ('environment' !== $name) { |
||||||
276 | throw new \Exception(sprintf('There is no property with name "%s"', $name)); |
||||||
277 | } |
||||||
278 | |||||||
279 | @trigger_error('Checking "environment" property is deprecated, please use static::$env.', \E_USER_DEPRECATED); |
||||||
280 | |||||||
281 | return true; |
||||||
282 | } |
||||||
283 | |||||||
284 | /** |
||||||
285 | * @deprecated |
||||||
286 | */ |
||||||
287 | public function __get($name) |
||||||
288 | { |
||||||
289 | if ('environment' !== $name) { |
||||||
290 | throw new \Exception(sprintf('There is no property with name "%s"', $name)); |
||||||
291 | } |
||||||
292 | |||||||
293 | @trigger_error('Getting "environment" property is deprecated, please use static::$env.', \E_USER_DEPRECATED); |
||||||
294 | |||||||
295 | return static::$env; |
||||||
296 | } |
||||||
297 | |||||||
298 | /** |
||||||
299 | * Creates an instance of a lightweight Http client. |
||||||
300 | * |
||||||
301 | * $params can be used to pass headers to the client, note that they have |
||||||
302 | * to follow the naming format used in $_SERVER. |
||||||
303 | * Example: 'HTTP_X_REQUESTED_WITH' instead of 'X-Requested-With' |
||||||
304 | * |
||||||
305 | * @deprecated |
||||||
306 | */ |
||||||
307 | 12 | protected function makeClient(array $params = []): Client |
|||||
308 | { |
||||||
309 | 12 | return $this->createClientWithParams($params); |
|||||
0 ignored issues
–
show
The function
Liip\FunctionalTestBundl...reateClientWithParams() has been deprecated.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
310 | } |
||||||
311 | |||||||
312 | /** |
||||||
313 | * Creates an instance of a lightweight Http client. |
||||||
314 | * |
||||||
315 | * $params can be used to pass headers to the client, note that they have |
||||||
316 | * to follow the naming format used in $_SERVER. |
||||||
317 | * Example: 'HTTP_X_REQUESTED_WITH' instead of 'X-Requested-With' |
||||||
318 | * |
||||||
319 | * @deprecated |
||||||
320 | */ |
||||||
321 | protected function makeAuthenticatedClient(array $params = []): Client |
||||||
322 | { |
||||||
323 | $username = $this->getContainer() |
||||||
324 | ->getParameter('liip_functional_test.authentication.username'); |
||||||
325 | $password = $this->getContainer() |
||||||
326 | ->getParameter('liip_functional_test.authentication.password'); |
||||||
327 | |||||||
328 | return $this->createClientWithParams($params, $username, $password); |
||||||
0 ignored issues
–
show
The function
Liip\FunctionalTestBundl...reateClientWithParams() has been deprecated.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
329 | } |
||||||
330 | |||||||
331 | /** |
||||||
332 | * Creates an instance of a lightweight Http client and log in user with |
||||||
333 | * username and password params. |
||||||
334 | * |
||||||
335 | * $params can be used to pass headers to the client, note that they have |
||||||
336 | * to follow the naming format used in $_SERVER. |
||||||
337 | * Example: 'HTTP_X_REQUESTED_WITH' instead of 'X-Requested-With' |
||||||
338 | * |
||||||
339 | * @deprecated |
||||||
340 | */ |
||||||
341 | protected function makeClientWithCredentials(string $username, string $password, array $params = []): Client |
||||||
342 | { |
||||||
343 | return $this->createClientWithParams($params, $username, $password); |
||||||
0 ignored issues
–
show
The function
Liip\FunctionalTestBundl...reateClientWithParams() has been deprecated.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
344 | } |
||||||
345 | |||||||
346 | /** |
||||||
347 | * Create User Token. |
||||||
348 | * |
||||||
349 | * Factory method for creating a User Token object for the firewall based on |
||||||
350 | * the user object provided. By default it will be a Username/Password |
||||||
351 | * Token based on the user's credentials, but may be overridden for custom |
||||||
352 | * tokens in your applications. |
||||||
353 | * |
||||||
354 | * @param UserInterface $user The user object to base the token off of |
||||||
355 | * @param string $firewallName name of the firewall provider to use |
||||||
356 | * |
||||||
357 | * @return TokenInterface The token to be used in the security context |
||||||
358 | */ |
||||||
359 | protected function createUserToken(UserInterface $user, string $firewallName): TokenInterface |
||||||
360 | { |
||||||
361 | // Since Symfony 6.0, UsernamePasswordToken only has 3 arguments |
||||||
362 | $usernamePasswordTokenClass = new \ReflectionClass(UsernamePasswordToken::class); |
||||||
363 | |||||||
364 | if (3 === $usernamePasswordTokenClass->getConstructor()->getNumberOfParameters()) { |
||||||
365 | return new UsernamePasswordToken( |
||||||
366 | $user, |
||||||
367 | $firewallName, |
||||||
368 | $user->getRoles() |
||||||
369 | ); |
||||||
370 | } |
||||||
371 | |||||||
372 | return new UsernamePasswordToken( |
||||||
373 | $user, |
||||||
374 | null, |
||||||
375 | $firewallName, |
||||||
376 | $user->getRoles() |
||||||
377 | ); |
||||||
378 | } |
||||||
379 | |||||||
380 | /** |
||||||
381 | * Extracts the location from the given route. |
||||||
382 | * |
||||||
383 | * @param string $route The name of the route |
||||||
384 | * @param array $params Set of parameters |
||||||
385 | */ |
||||||
386 | 1 | protected function getUrl(string $route, array $params = [], int $absolute = UrlGeneratorInterface::ABSOLUTE_PATH): string |
|||||
387 | { |
||||||
388 | 1 | return $this->getContainer()->get('router')->generate($route, $params, $absolute); |
|||||
389 | } |
||||||
390 | |||||||
391 | /** |
||||||
392 | * Checks the success state of a response. |
||||||
393 | * |
||||||
394 | * @param Response $response Response object |
||||||
395 | * @param bool $success to define whether the response is expected to be successful |
||||||
396 | * @param string $type |
||||||
397 | */ |
||||||
398 | 1 | public function isSuccessful(Response $response, $success = true, $type = 'text/html'): void |
|||||
399 | { |
||||||
400 | 1 | HttpAssertions::isSuccessful($response, $success, $type); |
|||||
401 | } |
||||||
402 | |||||||
403 | /** |
||||||
404 | * Executes a request on the given url and returns the response contents. |
||||||
405 | * |
||||||
406 | * This method also asserts the request was successful. |
||||||
407 | * |
||||||
408 | * @param string $path path of the requested page |
||||||
409 | * @param string $method The HTTP method to use, defaults to GET |
||||||
410 | * @param bool $authentication Whether to use authentication, defaults to false |
||||||
411 | * @param bool $success to define whether the response is expected to be successful |
||||||
412 | */ |
||||||
413 | public function fetchContent(string $path, string $method = 'GET', bool $authentication = false, bool $success = true): string |
||||||
414 | { |
||||||
415 | $client = ($authentication) ? $this->makeAuthenticatedClient() : $this->makeClient(); |
||||||
0 ignored issues
–
show
The function
Liip\FunctionalTestBundl...bTestCase::makeClient() has been deprecated.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() The function
Liip\FunctionalTestBundl...keAuthenticatedClient() has been deprecated.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
416 | |||||||
417 | $client->request($method, $path); |
||||||
418 | |||||||
419 | $content = $client->getResponse()->getContent(); |
||||||
420 | $this->isSuccessful($client->getResponse(), $success); |
||||||
421 | |||||||
422 | return $content; |
||||||
423 | } |
||||||
424 | |||||||
425 | /** |
||||||
426 | * Executes a request on the given url and returns a Crawler object. |
||||||
427 | * |
||||||
428 | * This method also asserts the request was successful. |
||||||
429 | * |
||||||
430 | * @param string $path path of the requested page |
||||||
431 | * @param string $method The HTTP method to use, defaults to GET |
||||||
432 | * @param bool $authentication Whether to use authentication, defaults to false |
||||||
433 | * @param bool $success Whether the response is expected to be successful |
||||||
434 | */ |
||||||
435 | public function fetchCrawler(string $path, string $method = 'GET', bool $authentication = false, bool $success = true): Crawler |
||||||
436 | { |
||||||
437 | $client = ($authentication) ? $this->makeAuthenticatedClient() : $this->makeClient(); |
||||||
0 ignored issues
–
show
The function
Liip\FunctionalTestBundl...keAuthenticatedClient() has been deprecated.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() The function
Liip\FunctionalTestBundl...bTestCase::makeClient() has been deprecated.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
438 | |||||||
439 | $crawler = $client->request($method, $path); |
||||||
440 | |||||||
441 | $this->isSuccessful($client->getResponse(), $success); |
||||||
442 | |||||||
443 | return $crawler; |
||||||
444 | } |
||||||
445 | |||||||
446 | /** |
||||||
447 | * @deprecated |
||||||
448 | * |
||||||
449 | * @return WebTestCase |
||||||
450 | */ |
||||||
451 | public function loginAs(UserInterface $user, string $firewallName): self |
||||||
452 | { |
||||||
453 | @trigger_error(sprintf('"%s()" is deprecated, use loginClient() after creating a client.', __METHOD__), \E_USER_DEPRECATED); |
||||||
454 | |||||||
455 | $this->firewallLogins[$firewallName] = $user; |
||||||
456 | |||||||
457 | return $this; |
||||||
458 | } |
||||||
459 | |||||||
460 | /** |
||||||
461 | * @deprecated |
||||||
462 | */ |
||||||
463 | public function loginClient(KernelBrowser $client, UserInterface $user, string $firewallName): void |
||||||
464 | { |
||||||
465 | // Available since Symfony 5.1 |
||||||
466 | if (method_exists($client, 'loginUser')) { |
||||||
467 | @trigger_error( |
||||||
468 | sprintf( |
||||||
469 | '"%s()" is deprecated, use loginUser() from Symfony 5.1+ instead %s', |
||||||
470 | __METHOD__, |
||||||
471 | 'https://symfony.com/doc/5.4/testing.html#logging-in-users-authentication' |
||||||
472 | ), |
||||||
473 | \E_USER_DEPRECATED |
||||||
474 | ); |
||||||
475 | |||||||
476 | $client->loginUser($user); |
||||||
477 | |||||||
478 | return; |
||||||
479 | } |
||||||
480 | |||||||
481 | // has to be set otherwise "hasPreviousSession" in Request returns false. |
||||||
482 | $options = $client->getContainer()->getParameter('session.storage.options'); |
||||||
483 | |||||||
484 | if (!$options || !isset($options['name'])) { |
||||||
485 | throw new \InvalidArgumentException('Missing session.storage.options#name'); |
||||||
486 | } |
||||||
487 | |||||||
488 | $session = $this->getSession($client); |
||||||
489 | |||||||
490 | $client->getCookieJar()->set(new Cookie($options['name'], $session->getId())); |
||||||
491 | |||||||
492 | $token = $this->createUserToken($user, $firewallName); |
||||||
493 | |||||||
494 | $tokenStorage = $client->getContainer()->get('security.token_storage'); |
||||||
495 | |||||||
496 | $tokenStorage->setToken($token); |
||||||
497 | $session->set('_security_'.$firewallName, serialize($token)); |
||||||
498 | |||||||
499 | $session->save(); |
||||||
500 | } |
||||||
501 | |||||||
502 | /** |
||||||
503 | * Asserts that the HTTP response code of the last request performed by |
||||||
504 | * $client matches the expected code. If not, raises an error with more |
||||||
505 | * information. |
||||||
506 | */ |
||||||
507 | public static function assertStatusCode(int $expectedStatusCode, Client $client): void |
||||||
508 | { |
||||||
509 | HttpAssertions::assertStatusCode($expectedStatusCode, $client); |
||||||
510 | } |
||||||
511 | |||||||
512 | /** |
||||||
513 | * Assert that the last validation errors within $container match the |
||||||
514 | * expected keys. |
||||||
515 | * |
||||||
516 | * @param array $expected A flat array of field names |
||||||
517 | */ |
||||||
518 | 1 | public static function assertValidationErrors(array $expected, ContainerInterface $container): void |
|||||
519 | { |
||||||
520 | 1 | HttpAssertions::assertValidationErrors($expected, $container); |
|||||
521 | } |
||||||
522 | |||||||
523 | 27 | protected function tearDown(): void |
|||||
524 | { |
||||||
525 | 27 | if (null !== $this->containers) { |
|||||
526 | 10 | foreach ($this->containers as $container) { |
|||||
527 | 10 | if ($container instanceof ResettableContainerInterface) { |
|||||
528 | 10 | $container->reset(); |
|||||
529 | } |
||||||
530 | } |
||||||
531 | } |
||||||
532 | |||||||
533 | 27 | $this->containers = null; |
|||||
534 | |||||||
535 | 27 | parent::tearDown(); |
|||||
536 | 27 | } |
|||||
537 | |||||||
538 | /** |
||||||
539 | * @deprecated |
||||||
540 | */ |
||||||
541 | 12 | protected function createClientWithParams(array $params, ?string $username = null, ?string $password = null): Client |
|||||
542 | { |
||||||
543 | 12 | if ($username && $password) { |
|||||
544 | $params = array_merge($params, [ |
||||||
545 | 'PHP_AUTH_USER' => $username, |
||||||
546 | 'PHP_AUTH_PW' => $password, |
||||||
547 | ]); |
||||||
548 | } |
||||||
549 | |||||||
550 | 12 | if (static::$booted) { |
|||||
551 | static::ensureKernelShutdown(); |
||||||
552 | } |
||||||
553 | |||||||
554 | 12 | $client = static::createClient(['environment' => static::$env], $params); |
|||||
555 | |||||||
556 | 12 | if ($this->firewallLogins) { |
|||||
0 ignored issues
–
show
The expression
$this->firewallLogins of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||||
557 | // has to be set otherwise "hasPreviousSession" in Request returns false. |
||||||
558 | $options = $client->getContainer()->getParameter('session.storage.options'); |
||||||
559 | |||||||
560 | if (!$options || !isset($options['name'])) { |
||||||
561 | throw new \InvalidArgumentException('Missing session.storage.options#name'); |
||||||
562 | } |
||||||
563 | |||||||
564 | $session = $this->getSession($client); |
||||||
565 | |||||||
566 | $client->getCookieJar()->set(new Cookie($options['name'], $session->getId())); |
||||||
567 | |||||||
568 | /** @var $user UserInterface */ |
||||||
569 | foreach ($this->firewallLogins as $firewallName => $user) { |
||||||
570 | $token = $this->createUserToken($user, $firewallName); |
||||||
571 | |||||||
572 | // Available since Symfony 5.1 |
||||||
573 | if (method_exists($client, 'loginUser')) { |
||||||
574 | @trigger_error( |
||||||
575 | sprintf( |
||||||
576 | '"%s()" is deprecated, use loginUser() from Symfony 5.1+ instead %s', |
||||||
577 | __METHOD__, |
||||||
578 | 'https://symfony.com/doc/5.4/testing.html#logging-in-users-authentication' |
||||||
579 | ), |
||||||
580 | \E_USER_DEPRECATED |
||||||
581 | ); |
||||||
582 | |||||||
583 | $client->loginUser($user); |
||||||
584 | |||||||
585 | continue; |
||||||
586 | } |
||||||
587 | |||||||
588 | $tokenStorage = $client->getContainer()->get('security.token_storage'); |
||||||
589 | |||||||
590 | $tokenStorage->setToken($token); |
||||||
591 | $session->set('_security_'.$firewallName, serialize($token)); |
||||||
592 | } |
||||||
593 | |||||||
594 | $session->save(); |
||||||
595 | } |
||||||
596 | |||||||
597 | 12 | return $client; |
|||||
598 | } |
||||||
599 | |||||||
600 | /** |
||||||
601 | * Compatibility layer. |
||||||
602 | */ |
||||||
603 | private function getSession(KernelBrowser $client): SessionInterface |
||||||
604 | { |
||||||
605 | $container = $client->getContainer(); |
||||||
606 | |||||||
607 | // Preferred since Symfony 5.4 |
||||||
608 | if ($container->has(RequestStack::class)) { |
||||||
609 | /** @var RequestStack $requestStack */ |
||||||
610 | $requestStack = $container->get(RequestStack::class); |
||||||
611 | |||||||
612 | // see https://github.com/symfony/symfony-docs/pull/14898/files#diff-29ab32502d95be802fed1001850b76c9624912cf4c299101d3ecaf17b0352562R37 |
||||||
613 | try { |
||||||
614 | $session = $requestStack->getSession(); |
||||||
615 | } catch (SessionNotFoundException $e) { |
||||||
616 | $requestStack->push(new Request()); |
||||||
617 | $session = new Session(); |
||||||
618 | $session->start(); |
||||||
619 | } |
||||||
620 | |||||||
621 | return $session; |
||||||
622 | } |
||||||
623 | |||||||
624 | /** @var SessionInterface $session */ |
||||||
625 | $session = $container->get(SessionInterface::class); |
||||||
626 | |||||||
627 | $session->start(); |
||||||
628 | |||||||
629 | return $session; |
||||||
630 | } |
||||||
631 | } |
||||||
632 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths