1<?php 2 3namespace Drupal\FunctionalJavascriptTests; 4 5use PHPUnit\Framework\AssertionFailedError; 6 7/** 8 * Tests if we can execute JavaScript in the browser. 9 * 10 * @group javascript 11 */ 12class BrowserWithJavascriptTest extends WebDriverTestBase { 13 14 /** 15 * Modules to enable. 16 * 17 * @var array 18 */ 19 protected static $modules = ['test_page_test']; 20 21 /** 22 * {@inheritdoc} 23 */ 24 protected $defaultTheme = 'stark'; 25 26 public function testJavascript() { 27 $this->drupalGet('<front>'); 28 $session = $this->getSession(); 29 30 $session->resizeWindow(400, 300); 31 $javascript = <<<JS 32 (function(){ 33 var w = window, 34 d = document, 35 e = d.documentElement, 36 g = d.getElementsByTagName('body')[0], 37 x = w.innerWidth || e.clientWidth || g.clientWidth, 38 y = w.innerHeight || e.clientHeight|| g.clientHeight; 39 return x == 400 && y == 300; 40 }()) 41JS; 42 $this->assertJsCondition($javascript); 43 44 // Ensure that \Drupal\Tests\UiHelperTrait::isTestUsingGuzzleClient() works 45 // as expected. 46 $this->assertFalse($this->isTestUsingGuzzleClient()); 47 } 48 49 public function testAssertJsCondition() { 50 $this->drupalGet('<front>'); 51 $session = $this->getSession(); 52 53 $session->resizeWindow(500, 300); 54 $javascript = <<<JS 55 (function(){ 56 var w = window, 57 d = document, 58 e = d.documentElement, 59 g = d.getElementsByTagName('body')[0], 60 x = w.innerWidth || e.clientWidth || g.clientWidth, 61 y = w.innerHeight || e.clientHeight|| g.clientHeight; 62 return x == 400 && y == 300; 63 }()) 64JS; 65 66 // We expected the following assertion to fail because the window has been 67 // re-sized to have a width of 500 not 400. 68 $this->expectException(AssertionFailedError::class); 69 $this->assertJsCondition($javascript, 100); 70 } 71 72 /** 73 * Tests creating screenshots. 74 */ 75 public function testCreateScreenshot() { 76 $this->drupalGet('<front>'); 77 $this->createScreenshot('public://screenshot.jpg'); 78 $this->assertFileExists('public://screenshot.jpg'); 79 } 80 81 /** 82 * Tests assertEscaped() and assertUnescaped(). 83 * 84 * @see \Drupal\Tests\WebAssert::assertNoEscaped() 85 * @see \Drupal\Tests\WebAssert::assertEscaped() 86 */ 87 public function testEscapingAssertions() { 88 $assert = $this->assertSession(); 89 90 $this->drupalGet('test-escaped-characters'); 91 $assert->assertNoEscaped('<div class="escaped">'); 92 $assert->responseContains('<div class="escaped">'); 93 $assert->assertEscaped('Escaped: <"\'&>'); 94 95 $this->drupalGet('test-escaped-script'); 96 $assert->assertNoEscaped('<div class="escaped">'); 97 $assert->responseContains('<div class="escaped">'); 98 $assert->assertEscaped("<script>alert('XSS');alert(\"XSS\");</script>"); 99 100 $this->drupalGetWithAlert('test-unescaped-script'); 101 $assert->assertNoEscaped('<div class="unescaped">'); 102 $assert->responseContains('<div class="unescaped">'); 103 $assert->responseContains("<script>alert('Marked safe');alert(\"Marked safe\");</script>"); 104 $assert->assertNoEscaped("<script>alert('Marked safe');alert(\"Marked safe\");</script>"); 105 } 106 107 /** 108 * Retrieves a Drupal path or an absolute path. 109 * 110 * @param string|\Drupal\Core\Url $path 111 * Drupal path or URL to load into Mink controlled browser. 112 * @param array $options 113 * (optional) Options to be forwarded to the url generator. 114 * @param string[] $headers 115 * An array containing additional HTTP request headers, the array keys are 116 * the header names and the array values the header values. This is useful 117 * to set for example the "Accept-Language" header for requesting the page 118 * in a different language. Note that not all headers are supported, for 119 * example the "Accept" header is always overridden by the browser. For 120 * testing REST APIs it is recommended to obtain a separate HTTP client 121 * using getHttpClient() and performing requests that way. 122 * 123 * @return string 124 * The retrieved HTML string, also available as $this->getRawContent() 125 * 126 * @see \Drupal\Tests\BrowserTestBase::getHttpClient() 127 */ 128 protected function drupalGetWithAlert($path, array $options = [], array $headers = []) { 129 $options['absolute'] = TRUE; 130 $url = $this->buildUrl($path, $options); 131 132 $session = $this->getSession(); 133 134 $this->prepareRequest(); 135 foreach ($headers as $header_name => $header_value) { 136 $session->setRequestHeader($header_name, $header_value); 137 } 138 139 $session->visit($url); 140 141 // There are 2 alerts to accept before we can get the content of the page. 142 $session->getDriver()->getWebdriverSession()->accept_alert(); 143 $session->getDriver()->getWebdriverSession()->accept_alert(); 144 145 $out = $session->getPage()->getContent(); 146 147 // Ensure that any changes to variables in the other thread are picked up. 148 $this->refreshVariables(); 149 150 // Replace original page output with new output from redirected page(s). 151 if ($new = $this->checkForMetaRefresh()) { 152 $out = $new; 153 // We are finished with all meta refresh redirects, so reset the counter. 154 $this->metaRefreshCount = 0; 155 } 156 157 // Log only for WebDriverTestBase tests because for DrupalTestBrowser we log 158 // with ::getResponseLogHandler. 159 if ($this->htmlOutputEnabled && !$this->isTestUsingGuzzleClient()) { 160 $html_output = 'GET request to: ' . $url . 161 '<hr />Ending URL: ' . $this->getSession()->getCurrentUrl(); 162 $html_output .= '<hr />' . $out; 163 $html_output .= $this->getHtmlOutputHeaders(); 164 $this->htmlOutput($html_output); 165 } 166 167 return $out; 168 } 169 170} 171