Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 17a3ccf

Browse filesBrowse files
committed
feature #30813 New PHPUnit assertions for the WebTestCase (Pierstoval, fabpot)
This PR was merged into the 4.3-dev branch. Discussion ---------- New PHPUnit assertions for the WebTestCase | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | replaces #29990 | License | MIT | Doc PR | n/a While reviewing #29990, and working on some tests, I realized that we could do better by adding PHPUnit constraint classes in various components that are then used in WebTextCase. **Before** ```php <?php namespace App\Tests; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class DefaultControllerTest extends WebTestCase { public function testSomething() { $client = static::createClient(); $crawler = $client->request('GET', '/test'); $this->assertSame(200, $client->getResponse()->getStatusCode()); $this->assertContains('Hello World', $crawler->filter('h1')->text()); } } ``` **After** ```php <?php namespace App\Tests; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class DefaultControllerTest extends WebTestCase { public function testSomething() { $client = static::createClient(); $client->request('GET', '/test'); $this->assertResponseIsSuccessful(); $this->assertSelectorTextContains('h1', 'Hello World'); } } ``` Commits ------- 4f91020 added PHPUnit assertions in various components 2f8040e Create new PHPUnit assertions for the WebTestCase
2 parents fefe62c + 4f91020 commit 17a3ccf
Copy full SHA for 17a3ccf

38 files changed

+2062
-8
lines changed

‎src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ CHANGELOG
44
4.3.0
55
-----
66

7+
* added `WebTestAssertions` trait (included by default in `WebTestCase`)
78
* renamed `Client` to `KernelBrowser`
89
* Not passing the project directory to the constructor of the `AssetsInstallCommand` is deprecated. This argument will
910
be mandatory in 5.0.

