Skip to content

Commit 1987a3d

Browse files
committed
get the inherent Symfony assertions
1 parent 9b77251 commit 1987a3d

File tree

5 files changed

+424
-57
lines changed

5 files changed

+424
-57
lines changed

Diff for: composer.json

+1
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": [

Diff for: src/Codeception/Module/Symfony.php

+2
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;

Diff for: src/Codeception/Module/Symfony/BrowserAssertionsTrait.php

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

53-
$this->assertThat($this->getClient()->getResponse(), new ResponseIsSuccessful());
233+
$this->assertResponseIsSuccessful();
234+
}
235+
236+
/**
237+
* Asserts that the response was successful (HTTP status is 2xx).
238+
*/
239+
public function assertResponseIsSuccessful(string $message = '', bool $verbose = true): void
240+
{
241+
$this->assertThatForResponse(new ResponseIsSuccessful($verbose), $message);
54242
}
55243

56244
/**
@@ -104,4 +292,9 @@ public function submitSymfonyForm(string $name, array $fields): void
104292

105293
$this->submitForm($selector, $params, $button);
106294
}
295+
296+
protected function assertThatForResponse(Constraint $constraint, string $message = ''): void
297+
{
298+
$this->assertThat($this->getClient()->getResponse(), $constraint, $message);
299+
}
107300
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Codeception\Module\Symfony;
6+
7+
use PHPUnit\Framework\Constraint\LogicalAnd;
8+
use PHPUnit\Framework\Constraint\LogicalNot;
9+
use Symfony\Component\DomCrawler\Crawler;
10+
use Symfony\Component\DomCrawler\Test\Constraint\CrawlerAnySelectorTextContains;
11+
use Symfony\Component\DomCrawler\Test\Constraint\CrawlerAnySelectorTextSame;
12+
use Symfony\Component\DomCrawler\Test\Constraint\CrawlerSelectorAttributeValueSame;
13+
use Symfony\Component\DomCrawler\Test\Constraint\CrawlerSelectorCount;
14+
use Symfony\Component\DomCrawler\Test\Constraint\CrawlerSelectorExists;
15+
use Symfony\Component\DomCrawler\Test\Constraint\CrawlerSelectorTextContains;
16+
use Symfony\Component\DomCrawler\Test\Constraint\CrawlerSelectorTextSame;
17+
18+
trait DomCrawlerAssertionsTrait
19+
{
20+
public function assertSelectorExists(string $selector, string $message = ''): void
21+
{
22+
$this->assertThat($this->getCrawler(), new CrawlerSelectorExists($selector), $message);
23+
}
24+
25+
public function assertSelectorNotExists(string $selector, string $message = ''): void
26+
{
27+
$this->assertThat($this->getCrawler(), new LogicalNot(new CrawlerSelectorExists($selector)), $message);
28+
}
29+
30+
public function assertSelectorCount(int $expectedCount, string $selector, string $message = ''): void
31+
{
32+
$this->assertThat($this->getCrawler(), new CrawlerSelectorCount($expectedCount, $selector), $message);
33+
}
34+
35+
public function assertAnySelectorTextContains(string $selector, string $text, string $message = ''): void
36+
{
37+
$this->assertThat($this->getCrawler(), LogicalAnd::fromConstraints(
38+
new CrawlerSelectorExists($selector),
39+
new CrawlerAnySelectorTextContains($selector, $text)
40+
), $message);
41+
}
42+
43+
public function assertAnySelectorTextSame(string $selector, string $text, string $message = ''): void
44+
{
45+
$this->assertThat($this->getCrawler(), LogicalAnd::fromConstraints(
46+
new CrawlerSelectorExists($selector),
47+
new CrawlerAnySelectorTextSame($selector, $text)
48+
), $message);
49+
}
50+
51+
public function assertSelectorTextNotContains(string $selector, string $text, string $message = ''): void
52+
{
53+
$this->assertThat($this->getCrawler(), LogicalAnd::fromConstraints(
54+
new CrawlerSelectorExists($selector),
55+
new LogicalNot(new CrawlerSelectorTextContains($selector, $text))
56+
), $message);
57+
}
58+
59+
public function assertAnySelectorTextNotContains(string $selector, string $text, string $message = ''): void
60+
{
61+
$this->assertThat($this->getCrawler(), LogicalAnd::fromConstraints(
62+
new CrawlerSelectorExists($selector),
63+
new LogicalNot(new CrawlerAnySelectorTextContains($selector, $text))
64+
), $message);
65+
}
66+
67+
public function assertPageTitleSame(string $expectedTitle, string $message = ''): void
68+
{
69+
$this->assertSelectorTextSame('title', $expectedTitle, $message);
70+
}
71+
72+
public function assertSelectorTextSame(string $selector, string $text, string $message = ''): void
73+
{
74+
$this->assertThat($this->getCrawler(), LogicalAnd::fromConstraints(
75+
new CrawlerSelectorExists($selector),
76+
new CrawlerSelectorTextSame($selector, $text)
77+
), $message);
78+
}
79+
80+
public function assertPageTitleContains(string $expectedTitle, string $message = ''): void
81+
{
82+
$this->assertSelectorTextContains('title', $expectedTitle, $message);
83+
}
84+
85+
public function assertSelectorTextContains(string $selector, string $text, string $message = ''): void
86+
{
87+
$this->assertThat($this->getCrawler(), LogicalAnd::fromConstraints(
88+
new CrawlerSelectorExists($selector),
89+
new CrawlerSelectorTextContains($selector, $text)
90+
), $message);
91+
}
92+
93+
public function assertInputValueSame(string $fieldName, string $expectedValue, string $message = ''): void
94+
{
95+
$this->assertThat($this->getCrawler(), LogicalAnd::fromConstraints(
96+
new CrawlerSelectorExists("input[name=\"$fieldName\"]"),
97+
new CrawlerSelectorAttributeValueSame("input[name=\"$fieldName\"]", 'value', $expectedValue)
98+
), $message);
99+
}
100+
101+
public function assertInputValueNotSame(string $fieldName, string $expectedValue, string $message = ''): void
102+
{
103+
$this->assertThat($this->getCrawler(), LogicalAnd::fromConstraints(
104+
new CrawlerSelectorExists("input[name=\"$fieldName\"]"),
105+
new LogicalNot(new CrawlerSelectorAttributeValueSame("input[name=\"$fieldName\"]", 'value', $expectedValue))
106+
), $message);
107+
}
108+
109+
/**
110+
* Asserts that the checkbox with the given name is checked.
111+
*/
112+
public function assertCheckboxChecked(string $fieldName, string $message = ''): void
113+
{
114+
$this->assertThat(
115+
$this->getCrawler(),
116+
new CrawlerSelectorExists("input[name=\"$fieldName\"]:checked"),
117+
$message
118+
);
119+
}
120+
121+
/**
122+
* Asserts that the checkbox with the given name is not checked.
123+
*/
124+
public function assertCheckboxNotChecked(string $fieldName, string $message = ''): void
125+
{
126+
$this->assertThat(
127+
$this->getCrawler(),
128+
new LogicalNot(new CrawlerSelectorExists("input[name=\"$fieldName\"]:checked")),
129+
$message
130+
);
131+
}
132+
133+
protected function getCrawler(): Crawler
134+
{
135+
return $this->client->getCrawler();
136+
}
137+
}

0 commit comments

Comments
 (0)