Skip to content

Commit 9749868

Browse files
committed
get the assertions inherent to Symfony
1 parent 9b77251 commit 9749868

File tree

5 files changed

+274
-1
lines changed

5 files changed

+274
-1
lines changed

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"type": "library",
66
"keywords": [
77
"codeception",
8+
"functional testing",
89
"symfony"
910
],
1011
"authors": [

src/Codeception/Module/Symfony.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Codeception\Module\Symfony\BrowserAssertionsTrait;
1414
use Codeception\Module\Symfony\ConsoleAssertionsTrait;
1515
use Codeception\Module\Symfony\DoctrineAssertionsTrait;
16+
use Codeception\Module\Symfony\DomCrawlerAssertionsTrait;
1617
use Codeception\Module\Symfony\EventsAssertionsTrait;
1718
use Codeception\Module\Symfony\FormAssertionsTrait;
1819
use Codeception\Module\Symfony\MailerAssertionsTrait;
@@ -135,6 +136,7 @@ class Symfony extends Framework implements DoctrineProvider, PartedModule
135136
use BrowserAssertionsTrait;
136137
use ConsoleAssertionsTrait;
137138
use DoctrineAssertionsTrait;
139+
use DomCrawlerAssertionsTrait;
138140
use EventsAssertionsTrait;
139141
use FormAssertionsTrait;
140142
use MailerAssertionsTrait;

src/Codeception/Module/Symfony/BrowserAssertionsTrait.php

Lines changed: 194 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,194 @@
44

55
namespace Codeception\Module\Symfony;
66

7+
use PHPUnit\Framework\Constraint\Constraint;
8+
use PHPUnit\Framework\Constraint\LogicalAnd;
9+
use PHPUnit\Framework\Constraint\LogicalNot;
10+
use Symfony\Component\BrowserKit\Test\Constraint\BrowserCookieValueSame;
11+
use Symfony\Component\BrowserKit\Test\Constraint\BrowserHasCookie;
12+
use Symfony\Component\HttpFoundation\Test\Constraint\RequestAttributeValueSame;
13+
use Symfony\Component\HttpFoundation\Test\Constraint\ResponseCookieValueSame;
14+
use Symfony\Component\HttpFoundation\Test\Constraint\ResponseFormatSame;
15+
use Symfony\Component\HttpFoundation\Test\Constraint\ResponseHasCookie;
16+
use Symfony\Component\HttpFoundation\Test\Constraint\ResponseHasHeader;
17+
use Symfony\Component\HttpFoundation\Test\Constraint\ResponseHeaderLocationSame;
18+
use Symfony\Component\HttpFoundation\Test\Constraint\ResponseHeaderSame;
19+
use Symfony\Component\HttpFoundation\Test\Constraint\ResponseIsRedirected;
720
use Symfony\Component\HttpFoundation\Test\Constraint\ResponseIsSuccessful;
21+
use Symfony\Component\HttpFoundation\Test\Constraint\ResponseIsUnprocessable;
22+
use Symfony\Component\HttpFoundation\Test\Constraint\ResponseStatusCodeSame;
823
use function sprintf;
924

1025
trait BrowserAssertionsTrait
1126
{
27+
/**
28+
* Asserts the response format returned by the `Response::getFormat()` method is the same as the expected value.
29+
*/
30+
public function assertResponseFormatSame(?string $expectedFormat, string $message = ''): void
31+
{
32+
$this->assertThatForResponse(new ResponseFormatSame($this->getClient()->getRequest(), $expectedFormat), $message);
33+
}
34+
35+
/**
36+
* Asserts that the response was successful (HTTP status is 2xx).
37+
*/
38+
public function assertResponseIsSuccessful(string $message = '', bool $verbose = true): void
39+
{
40+
$this->assertThatForResponse(new ResponseIsSuccessful($verbose), $message);
41+
}
42+
43+
/**
44+
* Asserts a specific HTTP status code.
45+
*/
46+
public function assertResponseStatusCodeSame(int $expectedCode, string $message = '', bool $verbose = true): void
47+
{
48+
$this->assertThatForResponse(new ResponseStatusCodeSame($expectedCode, $verbose), $message);
49+
}
50+
51+
/**
52+
* Asserts the response is a redirect response (optionally, you can check the target location and status code).
53+
* The excepted location can be either an absolute or a relative path.
54+
*/
55+
public function assertResponseRedirects(?string $expectedLocation = null, ?int $expectedCode = null, string $message = '', bool $verbose = true): void
56+
{
57+
$constraint = new ResponseIsRedirected($verbose);
58+
if ($expectedLocation) {
59+
if (class_exists(ResponseHeaderLocationSame::class)) {
60+
$locationConstraint = new ResponseHeaderLocationSame($this->getClient()->getRequest(), $expectedLocation);
61+
} else {
62+
$locationConstraint = new ResponseHeaderSame('Location', $expectedLocation);
63+
}
64+
65+
$constraint = LogicalAnd::fromConstraints($constraint, $locationConstraint);
66+
}
67+
if ($expectedCode) {
68+
$constraint = LogicalAnd::fromConstraints($constraint, new ResponseStatusCodeSame($expectedCode));
69+
}
70+
71+
$this->assertThatForResponse($constraint, $message);
72+
}
73+
74+
/**
75+
* Asserts the given header is available on the response, e.g. assertResponseHasHeader('content-type');.
76+
*/
77+
public function assertResponseHasHeader(string $headerName, string $message = ''): void
78+
{
79+
$this->assertThatForResponse(new ResponseHasHeader($headerName), $message);
80+
}
81+
82+
/**
83+
* Asserts the given header is not available on the response, e.g. assertResponseNotHasHeader('content-type');.
84+
*/
85+
public function assertResponseNotHasHeader(string $headerName, string $message = ''): void
86+
{
87+
$this->assertThatForResponse(new LogicalNot(new ResponseHasHeader($headerName)), $message);
88+
}
89+
90+
/**
91+
* Asserts the given header does contain the expected value on the response,
92+
* e.g. assertResponseHeaderSame('content-type', 'application/octet-stream');.
93+
*/
94+
public function assertResponseHeaderSame(string $headerName, string $expectedValue, string $message = ''): void
95+
{
96+
$this->assertThatForResponse(new ResponseHeaderSame($headerName, $expectedValue), $message);
97+
}
98+
99+
/**
100+
* Asserts the given header does not contain the expected value on the response,
101+
* e.g. assertResponseHeaderNotSame('content-type', 'application/octet-stream');.
102+
*/
103+
public function assertResponseHeaderNotSame(string $headerName, string $expectedValue, string $message = ''): void
104+
{
105+
$this->assertThatForResponse(new LogicalNot(new ResponseHeaderSame($headerName, $expectedValue)), $message);
106+
}
107+
108+
/**
109+
* Asserts the given cookie is present in the response (optionally checking for a specific cookie path or domain).
110+
*/
111+
public function assertResponseHasCookie(string $name, string $path = '/', ?string $domain = null, string $message = ''): void
112+
{
113+
$this->assertThatForResponse(new ResponseHasCookie($name, $path, $domain), $message);
114+
}
115+
116+
/**
117+
* Asserts the given cookie is not present in the response (optionally checking for a specific cookie path or domain).
118+
*/
119+
public function assertResponseNotHasCookie(string $name, string $path = '/', ?string $domain = null, string $message = ''): void
120+
{
121+
$this->assertThatForResponse(new LogicalNot(new ResponseHasCookie($name, $path, $domain)), $message);
122+
}
123+
124+
/**
125+
* Asserts the given cookie is present and set to the expected value.
126+
*/
127+
public function assertResponseCookieValueSame(string $name, string $expectedValue, string $path = '/', ?string $domain = null, string $message = ''): void
128+
{
129+
$this->assertThatForResponse(LogicalAnd::fromConstraints(
130+
new ResponseHasCookie($name, $path, $domain),
131+
new ResponseCookieValueSame($name, $expectedValue, $path, $domain)
132+
), $message);
133+
}
134+
135+
/**
136+
* Asserts the response is unprocessable (HTTP status is 422)
137+
*/
138+
public function assertResponseIsUnprocessable(string $message = '', bool $verbose = true): void
139+
{
140+
$this->assertThatForResponse(new ResponseIsUnprocessable($verbose), $message);
141+
}
142+
143+
/**
144+
* Asserts that the test Client does have the given cookie set (meaning, the cookie was set by any response in the test).
145+
*/
146+
public function assertBrowserHasCookie(string $name, string $path = '/', ?string $domain = null, string $message = ''): void
147+
{
148+
self::assertThatForClient(new BrowserHasCookie($name, $path, $domain), $message);
149+
}
150+
151+
/**
152+
* Asserts that the test Client does not have the given cookie set (meaning, the cookie was set by any response in the test).
153+
*/
154+
public function assertBrowserNotHasCookie(string $name, string $path = '/', ?string $domain = null, string $message = ''): void
155+
{
156+
self::assertThatForClient(new LogicalNot(new BrowserHasCookie($name, $path, $domain)), $message);
157+
}
158+
159+
/**
160+
* Asserts the given cookie in the test Client is set to the expected value.
161+
*/
162+
public function assertBrowserCookieValueSame(string $name, string $expectedValue, bool $raw = false, string $path = '/', ?string $domain = null, string $message = ''): void
163+
{
164+
self::assertThatForClient(LogicalAnd::fromConstraints(
165+
new BrowserHasCookie($name, $path, $domain),
166+
new BrowserCookieValueSame($name, $expectedValue, $raw, $path, $domain)
167+
), $message);
168+
}
169+
170+
/**
171+
* Asserts the given request attribute is set to the expected value.
172+
*/
173+
public function assertRequestAttributeValueSame(string $name, string $expectedValue, string $message = ''): void
174+
{
175+
self::assertThat($this->getClient()->getRequest(), new RequestAttributeValueSame($name, $expectedValue), $message);
176+
}
177+
178+
/**
179+
* Asserts the request matches the given route and optionally route parameters.
180+
*/
181+
public function assertRouteSame(string $expectedRoute, array $parameters = [], string $message = ''): void
182+
{
183+
$constraint = new RequestAttributeValueSame('_route', $expectedRoute);
184+
$constraints = [];
185+
foreach ($parameters as $key => $value) {
186+
$constraints[] = new RequestAttributeValueSame($key, $value);
187+
}
188+
if ($constraints) {
189+
$constraint = LogicalAnd::fromConstraints($constraint, ...$constraints);
190+
}
191+
192+
self::assertThat($this->getClient()->getRequest(), $constraint, $message);
193+
}
194+
12195
/**
13196
* Reboot client's kernel.
14197
* Can be used to manually reboot kernel when 'rebootable_client' => false
@@ -50,7 +233,7 @@ public function seePageIsAvailable(?string $url = null): void
50233
$this->seeInCurrentUrl($url);
51234
}
52235

53-
$this->assertThat($this->getClient()->getResponse(), new ResponseIsSuccessful());
236+
$this->assertResponseIsSuccessful();
54237
}
55238

56239
/**
@@ -104,4 +287,14 @@ public function submitSymfonyForm(string $name, array $fields): void
104287

105288
$this->submitForm($selector, $params, $button);
106289
}
290+
291+
protected function assertThatForClient(Constraint $constraint, string $message = ''): void
292+
{
293+
$this->assertThat($this->getClient(), $constraint, $message);
294+
}
295+
296+
protected function assertThatForResponse(Constraint $constraint, string $message = ''): void
297+
{
298+
$this->assertThat($this->getClient()->getResponse(), $constraint, $message);
299+
}
107300
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Codeception\Module\Symfony;
6+
7+
use PHPUnit\Framework\Constraint\LogicalNot;
8+
use Symfony\Component\DomCrawler\Crawler;
9+
use Symfony\Component\DomCrawler\Test\Constraint\CrawlerSelectorExists;
10+
11+
trait DomCrawlerAssertionsTrait
12+
{
13+
/**
14+
* Asserts that the checkbox with the given name is checked.
15+
*/
16+
public function assertCheckboxChecked(string $fieldName, string $message = ''): void
17+
{
18+
$this->assertThat(
19+
$this->getCrawler(),
20+
new CrawlerSelectorExists("input[name=\"$fieldName\"]:checked"),
21+
$message
22+
);
23+
}
24+
25+
/**
26+
* Asserts that the checkbox with the given name is not checked.
27+
*/
28+
public function assertCheckboxNotChecked(string $fieldName, string $message = ''): void
29+
{
30+
$this->assertThat(
31+
$this->getCrawler(),
32+
new LogicalNot(new CrawlerSelectorExists("input[name=\"$fieldName\"]:checked")),
33+
$message
34+
);
35+
}
36+
37+
protected function getCrawler(): Crawler
38+
{
39+
return $this->client->getCrawler();
40+
}
41+
}

src/Codeception/Module/Symfony/FormAssertionsTrait.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace Codeception\Module\Symfony;
66

7+
use DateInterval;
8+
use DateTime;
79
use Symfony\Component\Form\Extension\DataCollector\FormDataCollector;
810
use function array_key_exists;
911
use function in_array;
@@ -12,6 +14,40 @@
1214

1315
trait FormAssertionsTrait
1416
{
17+
public function assertDateTimeEquals(DateTime $expected, DateTime $actual): void
18+
{
19+
$this->assertSame($expected->format('c'), $actual->format('c'));
20+
}
21+
22+
public function assertDateIntervalEquals(DateInterval $expected, DateInterval $actual): void
23+
{
24+
$format = '%RP%yY%mM%dDT%hH%iM%sS';
25+
$this->assertSame($expected->format($format), $actual->format($format));
26+
}
27+
28+
/**
29+
* Asserts that value of the field of the first form matching the given selector does equal the expected value.
30+
*/
31+
public function assertFormValue(string $formSelector, string $fieldName, string $value, string $message = ''): void
32+
{
33+
$node = $this->getCrawler()->filter($formSelector);
34+
$this->assertNotEmpty($node, sprintf('Form "%s" not found.', $formSelector));
35+
$values = $node->form()->getValues();
36+
$this->assertArrayHasKey($fieldName, $values, $message ?: sprintf('Field "%s" not found in form "%s".', $fieldName, $formSelector));
37+
$this->assertSame($value, $values[$fieldName]);
38+
}
39+
40+
/**
41+
* Asserts that value of the field of the first form matching the given selector does equal the expected value.
42+
*/
43+
public function assertNoFormValue(string $formSelector, string $fieldName, string $message = ''): void
44+
{
45+
$node = $this->getCrawler()->filter($formSelector);
46+
$this->assertNotEmpty($node, sprintf('Form "%s" not found.', $formSelector));
47+
$values = $node->form()->getValues();
48+
$this->assertArrayNotHasKey($fieldName, $values, $message ?: sprintf('Field "%s" has a value in form "%s".', $fieldName, $formSelector));
49+
}
50+
1551
/**
1652
* Verifies that there are no errors bound to the submitted form.
1753
*

0 commit comments

Comments
 (0)