BrowserWithJavascriptTest.php 5.4 KB

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