diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index ac3d971898..3d19141469 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 4.3.0 ----- + * added `WebTestAssertions` trait (included by default in `WebTestCase`) * renamed `Client` to `KernelBrowser` * Not passing the project directory to the constructor of the `AssetsInstallCommand` is deprecated. This argument will be mandatory in 5.0. diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/WebTestAssertions.php b/src/Symfony/Bundle/FrameworkBundle/Test/WebTestAssertions.php index dbc6ef65ff..25eac6fe0a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Test/WebTestAssertions.php +++ b/src/Symfony/Bundle/FrameworkBundle/Test/WebTestAssertions.php @@ -11,12 +11,15 @@ namespace Symfony\Bundle\FrameworkBundle\Test; -use PHPUnit\Framework\Assert; -use Symfony\Bundle\FrameworkBundle\Client; +use PHPUnit\Framework\Constraint\LogicalAnd; +use PHPUnit\Framework\Constraint\LogicalNot; +use Symfony\Bundle\FrameworkBundle\KernelBrowser; +use Symfony\Component\BrowserKit\Test\Constraint as BrowserKitConstraint; use Symfony\Component\DomCrawler\Crawler; -use Symfony\Component\HttpFoundation\Cookie; +use Symfony\Component\DomCrawler\Test\Constraint as DomCrawlerConstraint; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Test\Constraint as ResponseConstraint; /** * Ideas borrowed from Laravel Dusk's assertions. @@ -25,324 +28,168 @@ use Symfony\Component\HttpFoundation\Response; */ trait WebTestAssertions { - /** @var Client|null */ - protected static $client; - - public static function assertResponseIsSuccessful(): void + public static function assertResponseIsSuccessful(string $message = ''): void { - $response = static::getResponse(); - - Assert::assertTrue( - $response->isSuccessful(), - sprintf('Response was expected to be successful, but actual HTTP code is %d.', $response->getStatusCode()) - ); + self::assertThat(static::getResponse(), new ResponseConstraint\ResponseIsSuccessful(), $message); } - public static function assertHttpCodeEquals(int $expectedCode): void + public static function assertResponseStatusCodeSame(int $expectedCode, string $message = ''): void { - Assert::assertSame( - $expectedCode, - $code = static::getResponse()->getStatusCode(), - sprintf('Response code "%s" does not match actual HTTP code "%s".', $expectedCode, $code) - ); + self::assertThat(static::getResponse(), new ResponseConstraint\ResponseStatusCodeSame($expectedCode), $message); } - public static function assertResponseHasHeader(string $headerName): void + public static function assertResponseRedirects(string $expectedLocation = null, int $expectedCode = null, string $message = ''): void { - Assert::assertTrue( - static::getResponse()->headers->has($headerName), - sprintf('Header "%s" was not found in the Response.', $headerName) - ); - } - - public static function assertResponseNotHasHeader(string $headerName): void - { - Assert::assertFalse( - static::getResponse()->headers->has($headerName), - sprintf('Header "%s" was not expected to be found in the Response.', $headerName) - ); - } - - public static function assertResponseHeaderEquals(string $headerName, $expectedValue): void - { - Assert::assertSame( - $expectedValue, - $value = static::getResponse()->headers->get($headerName, null, true), - sprintf('Header "%s" with value "%s" does not equal actual value "%s".', $headerName, $expectedValue, $value) - ); - } - - public static function assertResponseHeaderNotEquals(string $headerName, $expectedValue): void - { - Assert::assertNotSame( - $expectedValue, - $value = static::getResponse()->headers->get($headerName, null, true), - sprintf('Header "%s" with value "%s" was not expected to equal actual value "%s".', $headerName, $expectedValue, $value) - ); - } - - public static function assertResponseRedirects(string $expectedLocation = null, int $expectedCode = null): void - { - $response = static::getResponse(); - - Assert::assertTrue( - $response->isRedirect(), - sprintf('Response was expected to be a redirection, but actual HTTP code is %s.', $response->getStatusCode()) - ); - + $constraint = new ResponseConstraint\ResponseIsRedirected(); + if ($expectedLocation) { + $constraint = LogicalAnd::fromConstraints($constraint, new ResponseConstraint\ResponseHeaderSame('Location', $expectedLocation)); + } if ($expectedCode) { - static::assertHttpCodeEquals($expectedCode); + $constraint = LogicalAnd::fromConstraints($constraint, new ResponseConstraint\ResponseStatusCodeSame($expectedCode)); } - if (null !== $expectedLocation) { - Assert::assertSame( - $expectedLocation, - $location = $response->headers->get('Location'), - sprintf('Location "%s" does not match actual redirection URL "%s".', $expectedLocation, $location) - ); + self::assertThat(static::getResponse(), $constraint, $message); + } + + public static function assertResponseHasHeader(string $headerName, string $message = ''): void + { + self::assertThat(static::getResponse(), new ResponseConstraint\ResponseHasHeader($headerName), $message); + } + + public static function assertResponseNotHasHeader(string $headerName, string $message = ''): void + { + self::assertThat(static::getResponse(), new LogicalNot(new ResponseConstraint\ResponseHasHeader($headerName)), $message); + } + + public static function assertResponseHeaderSame(string $headerName, string $expectedValue, string $message = ''): void + { + self::assertThat(static::getResponse(), new ResponseConstraint\ResponseHeaderSame($headerName, $expectedValue), $message); + } + + public static function assertResponseHeaderNotSame(string $headerName, string $expectedValue, string $message = ''): void + { + self::assertThat(static::getResponse(), new LogicalNot(new ResponseConstraint\ResponseHeaderSame($headerName, $expectedValue)), $message); + } + + public static function assertResponseHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void + { + self::assertThat(static::getResponse(), new ResponseConstraint\ResponseHasCookie($name, $path, $domain), $message); + } + + public static function assertResponseNotHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void + { + self::assertThat(static::getResponse(), new LogicalNot(new ResponseConstraint\ResponseHasCookie($name, $path, $domain)), $message); + } + + public static function assertResponseCookieValueSame(string $name, string $expectedValue, string $path = '/', string $domain = null, string $message = ''): void + { + self::assertThat(static::getResponse(), LogicalAnd::fromConstraints( + new ResponseConstraint\ResponseHasCookie($name, $path, $domain), + new ResponseConstraint\ResponseCookieValueSame($name, $expectedValue, $path, $domain) + ), $message); + } + + public static function assertBrowserHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void + { + self::assertThat(static::getClient(), new BrowserKitConstraint\BrowserHasCookie($name, $path, $domain), $message); + } + + public static function assertBrowserNotHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void + { + self::assertThat(static::getClient(), new LogicalNot(new BrowserKitConstraint\BrowserHasCookie($name, $path, $domain)), $message); + } + + public static function assertBrowserCookieValueSame(string $name, string $expectedValue, bool $raw = false, string $path = '/', string $domain = null, string $message = ''): void + { + self::assertThat(static::getClient(), LogicalAnd::fromConstraints( + new BrowserKitConstraint\BrowserHasCookie($name, $path, $domain), + new BrowserKitConstraint\BrowserCookieValueSame($name, $expectedValue, $raw, $path, $domain) + ), $message); + } + + public static function assertSelectorExists(string $selector, string $message = ''): void + { + self::assertThat(static::getCrawler(), new DomCrawlerConstraint\CrawlerSelectorExists($selector), $message); + } + + public static function assertSelectorNotExists(string $selector, string $message = ''): void + { + self::assertThat(static::getCrawler(), new LogicalNot(new DomCrawlerConstraint\CrawlerSelectorExists($selector)), $message); + } + + public static function assertSelectorTextContains(string $selector, string $text, string $message = ''): void + { + self::assertThat(static::getCrawler(), LogicalAnd::fromConstraints( + new DomCrawlerConstraint\CrawlerSelectorExists($selector), + new DomCrawlerConstraint\CrawlerSelectorTextContains($selector, $text) + ), $message); + } + + public static function assertSelectorTextSame(string $selector, string $text, string $message = ''): void + { + self::assertThat(static::getCrawler(), LogicalAnd::fromConstraints( + new DomCrawlerConstraint\CrawlerSelectorExists($selector), + new DomCrawlerConstraint\CrawlerSelectorTextSame($selector, $text) + ), $message); + } + + public static function assertSelectorTextNotContains(string $selector, string $text, string $message = ''): void + { + self::assertThat(static::getCrawler(), LogicalAnd::fromConstraints( + new DomCrawlerConstraint\CrawlerSelectorExists($selector), + new LogicalNot(new DomCrawlerConstraint\CrawlerSelectorTextContains($selector, $text)) + ), $message); + } + + public static function assertPageTitleSame(string $expectedTitle, string $message = ''): void + { + self::assertSelectorTextSame('title', $expectedTitle, $message); + } + + public static function assertPageTitleContains(string $expectedTitle, string $message = ''): void + { + self::assertSelectorTextContains('title', $expectedTitle, $message); + } + + public static function assertInputValueSame(string $fieldName, string $expectedValue, string $message = ''): void + { + self::assertThat(static::getCrawler(), LogicalAnd::fromConstraints( + new DomCrawlerConstraint\CrawlerSelectorExists("input[name=\"$fieldName\"]"), + new DomCrawlerConstraint\CrawlerSelectorAttributeValueSame("input[name=\"$fieldName\"]", 'value', $expectedValue) + ), $message); + } + + public static function assertInputValueNotSame(string $fieldName, string $expectedValue, string $message = ''): void + { + self::assertThat(static::getCrawler(), LogicalAnd::fromConstraints( + new DomCrawlerConstraint\CrawlerSelectorExists("input[name=\"$fieldName\"]"), + new LogicalNot(new DomCrawlerConstraint\CrawlerSelectorAttributeValueSame("input[name=\"$fieldName\"]", 'value', $expectedValue)) + ), $message); + } + + public static function assertRequestAttributeValueSame(string $name, string $expectedValue, string $message = ''): void + { + self::assertThat(static::getRequest(), new ResponseConstraint\RequestAttributeValueSame($name, $expectedValue), $message); + } + + public static function assertRouteSame($expectedRoute, array $parameters = [], string $message = ''): void + { + $constraint = new ResponseConstraint\RequestAttributeValueSame('_route', $expectedRoute); + $constraints = []; + foreach ($parameters as $key => $value) { + $constraints[] = new ResponseConstraint\RequestAttributeValueSame($key, $value); } - } - - public static function assertPageTitleEquals(string $expectedTitle): void - { - $titleNode = static::getCrawler()->filter('title'); - - Assert::assertSame(1, $count = $titleNode->count(), sprintf('There must be one tag in the current page but there is actually %s.', $count)); - - Assert::assertEquals( - $expectedTitle, - trim($title = $titleNode->text()), - sprintf('Expected title "%s" does not equal actual title "%s".', $expectedTitle, $title) - ); - } - - public static function assertPageTitleContains(string $expectedTitle): void - { - $titleNode = static::getCrawler()->filter('title'); - - Assert::assertSame(1, $count = $titleNode->count(), sprintf('There must be one <title> tag in the current page but there is actually %s.', $count)); - - Assert::assertContains( - $expectedTitle, - trim($title = $titleNode->text()), - sprintf('Expected title "%s" does not contain "%s".', $expectedTitle, $title) - ); - } - - public static function assertClientHasCookie(string $name, string $path = '/', string $domain = null): void - { - static::getClientForAssertion(); - - Assert::assertNotNull( - static::$client->getCookieJar()->get($name, $path, $domain), - sprintf('Did not find expected cookie "%s".', $name) - ); - } - - public static function assertClientNotHasCookie(string $name): void - { - static::getClientForAssertion(); - - $cookie = static::$client->getCookieJar()->get($name); - - Assert::assertNull( - $cookie, - sprintf('Cookie "%s" was not expected to be set.', $name) - ); - } - - public static function assertClientCookieValueEquals(string $name, $expectedValue, string $path = '/', string $domain = null): void - { - static::getClientForAssertion(); - - $cookie = static::$client->getCookieJar()->get($name, $path, $domain); - - Assert::assertNotNull( - $cookie, - sprintf('Did not find expected cookie "%s".', $name) - ); - Assert::assertSame( - $expectedValue, - $value = $cookie->getValue(), - sprintf('Cookie name "%s" with value "%s" does not match actual value "%s".', $name, $expectedValue, $value) - ); - } - - public static function assertClientRawCookieValueEquals(string $name, $expectedValue, string $path = '/', string $domain = null): void - { - static::getClientForAssertion(); - - $cookie = static::$client->getCookieJar()->get($name, $path, $domain); - - Assert::assertNotNull( - $cookie, - sprintf('Did not find expected cookie "%s".', $name) - ); - Assert::assertSame( - $expectedValue, - $value = $cookie->getRawValue(), - sprintf('Cookie name "%s" with raw value "%s" does not match actual value "%s".', $name, $expectedValue, $value) - ); - } - - public static function assertResponseHasCookie(string $name, string $path = '/', string $domain = null): void - { - $cookie = static::getResponseCookieFromClient($name, $path, $domain); - - Assert::assertNotNull( - $cookie, - sprintf('Did not find expected cookie "%s".', $name) - ); - } - - public static function assertResponseNotHasCookie(string $name, string $path = '/', string $domain = null): void - { - $cookie = static::getResponseCookieFromClient($name, $path, $domain); - - Assert::assertNull( - $cookie, - sprintf('Cookie "%s" was not expected to be set.', $name) - ); - } - - public static function assertResponseCookieValueEquals(string $name, $expectedValue, string $path = '/', string $domain = null): void - { - $cookie = static::getResponseCookieFromClient($name, $path, $domain); - - Assert::assertNotNull( - $cookie, - sprintf('Did not find expected cookie "%s".', $name) - ); - Assert::assertSame( - $expectedValue, - $value = $cookie->getValue(), - sprintf('Cookie name "%s" with value "%s" does not match actual value "%s".', $name, $expectedValue, $value) - ); - } - - public static function assertResponseCookieValueNotEquals(string $name, $expectedValue, string $path = '/', string $domain = null): void - { - $cookie = static::getResponseCookieFromClient($name, $path, $domain); - - Assert::assertNotNull( - $cookie, - sprintf('Did not find expected cookie "%s".', $name) - ); - Assert::assertNotSame( - $expectedValue, - $value = $cookie->getValue(), - sprintf('Cookie name "%s" with value "%s" was not expected to be equal to actual value "%s".', $name, $expectedValue, $value) - ); - } - - public static function assertSelectorExists(string $selector): void - { - $nodes = static::getCrawler()->filter($selector); - - Assert::assertGreaterThan(0, $nodes->count(), sprintf('Selector "%s" does not resolve to any node.', $selector)); - } - - public static function assertSelectorNotExists(string $selector): void - { - $nodes = static::getCrawler()->filter($selector); - - Assert::assertEquals(0, $count = $nodes->count(), sprintf('Selector "%s" resolves to "%s" nodes where it expected 0.', $selector, $count)); - } - - public static function assertSelectorContainsText(string $selector, string $text): void - { - $nodes = static::getCrawler()->filter($selector); - - Assert::assertGreaterThan(0, $nodes->count(), sprintf('Selector "%s" does not resolve to any node.', $selector)); - - Assert::assertContains($text, $nodes->text(), sprintf('Selector "%s" does not contain text "%s".', $selector, $text)); - } - - public static function assertSelectorNotContainsText(string $selector, string $text): void - { - $nodes = static::getCrawler()->filter($selector); - - Assert::assertGreaterThan(0, $nodes->count(), sprintf('Selector "%s" does not resolve to any node.', $selector)); - - Assert::assertNotContains($text, $nodes->text(), sprintf('Selector "%s" was expected to not contain text "%s".', $selector, $text)); - } - - public static function assertInputValueEquals(string $fieldName, string $expectedValue): void - { - $inputNode = static::getCrawler()->filter("input[name=\"$fieldName\"]"); - - Assert::assertGreaterThan(0, $inputNode->count(), sprintf('Input with name "%s" not found on the page.', $fieldName)); - - Assert::assertEquals( - $expectedValue, - $value = $inputNode->getNode(0)->getAttribute('value'), - sprintf('Expected value "%s" for the "%s" input does not equal the actual value "%s".', $value, $fieldName, $value) - ); - } - - public static function assertInputValueNotEquals(string $fieldName, string $expectedValue): void - { - $inputNode = static::getCrawler()->filter("input[name=\"$fieldName\"]"); - - Assert::assertGreaterThan(0, $inputNode->count(), sprintf('Input with name "%s" not found on the page.', $fieldName)); - - Assert::assertNotEquals( - $expectedValue, - $value = $inputNode->getNode(0)->getAttribute('value'), - sprintf('Expected value "%s" for the "%s" input was expected to not equal the actual value "%s".', $value, $fieldName, $value) - ); - } - - public static function assertRouteEquals($expectedRoute, array $parameters = []): void - { - $request = static::checkRequestAvailable(); - - Assert::assertSame( - $expectedRoute, - $route = $request->attributes->get('_route'), - sprintf('Expected route name "%s" does not match the actual value "%s".', $expectedRoute, $route) - ); - - if (\count($parameters)) { - foreach ($parameters as $key => $expectedValue) { - static::assertRequestAttributeValueEquals($key, $expectedValue); - } + if ($constraints) { + $constraint = LogicalAnd::fromConstraints($constraint, ...$constraints); } + + self::assertThat(static::getRequest(), $constraint, $message); } - public static function assertRequestAttributeValueEquals(string $key, $expectedValue): void + private static function getClient(): KernelBrowser { - $request = static::checkRequestAvailable(); - - Assert::assertSame( - $expectedValue, - $value = $request->attributes->get($key), - sprintf('Expected request attribute "%s" value "%s" does not match actual value "%s".', $key, $expectedValue, $value) - ); - } - - protected static function getResponseCookieFromClient(string $name, string $path = '/', string $domain = null): ?Cookie - { - $cookies = static::getResponse()->headers->getCookies(); - - $filteredCookies = array_filter($cookies, function (Cookie $cookie) use ($name, $path, $domain) { - return - $cookie->getName() === $name - && $cookie->getPath() === $path - && $cookie->getDomain() === $domain - ; - }); - - return reset($filteredCookies) ?: null; - } - - private static function getClientForAssertion(): Client - { - if (!static::$client instanceof Client) { - static::fail(\sprintf( - 'A client must be set to make assertions on it. Did you forget to call "%s::createClient"?', - static::class - )); + if (!static::$client instanceof KernelBrowser) { + static::fail(\sprintf('A client must be set to make assertions on it. Did you forget to call "%s::createClient"?', __CLASS__)); } return static::$client; @@ -350,34 +197,28 @@ trait WebTestAssertions private static function getCrawler(): Crawler { - $client = static::getClientForAssertion(); - - if (!$client->getCrawler()) { + if (!$crawler = static::getClient()->getCrawler()) { static::fail('A client must have a crawler to make assertions. Did you forget to make an HTTP request?'); } - return $client->getCrawler(); + return $crawler; } private static function getResponse(): Response { - $client = static::getClientForAssertion(); - - if (!$client->getResponse()) { + if (!$response = static::getClient()->getResponse()) { static::fail('A client must have an HTTP Response to make assertions. Did you forget to make an HTTP request?'); } - return $client->getResponse(); + return $response; } - private static function checkRequestAvailable(): Request + private static function getRequest(): Request { - $client = static::getClientForAssertion(); - - if (!$client->getRequest()) { + if (!$request = static::getClient()->getRequest()) { static::fail('A client must have an HTTP Request to make assertions. Did you forget to make an HTTP request?'); } - return $client->getRequest(); + return $request; } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php index cf6ab72cc5..aa2b12ea29 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php +++ b/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php @@ -23,12 +23,14 @@ abstract class WebTestCase extends KernelTestCase { use WebTestAssertions; + /** @var Client|null */ + protected static $client; + protected function doTearDown(): void { parent::doTearDown(); - if (static::$client) { - static::$client = null; - } + + static::$client = null; } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Test/WebTestCaseTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Test/WebTestCaseTest.php new file mode 100644 index 0000000000..92f200be1f --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Test/WebTestCaseTest.php @@ -0,0 +1,288 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\Test; + +use PHPUnit\Framework\AssertionFailedError; +use PHPUnit\Framework\TestCase; +use Symfony\Bundle\FrameworkBundle\KernelBrowser; +use Symfony\Bundle\FrameworkBundle\Test\WebTestAssertions; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; +use Symfony\Component\BrowserKit\Cookie; +use Symfony\Component\BrowserKit\CookieJar; +use Symfony\Component\DomCrawler\Crawler; +use Symfony\Component\HttpFoundation\Cookie as HttpFoundationCookie; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; + +class WebTestCaseTest extends TestCase +{ + public function testAssertResponseIsSuccessful() + { + $this->getResponseTester(new Response())->assertResponseIsSuccessful(); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage("Failed asserting that the Response is successful.\nHTTP/1.0 404 Not Found"); + $this->getResponseTester(new Response('', 404))->assertResponseIsSuccessful(); + } + + public function testAssertResponseStatusCodeSame() + { + $this->getResponseTester(new Response())->assertResponseStatusCodeSame(200); + $this->getResponseTester(new Response('', 404))->assertResponseStatusCodeSame(404); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage("Failed asserting that the Response status code is 200.\nHTTP/1.0 404 Not Found"); + $this->getResponseTester(new Response('', 404))->assertResponseStatusCodeSame(200); + } + + public function testAssertResponseRedirects() + { + $this->getResponseTester(new Response('', 301))->assertResponseRedirects(); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage("Failed asserting that the Response is redirected.\nHTTP/1.0 200 OK"); + $this->getResponseTester(new Response())->assertResponseRedirects(); + } + + public function testAssertResponseRedirectsWithLocation() + { + $this->getResponseTester(new Response('', 301, ['Location' => 'https://example.com/']))->assertResponseRedirects('https://example.com/'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('is redirected and has header "Location" with value "https://example.com/".'); + $this->getResponseTester(new Response('', 301))->assertResponseRedirects('https://example.com/'); + } + + public function testAssertResponseRedirectsWithStatusCode() + { + $this->getResponseTester(new Response('', 302))->assertResponseRedirects(null, 302); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('is redirected and status code is 301.'); + $this->getResponseTester(new Response('', 302))->assertResponseRedirects(null, 301); + } + + public function testAssertResponseRedirectsWithLocationAndStatusCode() + { + $this->getResponseTester(new Response('', 302, ['Location' => 'https://example.com/']))->assertResponseRedirects('https://example.com/', 302); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('is redirected and has header "Location" with value "https://example.com/" and status code is 301.'); + $this->getResponseTester(new Response('', 302))->assertResponseRedirects('https://example.com/', 301); + } + + public function testAssertResponseHasHeader() + { + $this->getResponseTester(new Response())->assertResponseHasHeader('Date'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Failed asserting that the Response has header "X-Date".'); + $this->getResponseTester(new Response())->assertResponseHasHeader('X-Date'); + } + + public function testAssertResponseNotHasHeader() + { + $this->getResponseTester(new Response())->assertResponseNotHasHeader('X-Date'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Failed asserting that the Response does not have header "Date".'); + $this->getResponseTester(new Response())->assertResponseNotHasHeader('Date'); + } + + public function testAssertResponseHeaderSame() + { + $this->getResponseTester(new Response())->assertResponseHeaderSame('Cache-Control', 'no-cache, private'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Failed asserting that the Response has header "Cache-Control" with value "public".'); + $this->getResponseTester(new Response())->assertResponseHeaderSame('Cache-Control', 'public'); + } + + public function testAssertResponseHeaderNotSame() + { + $this->getResponseTester(new Response())->assertResponseHeaderNotSame('Cache-Control', 'public'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Failed asserting that the Response does not have header "Cache-Control" with value "no-cache, private".'); + $this->getResponseTester(new Response())->assertResponseHeaderNotSame('Cache-Control', 'no-cache, private'); + } + + public function testAssertResponseHasCookie() + { + $response = new Response(); + $response->headers->setCookie(HttpFoundationCookie::create('foo', 'bar')); + + $this->getResponseTester($response)->assertResponseHasCookie('foo'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Failed asserting that the Response has cookie "bar".'); + $this->getResponseTester($response)->assertResponseHasCookie('bar'); + } + + public function testAssertResponseNotHasCookie() + { + $response = new Response(); + $response->headers->setCookie(HttpFoundationCookie::create('foo', 'bar')); + + $this->getResponseTester($response)->assertResponseNotHasCookie('bar'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Failed asserting that the Response does not have cookie "foo".'); + $this->getResponseTester($response)->assertResponseNotHasCookie('foo'); + } + + public function testAssertResponseCookieValueSame() + { + $response = new Response(); + $response->headers->setCookie(HttpFoundationCookie::create('foo', 'bar')); + + $this->getResponseTester($response)->assertResponseCookieValueSame('foo', 'bar'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('has cookie "bar" and has cookie "bar" with value "bar".'); + $this->getResponseTester($response)->assertResponseCookieValueSame('bar', 'bar'); + } + + public function testAssertBrowserHasCookie() + { + $this->getClientTester()->assertBrowserHasCookie('foo', '/path'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Failed asserting that the Browser has cookie "bar".'); + $this->getClientTester()->assertBrowserHasCookie('bar'); + } + + public function testAssertBrowserNotHasCookie() + { + $this->getClientTester()->assertBrowserNotHasCookie('bar'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Failed asserting that the Browser does not have cookie "foo" with path "/path".'); + $this->getClientTester()->assertBrowserNotHasCookie('foo', '/path'); + } + + public function testAssertBrowserCookieValueSame() + { + $this->getClientTester()->assertBrowserCookieValueSame('foo', 'bar', false, '/path'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('has cookie "foo" with path "/path" and has cookie "foo" with path "/path" with value "babar".'); + $this->getClientTester()->assertBrowserCookieValueSame('foo', 'babar', false, '/path'); + } + + public function testAssertSelectorExists() + { + $this->getCrawlerTester(new Crawler('<html><body><h1>'))->assertSelectorExists('body > h1'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('matches selector "body > h1".'); + $this->getCrawlerTester(new Crawler('<html><head><title>Foo'))->assertSelectorExists('body > h1'); + } + + public function testAssertSelectorNotExists() + { + $this->getCrawlerTester(new Crawler('<html><head><title>Foo'))->assertSelectorNotExists('body > h1'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('does not match selector "body > h1".'); + $this->getCrawlerTester(new Crawler('<html><body><h1>'))->assertSelectorNotExists('body > h1'); + } + + public function testAssertSelectorTextNotContains() + { + $this->getCrawlerTester(new Crawler('<html><body><h1>Foo'))->assertSelectorTextNotContains('body > h1', 'Bar'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('matches selector "body > h1" and does not have a node matching selector "body > h1" with content containing "Foo".'); + $this->getCrawlerTester(new Crawler('<html><body><h1>Foo'))->assertSelectorTextNotContains('body > h1', 'Foo'); + } + + public function testAssertPageTitleSame() + { + $this->getCrawlerTester(new Crawler('<html><head><title>Foo'))->assertPageTitleSame('Foo'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('matches selector "title" and has a node matching selector "title" with content "Bar".'); + $this->getCrawlerTester(new Crawler('<html><head><title>Foo'))->assertPageTitleSame('Bar'); + } + + public function testAssertPageTitleContains() + { + $this->getCrawlerTester(new Crawler('<html><head><title>Foobar'))->assertPageTitleContains('Foo'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('matches selector "title" and has a node matching selector "title" with content containing "Bar".'); + $this->getCrawlerTester(new Crawler('<html><head><title>Foo'))->assertPageTitleContains('Bar'); + } + + public function testAssertInputValueSame() + { + $this->getCrawlerTester(new Crawler('<html><body><form><input type="text" name="username" value="Fabien">'))->assertInputValueSame('username', 'Fabien'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('matches selector "input[name="password"]" and has a node matching selector "input[name="password"]" with attribute "value" of value "pa$$".'); + $this->getCrawlerTester(new Crawler('<html><head><title>Foo'))->assertInputValueSame('password', 'pa$$'); + } + + public function testAssertInputValueNotSame() + { + $this->getCrawlerTester(new Crawler('<html><body><input type="text" name="username" value="Helene">'))->assertInputValueNotSame('username', 'Fabien'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('matches selector "input[name="password"]" and does not have a node matching selector "input[name="password"]" with attribute "value" of value "pa$$".'); + $this->getCrawlerTester(new Crawler('<html><body><form><input type="text" name="password" value="pa$$">'))->assertInputValueNotSame('password', 'pa$$'); + } + + public function testAssertRequestAttributeValueSame() + { + $this->getRequestTester()->assertRequestAttributeValueSame('foo', 'bar'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Failed asserting that the Request has attribute "foo" with value "baz".'); + $this->getRequestTester()->assertRequestAttributeValueSame('foo', 'baz'); + } + + public function testAssertRouteSame() + { + $this->getRequestTester()->assertRouteSame('homepage', ['foo' => 'bar']); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Failed asserting that the Request has attribute "_route" with value "articles".'); + $this->getRequestTester()->assertRouteSame('articles'); + } + + private function getResponseTester(Response $response): WebTestCase + { + $client = $this->createMock(KernelBrowser::class); + $client->expects($this->any())->method('getResponse')->will($this->returnValue($response)); + + return $this->getTester($client); + } + + private function getCrawlerTester(Crawler $crawler): WebTestCase + { + $client = $this->createMock(KernelBrowser::class); + $client->expects($this->any())->method('getCrawler')->will($this->returnValue($crawler)); + + return $this->getTester($client); + } + + private function getClientTester(): WebTestCase + { + $client = $this->createMock(KernelBrowser::class); + $jar = new CookieJar(); + $jar->set(new Cookie('foo', 'bar', null, '/path', 'example.com')); + $client->expects($this->any())->method('getCookieJar')->will($this->returnValue($jar)); + + return $this->getTester($client); + } + + private function getRequestTester(): WebTestCase + { + $client = $this->createMock(KernelBrowser::class); + $request = new Request(); + $request->attributes->set('foo', 'bar'); + $request->attributes->set('_route', 'homepage'); + $client->expects($this->any())->method('getRequest')->will($this->returnValue($request)); + + return $this->getTester($client); + } + + private function getTester(KernelBrowser $client): WebTestCase + { + return new class($client) extends WebTestCase { + use WebTestAssertions; + + protected static $client; + + public function __construct(KernelBrowser $client) + { + static::$client = $client; + } + }; + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 3e406515a9..1b8ffc1e66 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -36,7 +36,7 @@ "symfony/browser-kit": "^4.3", "symfony/console": "^4.3", "symfony/css-selector": "~3.4|~4.0", - "symfony/dom-crawler": "~3.4|~4.0", + "symfony/dom-crawler": "^4.3", "symfony/polyfill-intl-icu": "~1.0", "symfony/security": "~3.4|~4.0", "symfony/form": "^4.3", @@ -72,6 +72,7 @@ "symfony/browser-kit": "<4.3", "symfony/console": "<4.3", "symfony/dotenv": "<4.2", + "symfony/dom-crawler": "<4.3", "symfony/form": "<4.3", "symfony/messenger": "<4.3", "symfony/property-info": "<3.4", diff --git a/src/Symfony/Component/BrowserKit/CHANGELOG.md b/src/Symfony/Component/BrowserKit/CHANGELOG.md index b966974d8d..323166a3d6 100644 --- a/src/Symfony/Component/BrowserKit/CHANGELOG.md +++ b/src/Symfony/Component/BrowserKit/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 4.3.0 ----- + * Added PHPUnit constraints: `BrowserCookieValueSame` and `BrowserHasCookie` * Added `HttpBrowser`, an implementation of a browser with the HttpClient component * Renamed `Client` to `AbstractBrowser` * Marked `Response` final. diff --git a/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserCookieValueSame.php b/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserCookieValueSame.php new file mode 100644 index 0000000000..f3103242c2 --- /dev/null +++ b/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserCookieValueSame.php @@ -0,0 +1,75 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\BrowserKit\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\BrowserKit\AbstractBrowser; + +final class BrowserCookieValueSame extends Constraint +{ + private $name; + private $value; + private $raw; + private $path; + private $domain; + + public function __construct(string $name, string $value, bool $raw = false, string $path = '/', string $domain = null) + { + $this->name = $name; + $this->path = $path; + $this->domain = $domain; + $this->value = $value; + $this->raw = $raw; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + $str = sprintf('has cookie "%s"', $this->name); + if ('/' !== $this->path) { + $str .= sprintf(' with path "%s"', $this->path); + } + if ($this->domain) { + $str .= sprintf(' for domain "%s"', $this->domain); + } + $str .= sprintf(' with %svalue "%s"', $this->raw ? 'raw ' : '', $this->value); + + return $str; + } + + /** + * @param AbstractBrowser $browser + * + * {@inheritdoc} + */ + protected function matches($browser): bool + { + $cookie = $browser->getCookieJar()->get($this->name, $this->path, $this->domain); + if (!$cookie) { + return false; + } + + return $this->value === ($this->raw ? $cookie->getRawValue() : $cookie->getValue()); + } + + /** + * @param AbstractBrowser $browser + * + * {@inheritdoc} + */ + protected function failureDescription($browser): string + { + return 'the Browser '.$this->toString(); + } +} diff --git a/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserHasCookie.php b/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserHasCookie.php new file mode 100644 index 0000000000..2b84a5e9b9 --- /dev/null +++ b/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserHasCookie.php @@ -0,0 +1,65 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\BrowserKit\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\BrowserKit\AbstractBrowser; + +final class BrowserHasCookie extends Constraint +{ + private $name; + private $path; + private $domain; + + public function __construct(string $name, string $path = '/', string $domain = null) + { + $this->name = $name; + $this->path = $path; + $this->domain = $domain; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + $str = sprintf('has cookie "%s"', $this->name); + if ('/' !== $this->path) { + $str .= sprintf(' with path "%s"', $this->path); + } + if ($this->domain) { + $str .= sprintf(' for domain "%s"', $this->domain); + } + + return $str; + } + + /** + * @param AbstractBrowser $browser + * + * {@inheritdoc} + */ + protected function matches($browser): bool + { + return null !== $browser->getCookieJar()->get($this->name, $this->path, $this->domain); + } + + /** + * @param AbstractBrowser $browser + * + * {@inheritdoc} + */ + protected function failureDescription($browser): string + { + return 'the Browser '.$this->toString(); + } +} diff --git a/src/Symfony/Component/BrowserKit/Tests/Test/Constraint/BrowserCookieValueSameTest.php b/src/Symfony/Component/BrowserKit/Tests/Test/Constraint/BrowserCookieValueSameTest.php new file mode 100644 index 0000000000..ea27473cdb --- /dev/null +++ b/src/Symfony/Component/BrowserKit/Tests/Test/Constraint/BrowserCookieValueSameTest.php @@ -0,0 +1,54 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\BrowserKit\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\BrowserKit\AbstractBrowser; +use Symfony\Component\BrowserKit\Cookie; +use Symfony\Component\BrowserKit\CookieJar; +use Symfony\Component\BrowserKit\Test\Constraint\BrowserCookieValueSame; + +class BrowserCookieValueSameTest extends TestCase +{ + public function testConstraint(): void + { + $browser = $this->getBrowser(); + $constraint = new BrowserCookieValueSame('foo', 'bar', false, '/path'); + $this->assertTrue($constraint->evaluate($browser, '', true)); + $constraint = new BrowserCookieValueSame('foo', 'bar', true, '/path'); + $this->assertTrue($constraint->evaluate($browser, '', true)); + $constraint = new BrowserCookieValueSame('foo', 'babar', false, '/path'); + $this->assertFalse($constraint->evaluate($browser, '', true)); + + try { + $constraint->evaluate($browser); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Browser has cookie \"foo\" with path \"/path\" with value \"babar\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } + + private function getBrowser(): AbstractBrowser + { + $browser = $this->createMock(AbstractBrowser::class); + $jar = new CookieJar(); + $jar->set(new Cookie('foo', 'bar', null, '/path', 'example.com')); + $browser->expects($this->any())->method('getCookieJar')->will($this->returnValue($jar)); + + return $browser; + } +} diff --git a/src/Symfony/Component/BrowserKit/Tests/Test/Constraint/BrowserHasCookieTest.php b/src/Symfony/Component/BrowserKit/Tests/Test/Constraint/BrowserHasCookieTest.php new file mode 100644 index 0000000000..2f40c0257f --- /dev/null +++ b/src/Symfony/Component/BrowserKit/Tests/Test/Constraint/BrowserHasCookieTest.php @@ -0,0 +1,84 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\BrowserKit\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\BrowserKit\AbstractBrowser; +use Symfony\Component\BrowserKit\Cookie; +use Symfony\Component\BrowserKit\CookieJar; +use Symfony\Component\BrowserKit\Test\Constraint\BrowserHasCookie; + +class BrowserHasCookieTest extends TestCase +{ + public function testConstraint(): void + { + $browser = $this->getBrowser(); + $constraint = new BrowserHasCookie('foo', '/path'); + $this->assertTrue($constraint->evaluate($browser, '', true)); + $constraint = new BrowserHasCookie('foo', '/path', 'example.com'); + $this->assertTrue($constraint->evaluate($browser, '', true)); + $constraint = new BrowserHasCookie('bar'); + $this->assertFalse($constraint->evaluate($browser, '', true)); + + try { + $constraint->evaluate($browser); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Browser has cookie \"bar\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } + + public function testConstraintWithWrongPath(): void + { + $browser = $this->getBrowser(); + $constraint = new BrowserHasCookie('foo', '/other'); + try { + $constraint->evaluate($browser); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Browser has cookie \"foo\" with path \"/other\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } + + public function testConstraintWithWrongDomain(): void + { + $browser = $this->getBrowser(); + $constraint = new BrowserHasCookie('foo', '/path', 'example.org'); + try { + $constraint->evaluate($browser); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Browser has cookie \"foo\" with path \"/path\" for domain \"example.org\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } + + private function getBrowser(): AbstractBrowser + { + $browser = $this->createMock(AbstractBrowser::class); + $jar = new CookieJar(); + $jar->set(new Cookie('foo', 'bar', null, '/path', 'example.com')); + $browser->expects($this->any())->method('getCookieJar')->will($this->returnValue($jar)); + + return $browser; + } +} diff --git a/src/Symfony/Component/DomCrawler/CHANGELOG.md b/src/Symfony/Component/DomCrawler/CHANGELOG.md index fae5bd3f1d..4b79e96f7c 100644 --- a/src/Symfony/Component/DomCrawler/CHANGELOG.md +++ b/src/Symfony/Component/DomCrawler/CHANGELOG.md @@ -4,6 +4,8 @@ CHANGELOG 4.3.0 ----- +* Added PHPUnit constraints: `CrawlerSelectorAttributeValueSame`, `CrawlerSelectorExists`, `CrawlerSelectorTextContains`` + and `CrawlerSelectorTextSame` * Added return of element name (`_name`) in `extract()` method. * Added ability to return a default value in `text()` and `html()` instead of throwing an exception when node is empty. diff --git a/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorAttributeValueSame.php b/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorAttributeValueSame.php new file mode 100644 index 0000000000..962b6bf0b1 --- /dev/null +++ b/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorAttributeValueSame.php @@ -0,0 +1,62 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\DomCrawler\Crawler; + +final class CrawlerSelectorAttributeValueSame extends Constraint +{ + private $selector; + private $attribute; + private $expectedText; + + public function __construct(string $selector, string $attribute, string $expectedText) + { + $this->selector = $selector; + $this->attribute = $attribute; + $this->expectedText = $expectedText; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return sprintf('has a node matching selector "%s" with attribute "%s" of value "%s"', $this->selector, $this->attribute, $this->expectedText); + } + + /** + * @param Crawler $crawler + * + * {@inheritdoc} + */ + protected function matches($crawler): bool + { + $crawler = $crawler->filter($this->selector); + if (!\count($crawler)) { + return false; + } + + return $this->expectedText === trim($crawler->getNode(0)->getAttribute($this->attribute)); + } + + /** + * @param Crawler $crawler + * + * {@inheritdoc} + */ + protected function failureDescription($crawler): string + { + return 'the Crawler '.$this->toString(); + } +} diff --git a/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorExists.php b/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorExists.php new file mode 100644 index 0000000000..112b772b13 --- /dev/null +++ b/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorExists.php @@ -0,0 +1,53 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\DomCrawler\Crawler; + +final class CrawlerSelectorExists extends Constraint +{ + private $selector; + + public function __construct(string $selector) + { + $this->selector = $selector; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return sprintf('matches selector "%s"', $this->selector); + } + + /** + * @param Crawler $crawler + * + * {@inheritdoc} + */ + protected function matches($crawler): bool + { + return 0 < \count($crawler->filter($this->selector)); + } + + /** + * @param Crawler $crawler + * + * {@inheritdoc} + */ + protected function failureDescription($crawler): string + { + return 'the Crawler '.$this->toString(); + } +} diff --git a/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorTextContains.php b/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorTextContains.php new file mode 100644 index 0000000000..260ec57b07 --- /dev/null +++ b/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorTextContains.php @@ -0,0 +1,60 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\DomCrawler\Crawler; + +final class CrawlerSelectorTextContains extends Constraint +{ + private $selector; + private $expectedText; + + public function __construct(string $selector, string $expectedText) + { + $this->selector = $selector; + $this->expectedText = $expectedText; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return sprintf('has a node matching selector "%s" with content containing "%s"', $this->selector, $this->expectedText); + } + + /** + * @param Crawler $crawler + * + * {@inheritdoc} + */ + protected function matches($crawler): bool + { + $crawler = $crawler->filter($this->selector); + if (!\count($crawler)) { + return false; + } + + return false !== \mb_strpos($crawler->text(), $this->expectedText); + } + + /** + * @param Crawler $crawler + * + * {@inheritdoc} + */ + protected function failureDescription($crawler): string + { + return 'the Crawler '.$this->toString(); + } +} diff --git a/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorTextSame.php b/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorTextSame.php new file mode 100644 index 0000000000..30271f0191 --- /dev/null +++ b/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorTextSame.php @@ -0,0 +1,60 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\DomCrawler\Crawler; + +final class CrawlerSelectorTextSame extends Constraint +{ + private $selector; + private $expectedText; + + public function __construct(string $selector, string $expectedText) + { + $this->selector = $selector; + $this->expectedText = $expectedText; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return sprintf('has a node matching selector "%s" with content "%s"', $this->selector, $this->expectedText); + } + + /** + * @param Crawler $crawler + * + * {@inheritdoc} + */ + protected function matches($crawler): bool + { + $crawler = $crawler->filter($this->selector); + if (!\count($crawler)) { + return false; + } + + return $this->expectedText === trim($crawler->text()); + } + + /** + * @param Crawler $crawler + * + * {@inheritdoc} + */ + protected function failureDescription($crawler): string + { + return 'the Crawler '.$this->toString(); + } +} diff --git a/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorAttributeValueSameTest.php b/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorAttributeValueSameTest.php new file mode 100644 index 0000000000..9a3716d64f --- /dev/null +++ b/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorAttributeValueSameTest.php @@ -0,0 +1,38 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\DomCrawler\Crawler; +use Symfony\Component\DomCrawler\Test\Constraint\CrawlerSelectorAttributeValueSame; + +class CrawlerSelectorAttributeValueSameTest extends TestCase +{ + public function testConstraint(): void + { + $constraint = new CrawlerSelectorAttributeValueSame('input[name="username"]', 'value', 'Fabien'); + $this->assertTrue($constraint->evaluate(new Crawler('<html><body><form><input type="text" name="username" value="Fabien">'), '', true)); + $this->assertFalse($constraint->evaluate(new Crawler('<html><head><title>Bar'), '', true)); + + try { + $constraint->evaluate(new Crawler('<html><head><title>Bar')); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Crawler has a node matching selector \"input[name=\"username\"]\" with attribute \"value\" of value \"Fabien\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorExistsTest.php b/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorExistsTest.php new file mode 100644 index 0000000000..f80bd66706 --- /dev/null +++ b/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorExistsTest.php @@ -0,0 +1,39 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\DomCrawler\Crawler; +use Symfony\Component\DomCrawler\Test\Constraint\CrawlerSelectorExists; + +class CrawlerSelectorExistsTest extends TestCase +{ + public function testConstraint(): void + { + $constraint = new CrawlerSelectorExists('title'); + $this->assertTrue($constraint->evaluate(new Crawler('<html><head><title>'), '', true)); + $constraint = new CrawlerSelectorExists('h1'); + $this->assertFalse($constraint->evaluate(new Crawler('<html><head><title>'), '', true)); + + try { + $constraint->evaluate(new Crawler('<html><head><title>')); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Crawler matches selector \"h1\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorTextContainsTest.php b/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorTextContainsTest.php new file mode 100644 index 0000000000..d61647c388 --- /dev/null +++ b/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorTextContainsTest.php @@ -0,0 +1,38 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\DomCrawler\Crawler; +use Symfony\Component\DomCrawler\Test\Constraint\CrawlerSelectorTextContains; + +class CrawlerSelectorTextContainsTest extends TestCase +{ + public function testConstraint(): void + { + $constraint = new CrawlerSelectorTextContains('title', 'Foo'); + $this->assertTrue($constraint->evaluate(new Crawler('<html><head><title>Foobar'), '', true)); + $this->assertFalse($constraint->evaluate(new Crawler('<html><head><title>Bar'), '', true)); + + try { + $constraint->evaluate(new Crawler('<html><head><title>Bar')); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Crawler has a node matching selector \"title\" with content containing \"Foo\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorTextSameTest.php b/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorTextSameTest.php new file mode 100644 index 0000000000..f394abbc26 --- /dev/null +++ b/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorTextSameTest.php @@ -0,0 +1,38 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\DomCrawler\Crawler; +use Symfony\Component\DomCrawler\Test\Constraint\CrawlerSelectorTextSame; + +class CrawlerSelectorTextSameTest extends TestCase +{ + public function testConstraint(): void + { + $constraint = new CrawlerSelectorTextSame('title', 'Foo'); + $this->assertTrue($constraint->evaluate(new Crawler('<html><head><title>Foo'), '', true)); + $this->assertFalse($constraint->evaluate(new Crawler('<html><head><title>Bar'), '', true)); + + try { + $constraint->evaluate(new Crawler('<html><head><title>Bar')); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Crawler has a node matching selector \"title\" with content \"Foo\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/src/Symfony/Component/Form/Test/TestCaseSetUpTearDownTrait.php b/src/Symfony/Component/Form/Test/TestCaseSetUpTearDownTrait.php index c7d785e0a8..30d41059b2 100644 --- a/src/Symfony/Component/Form/Test/TestCaseSetUpTearDownTrait.php +++ b/src/Symfony/Component/Form/Test/TestCaseSetUpTearDownTrait.php @@ -45,11 +45,17 @@ if ((new \ReflectionMethod(TestCase::class, 'tearDown'))->hasReturnType()) { */ trait TestCaseSetUpTearDownTrait { - private function doSetUp(): void + /** + * @return void + */ + private function doSetUp() { } - private function doTearDown(): void + /** + * @return void + */ + private function doTearDown() { } diff --git a/src/Symfony/Component/HttpFoundation/CHANGELOG.md b/src/Symfony/Component/HttpFoundation/CHANGELOG.md index 5ce8df848b..17a0dcc721 100644 --- a/src/Symfony/Component/HttpFoundation/CHANGELOG.md +++ b/src/Symfony/Component/HttpFoundation/CHANGELOG.md @@ -4,6 +4,8 @@ CHANGELOG 4.3.0 ----- + * added PHPUnit constraints: `RequestAttributeValueSame`, `ResponseCookieValueSame`, `ResponseHasCookie`, + `ResponseHasHeader`, `ResponseHeaderSame`, `ResponseIsRedirected`, `ResponseIsSuccessful`, and `ResponseStatusCodeSame` * deprecated `MimeTypeGuesserInterface` and `ExtensionGuesserInterface` in favor of `Symfony\Component\Mime\MimeTypesInterface`. * deprecated `MimeType` and `MimeTypeExtensionGuesser` in favor of `Symfony\Component\Mime\MimeTypes`. * deprecated `FileBinaryMimeTypeGuesser` in favor of `Symfony\Component\Mime\FileBinaryMimeTypeGuesser`. diff --git a/src/Symfony/Component/HttpFoundation/Test/Constraint/RequestAttributeValueSame.php b/src/Symfony/Component/HttpFoundation/Test/Constraint/RequestAttributeValueSame.php new file mode 100644 index 0000000000..2d10562786 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Test/Constraint/RequestAttributeValueSame.php @@ -0,0 +1,54 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; + +final class RequestAttributeValueSame extends Constraint +{ + private $name; + private $value; + + public function __construct(string $name, string $value) + { + $this->name = $name; + $this->value = $value; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return sprintf('has attribute "%s" with value "%s"', $this->name, $this->value); + } + + /** + * @param Request $request + * + * {@inheritdoc} + */ + protected function matches($request): bool + { + return $this->value === $request->attributes->get($this->name); + } + + /** + * @param Request $request + * + * {@inheritdoc} + */ + protected function failureDescription($request): string + { + return 'the Request '.$this->toString(); + } +} diff --git a/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseCookieValueSame.php b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseCookieValueSame.php new file mode 100644 index 0000000000..554e1a1602 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseCookieValueSame.php @@ -0,0 +1,85 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\HttpFoundation\Cookie; +use Symfony\Component\HttpFoundation\Response; + +final class ResponseCookieValueSame extends Constraint +{ + private $name; + private $value; + private $path; + private $domain; + + public function __construct(string $name, string $value, string $path = '/', string $domain = null) + { + $this->name = $name; + $this->value = $value; + $this->path = $path; + $this->domain = $domain; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + $str = sprintf('has cookie "%s"', $this->name); + if ('/' !== $this->path) { + $str .= sprintf(' with path "%s"', $this->path); + } + if ($this->domain) { + $str .= sprintf(' for domain "%s"', $this->domain); + } + $str .= sprintf(' with value "%s"', $this->value); + + return $str; + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function matches($response): bool + { + $cookie = $this->getCookie($response); + if (!$cookie) { + return false; + } + + return $this->value === $cookie->getValue(); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function failureDescription($response): string + { + return 'the Response '.$this->toString(); + } + + protected function getCookie(Response $response): ?Cookie + { + $cookies = $response->headers->getCookies(); + + $filteredCookies = array_filter($cookies, function (Cookie $cookie) { + return $cookie->getName() === $this->name && $cookie->getPath() === $this->path && $cookie->getDomain() === $this->domain; + }); + + return reset($filteredCookies) ?: null; + } +} diff --git a/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseHasCookie.php b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseHasCookie.php new file mode 100644 index 0000000000..bd792b0d87 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseHasCookie.php @@ -0,0 +1,77 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\HttpFoundation\Cookie; +use Symfony\Component\HttpFoundation\Response; + +final class ResponseHasCookie extends Constraint +{ + private $name; + private $path; + private $domain; + + public function __construct(string $name, string $path = '/', string $domain = null) + { + $this->name = $name; + $this->path = $path; + $this->domain = $domain; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + $str = sprintf('has cookie "%s"', $this->name); + if ('/' !== $this->path) { + $str .= sprintf(' with path "%s"', $this->path); + } + if ($this->domain) { + $str .= sprintf(' for domain "%s"', $this->domain); + } + + return $str; + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function matches($response): bool + { + return null !== $this->getCookie($response); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function failureDescription($response): string + { + return 'the Response '.$this->toString(); + } + + protected function getCookie(Response $response): ?Cookie + { + $cookies = $response->headers->getCookies(); + + $filteredCookies = array_filter($cookies, function (Cookie $cookie) { + return $cookie->getName() === $this->name && $cookie->getPath() === $this->path && $cookie->getDomain() === $this->domain; + }); + + return reset($filteredCookies) ?: null; + } +} diff --git a/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseHasHeader.php b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseHasHeader.php new file mode 100644 index 0000000000..68ad8273fd --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseHasHeader.php @@ -0,0 +1,53 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\HttpFoundation\Response; + +final class ResponseHasHeader extends Constraint +{ + private $headerName; + + public function __construct(string $headerName) + { + $this->headerName = $headerName; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return sprintf('has header "%s"', $this->headerName); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function matches($response): bool + { + return $response->headers->has($this->headerName); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function failureDescription($response): string + { + return 'the Response '.$this->toString(); + } +} diff --git a/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseHeaderSame.php b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseHeaderSame.php new file mode 100644 index 0000000000..acdea71d15 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseHeaderSame.php @@ -0,0 +1,55 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\HttpFoundation\Response; + +final class ResponseHeaderSame extends Constraint +{ + private $headerName; + private $expectedValue; + + public function __construct(string $headerName, string $expectedValue) + { + $this->headerName = $headerName; + $this->expectedValue = $expectedValue; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return sprintf('has header "%s" with value "%s"', $this->headerName, $this->expectedValue); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function matches($response): bool + { + return $this->expectedValue === $response->headers->get($this->headerName, null, true); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function failureDescription($response): string + { + return 'the Response '.$this->toString(); + } +} diff --git a/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseIsRedirected.php b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseIsRedirected.php new file mode 100644 index 0000000000..8c4b883f0b --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseIsRedirected.php @@ -0,0 +1,56 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\HttpFoundation\Response; + +final class ResponseIsRedirected extends Constraint +{ + /** + * {@inheritdoc} + */ + public function toString(): string + { + return 'is redirected'; + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function matches($response): bool + { + return $response->isRedirect(); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function failureDescription($response): string + { + return 'the Response '.$this->toString(); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function additionalFailureDescription($response): string + { + return (string) $response; + } +} diff --git a/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseIsSuccessful.php b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseIsSuccessful.php new file mode 100644 index 0000000000..9c66558907 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseIsSuccessful.php @@ -0,0 +1,56 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\HttpFoundation\Response; + +final class ResponseIsSuccessful extends Constraint +{ + /** + * {@inheritdoc} + */ + public function toString(): string + { + return 'is successful'; + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function matches($response): bool + { + return $response->isSuccessful(); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function failureDescription($response): string + { + return 'the Response '.$this->toString(); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function additionalFailureDescription($response): string + { + return (string) $response; + } +} diff --git a/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseStatusCodeSame.php b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseStatusCodeSame.php new file mode 100644 index 0000000000..72bb000b85 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseStatusCodeSame.php @@ -0,0 +1,63 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\HttpFoundation\Response; + +final class ResponseStatusCodeSame extends Constraint +{ + private $statusCode; + + public function __construct(int $statusCode) + { + $this->statusCode = $statusCode; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return 'status code is '.$this->statusCode; + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function matches($response): bool + { + return $this->statusCode === $response->getStatusCode(); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function failureDescription($response): string + { + return 'the Response '.$this->toString(); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function additionalFailureDescription($response): string + { + return (string) $response; + } +} diff --git a/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/RequestAttributeValueSameTest.php b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/RequestAttributeValueSameTest.php new file mode 100644 index 0000000000..eca8aed263 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/RequestAttributeValueSameTest.php @@ -0,0 +1,41 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Test\Constraint\RequestAttributeValueSame; + +class RequestAttributeValueSameTest extends TestCase +{ + public function testConstraint(): void + { + $request = new Request(); + $request->attributes->set('foo', 'bar'); + $constraint = new RequestAttributeValueSame('foo', 'bar'); + $this->assertTrue($constraint->evaluate($request, '', true)); + $constraint = new RequestAttributeValueSame('bar', 'foo'); + $this->assertFalse($constraint->evaluate($request, '', true)); + + try { + $constraint->evaluate($request); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Request has attribute \"bar\" with value \"foo\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseCookieValueSameTest.php b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseCookieValueSameTest.php new file mode 100644 index 0000000000..778879c328 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseCookieValueSameTest.php @@ -0,0 +1,44 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\HttpFoundation\Cookie; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Test\Constraint\ResponseCookieValueSame; + +class ResponseCookieValueSameTest extends TestCase +{ + public function testConstraint(): void + { + $response = new Response(); + $response->headers->setCookie(Cookie::create('foo', 'bar', 0, '/path')); + $constraint = new ResponseCookieValueSame('foo', 'bar', '/path'); + $this->assertTrue($constraint->evaluate($response, '', true)); + $constraint = new ResponseCookieValueSame('foo', 'bar', '/path'); + $this->assertTrue($constraint->evaluate($response, '', true)); + $constraint = new ResponseCookieValueSame('foo', 'babar', '/path'); + $this->assertFalse($constraint->evaluate($response, '', true)); + + try { + $constraint->evaluate($response); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Response has cookie \"foo\" with path \"/path\" with value \"babar\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseHasCookieTest.php b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseHasCookieTest.php new file mode 100644 index 0000000000..05ca95fb46 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseHasCookieTest.php @@ -0,0 +1,42 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\HttpFoundation\Cookie; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Test\Constraint\ResponseHasCookie; + +class ResponseHasCookieTest extends TestCase +{ + public function testConstraint(): void + { + $response = new Response(); + $response->headers->setCookie(Cookie::create('foo', 'bar')); + $constraint = new ResponseHasCookie('foo'); + $this->assertTrue($constraint->evaluate($response, '', true)); + $constraint = new ResponseHasCookie('bar'); + $this->assertFalse($constraint->evaluate($response, '', true)); + + try { + $constraint->evaluate($response); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Response has cookie \"bar\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseHasHeaderTest.php b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseHasHeaderTest.php new file mode 100644 index 0000000000..7b811a64a2 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseHasHeaderTest.php @@ -0,0 +1,39 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Test\Constraint\ResponseHasHeader; + +class ResponseHasHeaderTest extends TestCase +{ + public function testConstraint(): void + { + $constraint = new ResponseHasHeader('Date'); + $this->assertTrue($constraint->evaluate(new Response(), '', true)); + $constraint = new ResponseHasHeader('X-Date'); + $this->assertFalse($constraint->evaluate(new Response(), '', true)); + + try { + $constraint->evaluate(new Response()); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Response has header \"X-Date\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseHeaderSameTest.php b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseHeaderSameTest.php new file mode 100644 index 0000000000..d527f35de8 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseHeaderSameTest.php @@ -0,0 +1,39 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Test\Constraint\ResponseHeaderSame; + +class ResponseHeaderSameTest extends TestCase +{ + public function testConstraint(): void + { + $constraint = new ResponseHeaderSame('Cache-Control', 'no-cache, private'); + $this->assertTrue($constraint->evaluate(new Response(), '', true)); + $constraint = new ResponseHeaderSame('Cache-Control', 'public'); + $this->assertFalse($constraint->evaluate(new Response(), '', true)); + + try { + $constraint->evaluate(new Response()); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Response has header \"Cache-Control\" with value \"public\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseIsRedirectedTest.php b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseIsRedirectedTest.php new file mode 100644 index 0000000000..a3a460636a --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseIsRedirectedTest.php @@ -0,0 +1,39 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Test\Constraint\ResponseIsRedirected; + +class ResponseIsRedirectedTest extends TestCase +{ + public function testConstraint(): void + { + $constraint = new ResponseIsRedirected(); + + $this->assertTrue($constraint->evaluate(new Response('', 301), '', true)); + $this->assertFalse($constraint->evaluate(new Response(), '', true)); + + try { + $constraint->evaluate(new Response()); + } catch (ExpectationFailedException $e) { + $this->assertContains("Failed asserting that the Response is redirected.\nHTTP/1.0 200 OK", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseIsSuccessfulTest.php b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseIsSuccessfulTest.php new file mode 100644 index 0000000000..0c99a5e484 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseIsSuccessfulTest.php @@ -0,0 +1,39 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Test\Constraint\ResponseIsSuccessful; + +class ResponseIsSuccessfulTest extends TestCase +{ + public function testConstraint(): void + { + $constraint = new ResponseIsSuccessful(); + + $this->assertTrue($constraint->evaluate(new Response(), '', true)); + $this->assertFalse($constraint->evaluate(new Response('', 404), '', true)); + + try { + $constraint->evaluate(new Response('', 404)); + } catch (ExpectationFailedException $e) { + $this->assertContains("Failed asserting that the Response is successful.\nHTTP/1.0 404 Not Found", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseStatusCodeSameTest.php b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseStatusCodeSameTest.php new file mode 100644 index 0000000000..3e15e90673 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseStatusCodeSameTest.php @@ -0,0 +1,41 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Test\Constraint\ResponseStatusCodeSame; + +class ResponseStatusCodeSameTest extends TestCase +{ + public function testConstraint(): void + { + $constraint = new ResponseStatusCodeSame(200); + $this->assertTrue($constraint->evaluate(new Response(), '', true)); + $this->assertFalse($constraint->evaluate(new Response('', 404), '', true)); + $constraint = new ResponseStatusCodeSame(404); + $this->assertTrue($constraint->evaluate(new Response('', 404), '', true)); + + $constraint = new ResponseStatusCodeSame(200); + try { + $constraint->evaluate(new Response('', 404)); + } catch (ExpectationFailedException $e) { + $this->assertContains("Failed asserting that the Response status code is 200.\nHTTP/1.0 404 Not Found", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/src/Symfony/Component/Validator/Test/TestCaseSetUpTearDownTrait.php b/src/Symfony/Component/Validator/Test/TestCaseSetUpTearDownTrait.php index ad8d38c97f..be05bbb33f 100644 --- a/src/Symfony/Component/Validator/Test/TestCaseSetUpTearDownTrait.php +++ b/src/Symfony/Component/Validator/Test/TestCaseSetUpTearDownTrait.php @@ -45,11 +45,17 @@ if ((new \ReflectionMethod(TestCase::class, 'tearDown'))->hasReturnType()) { */ trait TestCaseSetUpTearDownTrait { - private function doSetUp(): void + /** + * @return void + */ + private function doSetUp() { } - private function doTearDown(): void + /** + * @return void + */ + private function doTearDown() { }