Loading core/tests/Drupal/FunctionalTests/WebAssertTest.php→core/tests/Drupal/Tests/Core/Test/WebAssertTest.php +124 −47 Original line number Diff line number Diff line Loading @@ -2,35 +2,70 @@ declare(strict_types=1); namespace Drupal\FunctionalTests; namespace Drupal\Tests\Core\Test; use Behat\Mink\Driver\BrowserKitDriver; use Behat\Mink\Exception\ExpectationException; use Behat\Mink\Exception\ResponseTextException; use Behat\Mink\Session; use Drupal\Component\Utility\Html; use Drupal\Core\Url; use Drupal\Tests\BrowserTestBase; use Behat\Mink\Exception\ResponseTextException; use Drupal\Tests\UnitTestCase; use Drupal\Tests\WebAssert; use PHPUnit\Framework\AssertionFailedError; use Symfony\Component\BrowserKit\AbstractBrowser; use Symfony\Component\BrowserKit\Response; /** * Tests WebAssert functionality. * * @group browsertestbase * @group #slow * @coversDefaultClass \Drupal\Tests\WebAssert */ class WebAssertTest extends BrowserTestBase { class WebAssertTest extends UnitTestCase { /** * {@inheritdoc} * Session mock. */ protected Session $session; /** * Client mock. */ protected static $modules = [ 'test_page_test', ]; protected AbstractBrowser $client; /** * {@inheritdoc} */ protected $defaultTheme = 'stark'; public function setUp(): void { parent::setUp(); $this->client = new MockClient(); $driver = new BrowserKitDriver($this->client); $this->session = new Session($driver); } /** * Get the mocked session. */ protected function assertSession(): WebAssert { return new WebAssert($this->session); } /** * Simulate a page visit and expect a response. * * @param string $uri * The URI to visit. This is only required if assertions are made about the * URL, otherwise it can be left empty. * @param string $content * The expected response content. * @param array $responseHeaders * The expected response headers. */ protected function visit(string $uri = '', string $content = '', array $responseHeaders = []): void { $this->client->setExpectedResponse(new Response($content, 200, $responseHeaders)); $this->session->visit($uri); } /** * Tests WebAssert::responseHeaderExists(). Loading @@ -38,9 +73,8 @@ class WebAssertTest extends BrowserTestBase { * @covers ::responseHeaderExists */ public function testResponseHeaderExists(): void { $this->drupalGet('test-null-header'); $this->visit('', '', ['Null-Header' => '']); $this->assertSession()->responseHeaderExists('Null-Header'); $this->expectException(AssertionFailedError::class); $this->expectExceptionMessage("Failed asserting that the response has a 'does-not-exist' header."); $this->assertSession()->responseHeaderExists('does-not-exist'); Loading @@ -52,7 +86,7 @@ public function testResponseHeaderExists(): void { * @covers ::responseHeaderDoesNotExist */ public function testResponseHeaderDoesNotExist(): void { $this->drupalGet('test-null-header'); $this->visit('', '', ['Null-Header' => '']); $this->assertSession()->responseHeaderDoesNotExist('does-not-exist'); $this->expectException(AssertionFailedError::class); Loading @@ -64,10 +98,7 @@ public function testResponseHeaderDoesNotExist(): void { * @covers ::pageTextMatchesCount */ public function testPageTextMatchesCount(): void { $this->drupalLogin($this->drupalCreateUser()); // Visit a Drupal page that requires login. $this->drupalGet('test-page'); $this->visit('', 'Test page text. <a href="#">Foo</a>'); $this->assertSession()->pageTextMatchesCount(1, '/Test page text\./'); $this->expectException(AssertionFailedError::class); Loading @@ -79,10 +110,7 @@ public function testPageTextMatchesCount(): void { * @covers ::pageTextContainsOnce */ public function testPageTextContainsOnce(): void { $this->drupalLogin($this->drupalCreateUser()); // Visit a Drupal page that requires login. $this->drupalGet('test-page'); $this->visit('', 'Test page text. <a href="#">Foo</a>'); $this->assertSession()->pageTextContainsOnce('Test page text.'); $this->expectException(ResponseTextException::class); Loading @@ -94,7 +122,7 @@ public function testPageTextContainsOnce(): void { * @covers ::elementTextEquals */ public function testElementTextEquals(): void { $this->drupalGet('test-page'); $this->visit('', '<h1>Test page</h1>'); $this->assertSession()->elementTextEquals('xpath', '//h1', 'Test page'); $this->expectException(AssertionFailedError::class); Loading @@ -106,16 +134,23 @@ public function testElementTextEquals(): void { * @covers ::addressEquals */ public function testAddressEquals(): void { $this->drupalGet('test-page'); $this->visit('http://localhost/test-page'); $this->assertSession()->addressEquals('test-page'); $this->assertSession()->addressEquals('test-page?'); $this->assertSession()->addressNotEquals('test-page?a=b'); $this->assertSession()->addressNotEquals('other-page'); $this->drupalGet('test-page', ['query' => ['a' => 'b', 'c' => 'd']]); $this->visit('http://localhost/test-page?a=b&c=d'); $this->assertSession()->addressEquals('test-page'); $this->assertSession()->addressEquals('test-page?a=b&c=d'); $this->assertSession()->addressEquals(Url::fromRoute('test_page_test.test_page', [], ['query' => ['a' => 'b', 'c' => 'd']])); $url = $this->createMock(Url::class); $url->expects($this->any()) ->method('setAbsolute') ->willReturn($url); $url->expects($this->any()) ->method('toString') ->willReturn('test-page?a=b&c=d'); $this->assertSession()->addressEquals($url); $this->assertSession()->addressNotEquals('test-page?c=d&a=b'); $this->assertSession()->addressNotEquals('test-page?a=b'); $this->assertSession()->addressNotEquals('test-page?a=b&c=d&e=f'); Loading @@ -131,7 +166,8 @@ public function testAddressEquals(): void { * @covers ::addressNotEquals */ public function testAddressNotEqualsException(): void { $this->drupalGet('test-page', ['query' => ['a' => 'b', 'c' => 'd']]); $this->visit('http://localhost/test-page?a=b&c=d'); $this->expectException(ExpectationException::class); $this->expectExceptionMessage('Current page is "/test-page?a=b&c=d", but should not be.'); $this->assertSession()->addressNotEquals('test-page?a=b&c=d'); Loading @@ -143,8 +179,9 @@ public function testAddressNotEqualsException(): void { * @covers ::linkExists */ public function testPipeCharInLocator(): void { $this->drupalGet('test-pipe-char'); $this->visit('', '<a href="http://example.com">foo|bar|baz</a>'); $this->assertSession()->linkExists('foo|bar|baz'); $this->addToAssertionCount(1); } /** Loading @@ -153,8 +190,9 @@ public function testPipeCharInLocator(): void { * @covers ::linkExistsExact */ public function testLinkExistsExact(): void { $this->drupalGet('test-pipe-char'); $this->visit('', '<a href="http://example.com">foo|bar|baz</a>'); $this->assertSession()->linkExistsExact('foo|bar|baz'); $this->addToAssertionCount(1); } /** Loading @@ -163,7 +201,7 @@ public function testLinkExistsExact(): void { * @covers ::linkExistsExact */ public function testInvalidLinkExistsExact(): void { $this->drupalGet('test-pipe-char'); $this->visit('', '<a href="http://example.com">foo|bar|baz</a>'); $this->expectException(ExpectationException::class); $this->expectExceptionMessage('Link with label foo|bar not found'); $this->assertSession()->linkExistsExact('foo|bar'); Loading @@ -175,8 +213,9 @@ public function testInvalidLinkExistsExact(): void { * @covers ::linkNotExistsExact */ public function testLinkNotExistsExact(): void { $this->drupalGet('test-pipe-char'); $this->visit('', '<a href="http://example.com">foo|bar|baz</a>'); $this->assertSession()->linkNotExistsExact('foo|bar'); $this->addToAssertionCount(1); } /** Loading @@ -185,10 +224,11 @@ public function testLinkNotExistsExact(): void { * @covers ::linkNotExistsExact */ public function testInvalidLinkNotExistsExact(): void { $this->drupalGet('test-pipe-char'); $this->visit('', '<a href="http://example.com">foo|bar|baz</a>'); $this->expectException(ExpectationException::class); $this->expectExceptionMessage('Link with label foo|bar|baz found'); $this->assertSession()->linkNotExistsExact('foo|bar|baz'); $this->addToAssertionCount(1); } /** Loading @@ -197,11 +237,12 @@ public function testInvalidLinkNotExistsExact(): void { * @covers ::linkByHrefExists */ public function testLinkByHrefExists(): void { $this->drupalGet('test-page'); $this->visit('', '<a href="/user/login">Log in</a><a href="/user/register">Register</a>'); // Partial matching. $this->assertSession()->linkByHrefExists('/user'); // Full matching. $this->assertSession()->linkByHrefExists('/user/login'); $this->addToAssertionCount(1); } /** Loading @@ -210,9 +251,10 @@ public function testLinkByHrefExists(): void { * @covers ::linkByHrefExists */ public function testInvalidLinkByHrefExists(): void { $this->drupalGet('test-page'); $this->visit('', '<a href="/user/login">Log in</a><a href="/user/register">Register</a>'); $this->expectException(ExpectationException::class); $this->assertSession()->linkByHrefExists('/foo'); $this->addToAssertionCount(1); } /** Loading @@ -221,8 +263,9 @@ public function testInvalidLinkByHrefExists(): void { * @covers ::linkByHrefNotExists */ public function testLinkByHrefNotExists(): void { $this->drupalGet('test-page'); $this->visit('', '<a href="/user/login">Log in</a><a href="/user/register">Register</a>'); $this->assertSession()->linkByHrefNotExists('/foo'); $this->addToAssertionCount(1); } /** Loading @@ -231,9 +274,10 @@ public function testLinkByHrefNotExists(): void { * @covers ::linkByHrefNotExists */ public function testInvalidLinkByHrefNotExistsPartial(): void { $this->drupalGet('test-page'); $this->visit('', '<a href="/user/login">Log in</a><a href="/user/register">Register</a>'); $this->expectException(ExpectationException::class); $this->assertSession()->linkByHrefNotExists('/user'); $this->addToAssertionCount(1); } /** Loading @@ -242,7 +286,7 @@ public function testInvalidLinkByHrefNotExistsPartial(): void { * @covers ::linkByHrefNotExists */ public function testInvalidLinkByHrefNotExistsFull(): void { $this->drupalGet('test-page'); $this->visit('', '<a href="/user/login">Log in</a><a href="/user/register">Register</a>'); $this->expectException(ExpectationException::class); $this->assertSession()->linkByHrefNotExists('/user/login'); } Loading @@ -253,8 +297,9 @@ public function testInvalidLinkByHrefNotExistsFull(): void { * @covers ::linkByHrefExistsExact */ public function testLinkByHrefExistsExact(): void { $this->drupalGet('test-page'); $this->visit('', '<a href="/user/login">Log in</a><a href="/user/register">Register</a>'); $this->assertSession()->linkByHrefExistsExact('/user/login'); $this->addToAssertionCount(1); } /** Loading @@ -263,7 +308,7 @@ public function testLinkByHrefExistsExact(): void { * @covers ::linkByHrefExistsExact */ public function testInvalidLinkByHrefExistsExact(): void { $this->drupalGet('test-page'); $this->visit('', '<a href="/user/login">Log in</a><a href="/user/register">Register</a>'); $this->expectException(ExpectationException::class); $this->assertSession()->linkByHrefExistsExact('/foo'); } Loading @@ -274,8 +319,9 @@ public function testInvalidLinkByHrefExistsExact(): void { * @covers ::linkByHrefNotExistsExact */ public function testLinkByHrefNotExistsExact(): void { $this->drupalGet('test-page'); $this->visit('', '<a href="/user/login">Log in</a><a href="/user/register">Register</a>'); $this->assertSession()->linkByHrefNotExistsExact('/foo'); $this->addToAssertionCount(1); } /** Loading @@ -284,7 +330,7 @@ public function testLinkByHrefNotExistsExact(): void { * @covers ::linkByHrefNotExistsExact */ public function testInvalidLinkByHrefNotExistsExact(): void { $this->drupalGet('test-page'); $this->visit('', '<a href="/user/login">Log in</a><a href="/user/register">Register</a>'); $this->expectException(ExpectationException::class); $this->assertSession()->linkByHrefNotExistsExact('/user/login'); } Loading @@ -296,11 +342,12 @@ public function testInvalidLinkByHrefNotExistsExact(): void { * @covers ::responseNotContains */ public function testTextAsserts(): void { $this->drupalGet('test-encoded'); $this->visit('', 'Bad html <script>alert(123);</script>'); $dangerous = 'Bad html <script>alert(123);</script>'; $sanitized = Html::escape($dangerous); $this->assertSession()->responseNotContains($dangerous); $this->assertSession()->responseContains($sanitized); $this->addToAssertionCount(2); } /** Loading @@ -310,7 +357,11 @@ public function testTextAsserts(): void { * @covers ::buttonNotExists */ public function testFieldAssertsForButton(): void { $this->drupalGet('test-field-xpath'); $this->visit('', <<<HTML <input type="submit" id="edit-save" value="Save" name="op"> <input type="submit" id="duplicate_button" value="Duplicate button 1" name="duplicate_button"> <input type="submit" id="duplicate_button" value="Duplicate button 2" name="duplicate_button"> HTML); // Verify if the test passes with button ID. $this->assertSession()->buttonExists('edit-save'); Loading Loading @@ -339,6 +390,7 @@ public function testFieldAssertsForButton(): void { catch (ExpectationException $e) { // Expected exception; just continue testing. } $this->addToAssertionCount(11); } /** Loading @@ -347,11 +399,17 @@ public function testFieldAssertsForButton(): void { * @covers ::pageContainsNoDuplicateId */ public function testPageContainsNoDuplicateId(): void { $this->visit('', <<<HTML <h1 id="page-element-title">Hello</h1> <h2 id="page-element-description">World</h2> HTML); $assert_session = $this->assertSession(); $this->drupalGet(Url::fromRoute('test_page_test.page_without_duplicate_ids')); $assert_session->pageContainsNoDuplicateId(); $this->drupalGet(Url::fromRoute('test_page_test.page_with_duplicate_ids')); $this->visit('', <<<HTML <h1 id="page-element">Hello</h1> <h2 id="page-element">World</h2> HTML); $this->expectException(ExpectationException::class); $this->expectExceptionMessage('The page contains a duplicate HTML ID "page-element".'); $assert_session->pageContainsNoDuplicateId(); Loading @@ -366,21 +424,40 @@ public function testPageContainsNoDuplicateId(): void { public function testEscapingAssertions(): void { $assert = $this->assertSession(); $this->drupalGet('test-escaped-characters'); $this->visit('', '<div class="escaped">Escaped: <"'&></div>'); $assert->assertNoEscaped('<div class="escaped">'); $assert->responseContains('<div class="escaped">'); $assert->assertEscaped('Escaped: <"\'&>'); $this->drupalGet('test-escaped-script'); $this->visit('', '<div class="escaped"><script>alert('XSS');alert("XSS");</script></div>'); $assert->assertNoEscaped('<div class="escaped">'); $assert->responseContains('<div class="escaped">'); $assert->assertEscaped("<script>alert('XSS');alert(\"XSS\");</script>"); $this->drupalGet('test-unescaped-script'); $this->visit('', <<<HTML <div class="unescaped"><script>alert('Marked safe');alert("Marked safe");</script></div> HTML); $this->session->visit(''); $assert->assertNoEscaped('<div class="unescaped">'); $assert->responseContains('<div class="unescaped">'); $assert->responseContains("<script>alert('Marked safe');alert(\"Marked safe\");</script>"); $assert->assertNoEscaped("<script>alert('Marked safe');alert(\"Marked safe\");</script>"); $this->addToAssertionCount(10); } } /** * A mock client. */ class MockClient extends AbstractBrowser { public function setExpectedResponse(Response $response) { $this->response = $response; } protected function doRequest(object $request) { return $this->response ?? new Response(); } } Loading
core/tests/Drupal/FunctionalTests/WebAssertTest.php→core/tests/Drupal/Tests/Core/Test/WebAssertTest.php +124 −47 Original line number Diff line number Diff line Loading @@ -2,35 +2,70 @@ declare(strict_types=1); namespace Drupal\FunctionalTests; namespace Drupal\Tests\Core\Test; use Behat\Mink\Driver\BrowserKitDriver; use Behat\Mink\Exception\ExpectationException; use Behat\Mink\Exception\ResponseTextException; use Behat\Mink\Session; use Drupal\Component\Utility\Html; use Drupal\Core\Url; use Drupal\Tests\BrowserTestBase; use Behat\Mink\Exception\ResponseTextException; use Drupal\Tests\UnitTestCase; use Drupal\Tests\WebAssert; use PHPUnit\Framework\AssertionFailedError; use Symfony\Component\BrowserKit\AbstractBrowser; use Symfony\Component\BrowserKit\Response; /** * Tests WebAssert functionality. * * @group browsertestbase * @group #slow * @coversDefaultClass \Drupal\Tests\WebAssert */ class WebAssertTest extends BrowserTestBase { class WebAssertTest extends UnitTestCase { /** * {@inheritdoc} * Session mock. */ protected Session $session; /** * Client mock. */ protected static $modules = [ 'test_page_test', ]; protected AbstractBrowser $client; /** * {@inheritdoc} */ protected $defaultTheme = 'stark'; public function setUp(): void { parent::setUp(); $this->client = new MockClient(); $driver = new BrowserKitDriver($this->client); $this->session = new Session($driver); } /** * Get the mocked session. */ protected function assertSession(): WebAssert { return new WebAssert($this->session); } /** * Simulate a page visit and expect a response. * * @param string $uri * The URI to visit. This is only required if assertions are made about the * URL, otherwise it can be left empty. * @param string $content * The expected response content. * @param array $responseHeaders * The expected response headers. */ protected function visit(string $uri = '', string $content = '', array $responseHeaders = []): void { $this->client->setExpectedResponse(new Response($content, 200, $responseHeaders)); $this->session->visit($uri); } /** * Tests WebAssert::responseHeaderExists(). Loading @@ -38,9 +73,8 @@ class WebAssertTest extends BrowserTestBase { * @covers ::responseHeaderExists */ public function testResponseHeaderExists(): void { $this->drupalGet('test-null-header'); $this->visit('', '', ['Null-Header' => '']); $this->assertSession()->responseHeaderExists('Null-Header'); $this->expectException(AssertionFailedError::class); $this->expectExceptionMessage("Failed asserting that the response has a 'does-not-exist' header."); $this->assertSession()->responseHeaderExists('does-not-exist'); Loading @@ -52,7 +86,7 @@ public function testResponseHeaderExists(): void { * @covers ::responseHeaderDoesNotExist */ public function testResponseHeaderDoesNotExist(): void { $this->drupalGet('test-null-header'); $this->visit('', '', ['Null-Header' => '']); $this->assertSession()->responseHeaderDoesNotExist('does-not-exist'); $this->expectException(AssertionFailedError::class); Loading @@ -64,10 +98,7 @@ public function testResponseHeaderDoesNotExist(): void { * @covers ::pageTextMatchesCount */ public function testPageTextMatchesCount(): void { $this->drupalLogin($this->drupalCreateUser()); // Visit a Drupal page that requires login. $this->drupalGet('test-page'); $this->visit('', 'Test page text. <a href="#">Foo</a>'); $this->assertSession()->pageTextMatchesCount(1, '/Test page text\./'); $this->expectException(AssertionFailedError::class); Loading @@ -79,10 +110,7 @@ public function testPageTextMatchesCount(): void { * @covers ::pageTextContainsOnce */ public function testPageTextContainsOnce(): void { $this->drupalLogin($this->drupalCreateUser()); // Visit a Drupal page that requires login. $this->drupalGet('test-page'); $this->visit('', 'Test page text. <a href="#">Foo</a>'); $this->assertSession()->pageTextContainsOnce('Test page text.'); $this->expectException(ResponseTextException::class); Loading @@ -94,7 +122,7 @@ public function testPageTextContainsOnce(): void { * @covers ::elementTextEquals */ public function testElementTextEquals(): void { $this->drupalGet('test-page'); $this->visit('', '<h1>Test page</h1>'); $this->assertSession()->elementTextEquals('xpath', '//h1', 'Test page'); $this->expectException(AssertionFailedError::class); Loading @@ -106,16 +134,23 @@ public function testElementTextEquals(): void { * @covers ::addressEquals */ public function testAddressEquals(): void { $this->drupalGet('test-page'); $this->visit('http://localhost/test-page'); $this->assertSession()->addressEquals('test-page'); $this->assertSession()->addressEquals('test-page?'); $this->assertSession()->addressNotEquals('test-page?a=b'); $this->assertSession()->addressNotEquals('other-page'); $this->drupalGet('test-page', ['query' => ['a' => 'b', 'c' => 'd']]); $this->visit('http://localhost/test-page?a=b&c=d'); $this->assertSession()->addressEquals('test-page'); $this->assertSession()->addressEquals('test-page?a=b&c=d'); $this->assertSession()->addressEquals(Url::fromRoute('test_page_test.test_page', [], ['query' => ['a' => 'b', 'c' => 'd']])); $url = $this->createMock(Url::class); $url->expects($this->any()) ->method('setAbsolute') ->willReturn($url); $url->expects($this->any()) ->method('toString') ->willReturn('test-page?a=b&c=d'); $this->assertSession()->addressEquals($url); $this->assertSession()->addressNotEquals('test-page?c=d&a=b'); $this->assertSession()->addressNotEquals('test-page?a=b'); $this->assertSession()->addressNotEquals('test-page?a=b&c=d&e=f'); Loading @@ -131,7 +166,8 @@ public function testAddressEquals(): void { * @covers ::addressNotEquals */ public function testAddressNotEqualsException(): void { $this->drupalGet('test-page', ['query' => ['a' => 'b', 'c' => 'd']]); $this->visit('http://localhost/test-page?a=b&c=d'); $this->expectException(ExpectationException::class); $this->expectExceptionMessage('Current page is "/test-page?a=b&c=d", but should not be.'); $this->assertSession()->addressNotEquals('test-page?a=b&c=d'); Loading @@ -143,8 +179,9 @@ public function testAddressNotEqualsException(): void { * @covers ::linkExists */ public function testPipeCharInLocator(): void { $this->drupalGet('test-pipe-char'); $this->visit('', '<a href="http://example.com">foo|bar|baz</a>'); $this->assertSession()->linkExists('foo|bar|baz'); $this->addToAssertionCount(1); } /** Loading @@ -153,8 +190,9 @@ public function testPipeCharInLocator(): void { * @covers ::linkExistsExact */ public function testLinkExistsExact(): void { $this->drupalGet('test-pipe-char'); $this->visit('', '<a href="http://example.com">foo|bar|baz</a>'); $this->assertSession()->linkExistsExact('foo|bar|baz'); $this->addToAssertionCount(1); } /** Loading @@ -163,7 +201,7 @@ public function testLinkExistsExact(): void { * @covers ::linkExistsExact */ public function testInvalidLinkExistsExact(): void { $this->drupalGet('test-pipe-char'); $this->visit('', '<a href="http://example.com">foo|bar|baz</a>'); $this->expectException(ExpectationException::class); $this->expectExceptionMessage('Link with label foo|bar not found'); $this->assertSession()->linkExistsExact('foo|bar'); Loading @@ -175,8 +213,9 @@ public function testInvalidLinkExistsExact(): void { * @covers ::linkNotExistsExact */ public function testLinkNotExistsExact(): void { $this->drupalGet('test-pipe-char'); $this->visit('', '<a href="http://example.com">foo|bar|baz</a>'); $this->assertSession()->linkNotExistsExact('foo|bar'); $this->addToAssertionCount(1); } /** Loading @@ -185,10 +224,11 @@ public function testLinkNotExistsExact(): void { * @covers ::linkNotExistsExact */ public function testInvalidLinkNotExistsExact(): void { $this->drupalGet('test-pipe-char'); $this->visit('', '<a href="http://example.com">foo|bar|baz</a>'); $this->expectException(ExpectationException::class); $this->expectExceptionMessage('Link with label foo|bar|baz found'); $this->assertSession()->linkNotExistsExact('foo|bar|baz'); $this->addToAssertionCount(1); } /** Loading @@ -197,11 +237,12 @@ public function testInvalidLinkNotExistsExact(): void { * @covers ::linkByHrefExists */ public function testLinkByHrefExists(): void { $this->drupalGet('test-page'); $this->visit('', '<a href="/user/login">Log in</a><a href="/user/register">Register</a>'); // Partial matching. $this->assertSession()->linkByHrefExists('/user'); // Full matching. $this->assertSession()->linkByHrefExists('/user/login'); $this->addToAssertionCount(1); } /** Loading @@ -210,9 +251,10 @@ public function testLinkByHrefExists(): void { * @covers ::linkByHrefExists */ public function testInvalidLinkByHrefExists(): void { $this->drupalGet('test-page'); $this->visit('', '<a href="/user/login">Log in</a><a href="/user/register">Register</a>'); $this->expectException(ExpectationException::class); $this->assertSession()->linkByHrefExists('/foo'); $this->addToAssertionCount(1); } /** Loading @@ -221,8 +263,9 @@ public function testInvalidLinkByHrefExists(): void { * @covers ::linkByHrefNotExists */ public function testLinkByHrefNotExists(): void { $this->drupalGet('test-page'); $this->visit('', '<a href="/user/login">Log in</a><a href="/user/register">Register</a>'); $this->assertSession()->linkByHrefNotExists('/foo'); $this->addToAssertionCount(1); } /** Loading @@ -231,9 +274,10 @@ public function testLinkByHrefNotExists(): void { * @covers ::linkByHrefNotExists */ public function testInvalidLinkByHrefNotExistsPartial(): void { $this->drupalGet('test-page'); $this->visit('', '<a href="/user/login">Log in</a><a href="/user/register">Register</a>'); $this->expectException(ExpectationException::class); $this->assertSession()->linkByHrefNotExists('/user'); $this->addToAssertionCount(1); } /** Loading @@ -242,7 +286,7 @@ public function testInvalidLinkByHrefNotExistsPartial(): void { * @covers ::linkByHrefNotExists */ public function testInvalidLinkByHrefNotExistsFull(): void { $this->drupalGet('test-page'); $this->visit('', '<a href="/user/login">Log in</a><a href="/user/register">Register</a>'); $this->expectException(ExpectationException::class); $this->assertSession()->linkByHrefNotExists('/user/login'); } Loading @@ -253,8 +297,9 @@ public function testInvalidLinkByHrefNotExistsFull(): void { * @covers ::linkByHrefExistsExact */ public function testLinkByHrefExistsExact(): void { $this->drupalGet('test-page'); $this->visit('', '<a href="/user/login">Log in</a><a href="/user/register">Register</a>'); $this->assertSession()->linkByHrefExistsExact('/user/login'); $this->addToAssertionCount(1); } /** Loading @@ -263,7 +308,7 @@ public function testLinkByHrefExistsExact(): void { * @covers ::linkByHrefExistsExact */ public function testInvalidLinkByHrefExistsExact(): void { $this->drupalGet('test-page'); $this->visit('', '<a href="/user/login">Log in</a><a href="/user/register">Register</a>'); $this->expectException(ExpectationException::class); $this->assertSession()->linkByHrefExistsExact('/foo'); } Loading @@ -274,8 +319,9 @@ public function testInvalidLinkByHrefExistsExact(): void { * @covers ::linkByHrefNotExistsExact */ public function testLinkByHrefNotExistsExact(): void { $this->drupalGet('test-page'); $this->visit('', '<a href="/user/login">Log in</a><a href="/user/register">Register</a>'); $this->assertSession()->linkByHrefNotExistsExact('/foo'); $this->addToAssertionCount(1); } /** Loading @@ -284,7 +330,7 @@ public function testLinkByHrefNotExistsExact(): void { * @covers ::linkByHrefNotExistsExact */ public function testInvalidLinkByHrefNotExistsExact(): void { $this->drupalGet('test-page'); $this->visit('', '<a href="/user/login">Log in</a><a href="/user/register">Register</a>'); $this->expectException(ExpectationException::class); $this->assertSession()->linkByHrefNotExistsExact('/user/login'); } Loading @@ -296,11 +342,12 @@ public function testInvalidLinkByHrefNotExistsExact(): void { * @covers ::responseNotContains */ public function testTextAsserts(): void { $this->drupalGet('test-encoded'); $this->visit('', 'Bad html <script>alert(123);</script>'); $dangerous = 'Bad html <script>alert(123);</script>'; $sanitized = Html::escape($dangerous); $this->assertSession()->responseNotContains($dangerous); $this->assertSession()->responseContains($sanitized); $this->addToAssertionCount(2); } /** Loading @@ -310,7 +357,11 @@ public function testTextAsserts(): void { * @covers ::buttonNotExists */ public function testFieldAssertsForButton(): void { $this->drupalGet('test-field-xpath'); $this->visit('', <<<HTML <input type="submit" id="edit-save" value="Save" name="op"> <input type="submit" id="duplicate_button" value="Duplicate button 1" name="duplicate_button"> <input type="submit" id="duplicate_button" value="Duplicate button 2" name="duplicate_button"> HTML); // Verify if the test passes with button ID. $this->assertSession()->buttonExists('edit-save'); Loading Loading @@ -339,6 +390,7 @@ public function testFieldAssertsForButton(): void { catch (ExpectationException $e) { // Expected exception; just continue testing. } $this->addToAssertionCount(11); } /** Loading @@ -347,11 +399,17 @@ public function testFieldAssertsForButton(): void { * @covers ::pageContainsNoDuplicateId */ public function testPageContainsNoDuplicateId(): void { $this->visit('', <<<HTML <h1 id="page-element-title">Hello</h1> <h2 id="page-element-description">World</h2> HTML); $assert_session = $this->assertSession(); $this->drupalGet(Url::fromRoute('test_page_test.page_without_duplicate_ids')); $assert_session->pageContainsNoDuplicateId(); $this->drupalGet(Url::fromRoute('test_page_test.page_with_duplicate_ids')); $this->visit('', <<<HTML <h1 id="page-element">Hello</h1> <h2 id="page-element">World</h2> HTML); $this->expectException(ExpectationException::class); $this->expectExceptionMessage('The page contains a duplicate HTML ID "page-element".'); $assert_session->pageContainsNoDuplicateId(); Loading @@ -366,21 +424,40 @@ public function testPageContainsNoDuplicateId(): void { public function testEscapingAssertions(): void { $assert = $this->assertSession(); $this->drupalGet('test-escaped-characters'); $this->visit('', '<div class="escaped">Escaped: <"'&></div>'); $assert->assertNoEscaped('<div class="escaped">'); $assert->responseContains('<div class="escaped">'); $assert->assertEscaped('Escaped: <"\'&>'); $this->drupalGet('test-escaped-script'); $this->visit('', '<div class="escaped"><script>alert('XSS');alert("XSS");</script></div>'); $assert->assertNoEscaped('<div class="escaped">'); $assert->responseContains('<div class="escaped">'); $assert->assertEscaped("<script>alert('XSS');alert(\"XSS\");</script>"); $this->drupalGet('test-unescaped-script'); $this->visit('', <<<HTML <div class="unescaped"><script>alert('Marked safe');alert("Marked safe");</script></div> HTML); $this->session->visit(''); $assert->assertNoEscaped('<div class="unescaped">'); $assert->responseContains('<div class="unescaped">'); $assert->responseContains("<script>alert('Marked safe');alert(\"Marked safe\");</script>"); $assert->assertNoEscaped("<script>alert('Marked safe');alert(\"Marked safe\");</script>"); $this->addToAssertionCount(10); } } /** * A mock client. */ class MockClient extends AbstractBrowser { public function setExpectedResponse(Response $response) { $this->response = $response; } protected function doRequest(object $request) { return $this->response ?? new Response(); } }