JavascriptTestBase.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. <?php
  2. namespace Drupal\FunctionalJavascriptTests;
  3. use Drupal\Tests\BrowserTestBase;
  4. use Zumba\GastonJS\Exception\DeadClient;
  5. use Zumba\Mink\Driver\PhantomJSDriver;
  6. /**
  7. * Runs a browser test using PhantomJS.
  8. *
  9. * Base class for testing browser interaction implemented in JavaScript.
  10. */
  11. abstract class JavascriptTestBase extends BrowserTestBase {
  12. /**
  13. * {@inheritdoc}
  14. */
  15. protected $minkDefaultDriverClass = PhantomJSDriver::class;
  16. /**
  17. * {@inheritdoc}
  18. */
  19. protected function initMink() {
  20. // Set up the template cache used by the PhantomJS mink driver.
  21. $path = $this->tempFilesDirectory . DIRECTORY_SEPARATOR . 'browsertestbase-templatecache';
  22. $this->minkDefaultDriverArgs = [
  23. 'http://127.0.0.1:8510',
  24. $path,
  25. ];
  26. if (!file_exists($path)) {
  27. mkdir($path);
  28. }
  29. try {
  30. return parent::initMink();
  31. }
  32. catch (DeadClient $e) {
  33. $this->markTestSkipped('PhantomJS is either not installed or not running. Start it via phantomjs --ssl-protocol=any --ignore-ssl-errors=true vendor/jcalderonzumba/gastonjs/src/Client/main.js 8510 1024 768&');
  34. }
  35. catch (\Exception $e) {
  36. $this->markTestSkipped('An unexpected error occurred while starting Mink: ' . $e->getMessage());
  37. }
  38. }
  39. /**
  40. * {@inheritdoc}
  41. */
  42. protected function tearDown() {
  43. if ($this->mink) {
  44. // Wait for all requests to finish. It is possible that an AJAX request is
  45. // still on-going.
  46. $result = $this->getSession()->wait(5000, '(typeof(jQuery)=="undefined" || (0 === jQuery.active && 0 === jQuery(\':animated\').length))');
  47. if (!$result) {
  48. // If the wait is unsuccessful, there may still be an AJAX request in
  49. // progress. If we tear down now, then this AJAX request may fail with
  50. // missing database tables, because tear down will have removed them.
  51. // Rather than allow it to fail, throw an explicit exception now
  52. // explaining what the problem is.
  53. throw new \RuntimeException('Unfinished AJAX requests while tearing down a test');
  54. }
  55. }
  56. parent::tearDown();
  57. }
  58. /**
  59. * Asserts that the element with the given CSS selector is visible.
  60. *
  61. * @param string $css_selector
  62. * The CSS selector identifying the element to check.
  63. * @param string $message
  64. * Optional message to show alongside the assertion.
  65. *
  66. * @deprecated in Drupal 8.1.x, will be removed before Drupal 8.3.x. Use
  67. * \Behat\Mink\Element\NodeElement::isVisible() instead.
  68. */
  69. protected function assertElementVisible($css_selector, $message = '') {
  70. $this->assertTrue($this->getSession()->getDriver()->isVisible($this->cssSelectToXpath($css_selector)), $message);
  71. }
  72. /**
  73. * Asserts that the element with the given CSS selector is not visible.
  74. *
  75. * @param string $css_selector
  76. * The CSS selector identifying the element to check.
  77. * @param string $message
  78. * Optional message to show alongside the assertion.
  79. *
  80. * @deprecated in Drupal 8.1.x, will be removed before Drupal 8.3.x. Use
  81. * \Behat\Mink\Element\NodeElement::isVisible() instead.
  82. */
  83. protected function assertElementNotVisible($css_selector, $message = '') {
  84. $this->assertFalse($this->getSession()->getDriver()->isVisible($this->cssSelectToXpath($css_selector)), $message);
  85. }
  86. /**
  87. * Waits for the given time or until the given JS condition becomes TRUE.
  88. *
  89. * @param string $condition
  90. * JS condition to wait until it becomes TRUE.
  91. * @param int $timeout
  92. * (Optional) Timeout in milliseconds, defaults to 10000.
  93. * @param string $message
  94. * (optional) A message to display with the assertion. If left blank, a
  95. * default message will be displayed.
  96. *
  97. * @throws \PHPUnit_Framework_AssertionFailedError
  98. *
  99. * @see \Behat\Mink\Driver\DriverInterface::evaluateScript()
  100. */
  101. protected function assertJsCondition($condition, $timeout = 10000, $message = '') {
  102. $message = $message ?: "Javascript condition met:\n" . $condition;
  103. $result = $this->getSession()->getDriver()->wait($timeout, $condition);
  104. $this->assertTrue($result, $message);
  105. }
  106. /**
  107. * Creates a screenshot.
  108. *
  109. * @param string $filename
  110. * The file name of the resulting screenshot. If using the default phantomjs
  111. * driver then this should be a JPG filename.
  112. * @param bool $set_background_color
  113. * (optional) By default this method will set the background color to white.
  114. * Set to FALSE to override this behaviour.
  115. *
  116. * @throws \Behat\Mink\Exception\UnsupportedDriverActionException
  117. * When operation not supported by the driver.
  118. * @throws \Behat\Mink\Exception\DriverException
  119. * When the operation cannot be done.
  120. */
  121. protected function createScreenshot($filename, $set_background_color = TRUE) {
  122. $session = $this->getSession();
  123. if ($set_background_color) {
  124. $session->executeScript("document.body.style.backgroundColor = 'white';");
  125. }
  126. $image = $session->getScreenshot();
  127. file_put_contents($filename, $image);
  128. }
  129. /**
  130. * {@inheritdoc}
  131. */
  132. public function assertSession($name = NULL) {
  133. return new JSWebAssert($this->getSession($name), $this->baseUrl);
  134. }
  135. /**
  136. * Gets the current Drupal javascript settings and parses into an array.
  137. *
  138. * Unlike BrowserTestBase::getDrupalSettings(), this implementation reads the
  139. * current values of drupalSettings, capturing all changes made via javascript
  140. * after the page was loaded.
  141. *
  142. * @return array
  143. * The Drupal javascript settings array.
  144. *
  145. * @see \Drupal\Tests\BrowserTestBase::getDrupalSettings()
  146. */
  147. protected function getDrupalSettings() {
  148. $script = <<<EndOfScript
  149. (function () {
  150. if (typeof drupalSettings !== 'undefined') {
  151. return drupalSettings;
  152. }
  153. })();
  154. EndOfScript;
  155. return $this->getSession()->evaluateScript($script) ?: [];
  156. }
  157. }