‎src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php
+6-1Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
*/
2424
abstract class KernelTestCase extends TestCase
2525
{
26-
use KernelShutdownOnTearDownTrait;
26+
use TestCaseSetUpTearDownTrait;
2727

2828
protected static $class;
2929

@@ -37,6 +37,11 @@ abstract class KernelTestCase extends TestCase
3737
*/
3838
protected static $container;
3939

40+
protected function doTearDown(): void
41+
{
42+
static::ensureKernelShutdown();
43+
}
44+
4045
/**
4146
* @return string The Kernel class name
4247
*

‎src/Symfony/Bundle/FrameworkBundle/Test/KernelShutdownOnTearDownTrait.php renamed to ‎src/Symfony/Bundle/FrameworkBundle/Test/TestCaseSetUpTearDownTrait.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Test/TestCaseSetUpTearDownTrait.php
+34-5Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,31 +13,60 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515

16-
// Auto-adapt to PHPUnit 8 that added a `void` return-type to the tearDown method
16+
// Auto-adapt to PHPUnit 8 that added a `void` return-type to the setUp/tearDown methods
1717

1818
if ((new \ReflectionMethod(TestCase::class, 'tearDown'))->hasReturnType()) {
1919
/**
2020
* @internal
2121
*/
22-
trait KernelShutdownOnTearDownTrait
22+
trait TestCaseSetUpTearDownTrait
2323
{
24+
private function doSetUp(): void
25+
{
26+
}
27+
28+
private function doTearDown(): void
29+
{
30+
}
31+
32+
protected function setUp(): void
33+
{
34+
$this->doSetUp();
35+
}
36+
2437
protected function tearDown(): void
2538
{
26-
static::ensureKernelShutdown();
39+
$this->doTearDown();
2740
}
2841
}
2942
} else {
3043
/**
3144
* @internal
3245
*/
33-
trait KernelShutdownOnTearDownTrait
46+
trait TestCaseSetUpTearDownTrait
3447
{
48+
private function doSetUp(): void
49+
{
50+
}
51+
52+
private function doTearDown(): void
53+
{
54+
}
55+
56+
/**
57+
* @return void
58+
*/
59+
protected function setUp()
60+
{
61+
$this->doSetUp();
62+
}
63+
3564
/**
3665
* @return void
3766
*/
3867
protected function tearDown()
3968
{
40-
static::ensureKernelShutdown();
69+
$this->doTearDown();
4170
}
4271
}
4372
}
+224Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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 Symfony\Bundle\FrameworkBundle\Test;
13+
14+
use PHPUnit\Framework\Constraint\LogicalAnd;
15+
use PHPUnit\Framework\Constraint\LogicalNot;
16+
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
17+
use Symfony\Component\BrowserKit\Test\Constraint as BrowserKitConstraint;
18+
use Symfony\Component\DomCrawler\Crawler;
19+
use Symfony\Component\DomCrawler\Test\Constraint as DomCrawlerConstraint;
20+
use Symfony\Component\HttpFoundation\Request;
21+
use Symfony\Component\HttpFoundation\Response;
22+
use Symfony\Component\HttpFoundation\Test\Constraint as ResponseConstraint;
23+
24+
/**
25+
* Ideas borrowed from Laravel Dusk's assertions.
26+
*
27+
* @see https://laravel.com/docs/5.7/dusk#available-assertions
28+
*/
29+
trait WebTestAssertions
30+
{
31+
public static function assertResponseIsSuccessful(string $message = ''): void
32+
{
33+
self::assertThat(static::getResponse(), new ResponseConstraint\ResponseIsSuccessful(), $message);
34+
}
35+
36+
public static function assertResponseStatusCodeSame(int $expectedCode, string $message = ''): void
37+
{
38+
self::assertThat(static::getResponse(), new ResponseConstraint\ResponseStatusCodeSame($expectedCode), $message);
39+
}
40+
41+
public static function assertResponseRedirects(string $expectedLocation = null, int $expectedCode = null, string $message = ''): void
42+
{
43+
$constraint = new ResponseConstraint\ResponseIsRedirected();
44+
if ($expectedLocation) {
45+
$constraint = LogicalAnd::fromConstraints($constraint, new ResponseConstraint\ResponseHeaderSame('Location', $expectedLocation));
46+
}
47+
if ($expectedCode) {
48+
$constraint = LogicalAnd::fromConstraints($constraint, new ResponseConstraint\ResponseStatusCodeSame($expectedCode));
49+
}
50+
51+
self::assertThat(static::getResponse(), $constraint, $message);
52+
}
53+
54+
public static function assertResponseHasHeader(string $headerName, string $message = ''): void
55+
{
56+
self::assertThat(static::getResponse(), new ResponseConstraint\ResponseHasHeader($headerName), $message);
57+
}
58+
59+
public static function assertResponseNotHasHeader(string $headerName, string $message = ''): void
60+
{
61+
self::assertThat(static::getResponse(), new LogicalNot(new ResponseConstraint\ResponseHasHeader($headerName)), $message);
62+
}
63+
64+
public static function assertResponseHeaderSame(string $headerName, string $expectedValue, string $message = ''): void
65+
{
66+
self::assertThat(static::getResponse(), new ResponseConstraint\ResponseHeaderSame($headerName, $expectedValue), $message);
67+
}
68+
69+
public static function assertResponseHeaderNotSame(string $headerName, string $expectedValue, string $message = ''): void
70+
{
71+
self::assertThat(static::getResponse(), new LogicalNot(new ResponseConstraint\ResponseHeaderSame($headerName, $expectedValue)), $message);
72+
}
73+
74+
public static function assertResponseHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void
75+
{
76+
self::assertThat(static::getResponse(), new ResponseConstraint\ResponseHasCookie($name, $path, $domain), $message);
77+
}
78+
79+
public static function assertResponseNotHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void
80+
{
81+
self::assertThat(static::getResponse(), new LogicalNot(new ResponseConstraint\ResponseHasCookie($name, $path, $domain)), $message);
82+
}
83+
84+
public static function assertResponseCookieValueSame(string $name, string $expectedValue, string $path = '/', string $domain = null, string $message = ''): void
85+
{
86+
self::assertThat(static::getResponse(), LogicalAnd::fromConstraints(
87+
new ResponseConstraint\ResponseHasCookie($name, $path, $domain),
88+
new ResponseConstraint\ResponseCookieValueSame($name, $expectedValue, $path, $domain)
89+
), $message);
90+
}
91+
92+
public static function assertBrowserHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void
93+
{
94+
self::assertThat(static::getClient(), new BrowserKitConstraint\BrowserHasCookie($name, $path, $domain), $message);
95+
}
96+
97+
public static function assertBrowserNotHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void
98+
{
99+
self::assertThat(static::getClient(), new LogicalNot(new BrowserKitConstraint\BrowserHasCookie($name, $path, $domain)), $message);
100+
}
101+
102+
public static function assertBrowserCookieValueSame(string $name, string $expectedValue, bool $raw = false, string $path = '/', string $domain = null, string $message = ''): void
103+
{
104+
self::assertThat(static::getClient(), LogicalAnd::fromConstraints(
105+
new BrowserKitConstraint\BrowserHasCookie($name, $path, $domain),
106+
new BrowserKitConstraint\BrowserCookieValueSame($name, $expectedValue, $raw, $path, $domain)
107+
), $message);
108+
}
109+
110+
public static function assertSelectorExists(string $selector, string $message = ''): void
111+
{
112+
self::assertThat(static::getCrawler(), new DomCrawlerConstraint\CrawlerSelectorExists($selector), $message);
113+
}
114+
115+
public static function assertSelectorNotExists(string $selector, string $message = ''): void
116+
{
117+
self::assertThat(static::getCrawler(), new LogicalNot(new DomCrawlerConstraint\CrawlerSelectorExists($selector)), $message);
118+
}
119+
120+
public static function assertSelectorTextContains(string $selector, string $text, string $message = ''): void
121+
{
122+
self::assertThat(static::getCrawler(), LogicalAnd::fromConstraints(
123+
new DomCrawlerConstraint\CrawlerSelectorExists($selector),
124+
new DomCrawlerConstraint\CrawlerSelectorTextContains($selector, $text)
125+
), $message);
126+
}
127+
128+
public static function assertSelectorTextSame(string $selector, string $text, string $message = ''): void
129+
{
130+
self::assertThat(static::getCrawler(), LogicalAnd::fromConstraints(
131+
new DomCrawlerConstraint\CrawlerSelectorExists($selector),
132+
new DomCrawlerConstraint\CrawlerSelectorTextSame($selector, $text)
133+
), $message);
134+
}
135+
136+
public static function assertSelectorTextNotContains(string $selector, string $text, string $message = ''): void
137+
{
138+
self::assertThat(static::getCrawler(), LogicalAnd::fromConstraints(
139+
new DomCrawlerConstraint\CrawlerSelectorExists($selector),
140+
new LogicalNot(new DomCrawlerConstraint\CrawlerSelectorTextContains($selector, $text))
141+
), $message);
142+
}
143+
144+
public static function assertPageTitleSame(string $expectedTitle, string $message = ''): void
145+
{
146+
self::assertSelectorTextSame('title', $expectedTitle, $message);
147+
}
148+
149+
public static function assertPageTitleContains(string $expectedTitle, string $message = ''): void
150+
{
151+
self::assertSelectorTextContains('title', $expectedTitle, $message);
152+
}
153+
154+
public static function assertInputValueSame(string $fieldName, string $expectedValue, string $message = ''): void
155+
{
156+
self::assertThat(static::getCrawler(), LogicalAnd::fromConstraints(
157+
new DomCrawlerConstraint\CrawlerSelectorExists("input[name=\"$fieldName\"]"),
158+
new DomCrawlerConstraint\CrawlerSelectorAttributeValueSame("input[name=\"$fieldName\"]", 'value', $expectedValue)
159+
), $message);
160+
}
161+
162+
public static function assertInputValueNotSame(string $fieldName, string $expectedValue, string $message = ''): void
163+
{
164+
self::assertThat(static::getCrawler(), LogicalAnd::fromConstraints(
165+
new DomCrawlerConstraint\CrawlerSelectorExists("input[name=\"$fieldName\"]"),
166+
new LogicalNot(new DomCrawlerConstraint\CrawlerSelectorAttributeValueSame("input[name=\"$fieldName\"]", 'value', $expectedValue))
167+
), $message);
168+
}
169+
170+
public static function assertRequestAttributeValueSame(string $name, string $expectedValue, string $message = ''): void
171+
{
172+
self::assertThat(static::getRequest(), new ResponseConstraint\RequestAttributeValueSame($name, $expectedValue), $message);
173+
}
174+
175+
public static function assertRouteSame($expectedRoute, array $parameters = [], string $message = ''): void
176+
{
177+
$constraint = new ResponseConstraint\RequestAttributeValueSame('_route', $expectedRoute);
178+
$constraints = [];
179+
foreach ($parameters as $key => $value) {
180+
$constraints[] = new ResponseConstraint\RequestAttributeValueSame($key, $value);
181+
}
182+
if ($constraints) {
183+
$constraint = LogicalAnd::fromConstraints($constraint, ...$constraints);
184+
}
185+
186+
self::assertThat(static::getRequest(), $constraint, $message);
187+
}
188+
189+
private static function getClient(): KernelBrowser
190+
{
191+
if (!static::$client instanceof KernelBrowser) {
192+
static::fail(\sprintf('A client must be set to make assertions on it. Did you forget to call "%s::createClient"?', __CLASS__));
193+
}
194+
195+
return static::$client;
196+
}
197+
198+
private static function getCrawler(): Crawler
199+
{
200+
if (!$crawler = static::getClient()->getCrawler()) {
201+
static::fail('A client must have a crawler to make assertions. Did you forget to make an HTTP request?');
202+
}
203+
204+
return $crawler;
205+
}
206+
207+
private static function getResponse(): Response
208+
{
209+
if (!$response = static::getClient()->getResponse()) {
210+
static::fail('A client must have an HTTP Response to make assertions. Did you forget to make an HTTP request?');
211+
}
212+
213+
return $response;
214+
}
215+
216+
private static function getRequest(): Request
217+
{
218+
if (!$request = static::getClient()->getRequest()) {
219+
static::fail('A client must have an HTTP Request to make assertions. Did you forget to make an HTTP request?');
220+
}
221+
222+
return $request;
223+
}
224+
}

‎src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php
+13-1Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,18 @@
2121
*/
2222
abstract class WebTestCase extends KernelTestCase
2323
{
24+
use WebTestAssertions;
25+
26+
/** @var Client|null */
27+
protected static $client;
28+
29+
protected function doTearDown(): void
30+
{
31+
parent::doTearDown();
32+
33+
static::$client = null;
34+
}
35+
2436
/**
2537
* Creates a KernelBrowser.
2638
*
@@ -44,6 +56,6 @@ protected static function createClient(array $options = [], array $server = [])
4456

4557
$client->setServerParameters($server);
4658

47-
return $client;
59+
return static::$client = $client;
4860
}
4961
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.