View source
<?php
namespace Drupal\Tests\thunder\FunctionalJavascript;
use Behat\Mink\Driver\Selenium2Driver;
use Behat\Mink\Element\DocumentElement;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
use Drupal\Tests\thunder\Traits\ThunderTestTrait;
use Drupal\Core\Database\Database;
use Drupal\Component\Utility\Xss;
use Drupal\Component\Render\FormattableMarkup;
abstract class ThunderJavascriptTestBase extends WebDriverTestBase {
use ThunderTestTrait;
use StringTranslationTrait;
protected $disableCssAnimations = FALSE;
protected static $modules = [
'thunder_testing_demo',
'thunder_workflow',
'thunder_test_mock_request',
];
protected $profile = 'thunder';
protected $screenshotDirectory = '/tmp/thunder-travis-ci';
protected static $defaultUserRole = 'editor';
protected function setUp() {
parent::setUp();
$this
->logWithRole(static::$defaultUserRole);
$instagram = $this
->config('media_entity_instagram.settings');
$instagram
->set('facebook_app_id', 123)
->set('facebook_app_secret', 123)
->save();
}
protected function initFrontPage() {
parent::initFrontPage();
$windowSize = $this
->getWindowSize();
$this
->getSession()
->resizeWindow($windowSize['width'], $windowSize['height']);
}
protected function getWindowSize() {
return [
'width' => 1280,
'height' => 768,
];
}
public function waitUntilVisible($selector, $timeout = 1000, $message = '') {
$condition = "jQuery('" . $selector . ":visible').length > 0";
$this
->assertJsCondition($condition, $timeout, $message);
}
public function waitForImages($cssSelector, $total, $time = 10000) {
$this
->getSession()
->wait($time, "jQuery('{$cssSelector}').filter(function(){return jQuery(this).prop('complete');}).length === {$total}");
}
protected function getScreenshotFolder() {
$dir = $this->screenshotDirectory;
$travisId = getenv('TRAVIS_JOB_ID');
if (!empty($travisId)) {
$dir .= '/' . $travisId;
}
if (!is_dir($dir)) {
if (mkdir($dir, 0777, TRUE) === FALSE) {
throw new \Exception('Unable to create directory: ' . $dir);
}
}
return realpath($dir);
}
public function scrollElementInView($cssSelector) {
$this
->getSession()
->executeScript('
var viewPortHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
var element = jQuery(\'' . addcslashes($cssSelector, '\'') . '\');
var scrollTop = element.offset().top - (viewPortHeight/2);
var scrollableParent = jQuery.isFunction(element.scrollParent) ? element.scrollParent() : [];
if (scrollableParent.length > 0 && scrollableParent[0] !== document && scrollableParent[0] !== document.body) { scrollableParent[0].scrollTop = scrollableParent[0].scrollTop + scrollTop - scrollableParent.offset().top } else { window.scroll(0, scrollTop); };
');
}
public function clickButtonDrupalSelector(DocumentElement $page, $drupalSelector, $waitAfterAction = TRUE) {
$this
->clickButtonCssSelector($page, '[data-drupal-selector="' . $drupalSelector . '"]', $waitAfterAction);
}
public function clickButtonCssSelector(DocumentElement $page, $cssSelector, $waitAfterAction = TRUE) {
$this
->scrollElementInView($cssSelector);
$editButton = $page
->find('css', $cssSelector);
$editButton
->click();
if ($waitAfterAction) {
$this
->assertWaitOnAjaxRequest();
}
}
public function clickAjaxButtonCssSelector($cssSelector, $waitAfterAction = TRUE) {
$this
->scrollElementInView($cssSelector);
$this
->getSession()
->executeScript("jQuery('{$cssSelector}').trigger('mousedown');");
if ($waitAfterAction) {
$this
->assertWaitOnAjaxRequest();
}
}
protected function clickDropButton($fieldName, $toggle = TRUE) {
$page = $this
->getSession()
->getPage();
if ($toggle) {
$toggleButtonXpath = '//ul[.//*[@name="' . $fieldName . '"]]/li[contains(@class,"dropbutton-toggle")]/button';
$toggleButton = $page
->find('xpath', $toggleButtonXpath);
$toggleButton
->click();
$this
->assertWaitOnAjaxRequest();
}
$this
->scrollElementInView('[name="' . $fieldName . '"]');
$page
->pressButton($fieldName);
$this
->assertWaitOnAjaxRequest();
}
protected function assertPageTitle($expectedTitle) {
$driver = $this
->getSession()
->getDriver();
if ($driver instanceof Selenium2Driver) {
$actualTitle = $driver
->getWebDriverSession()
->title();
static::assertEquals($expectedTitle, $actualTitle, 'Title found');
}
else {
$this
->assertSession()
->titleEquals($expectedTitle);
}
}
public function fillCkEditor($ckEditorCssSelector, $text) {
$ckEditorId = $this
->getCkEditorId($ckEditorCssSelector);
$this
->getSession()
->getDriver()
->executeScript("CKEDITOR.instances[\"{$ckEditorId}\"].insertHtml(\"{$text}\");");
}
public function selectCkEditorElement($ckEditorCssSelector, $childIndex) {
$ckEditorId = $this
->getCkEditorId($ckEditorCssSelector);
$this
->getSession()
->getDriver()
->executeScript("let selection = CKEDITOR.instances[\"{$ckEditorId}\"].getSelection(); selection.selectElement(selection.root.getChild({$childIndex})); var ranges = selection.getRanges(); ranges[0].setEndBefore(ranges[0].getBoundaryNodes().endNode); selection.selectRanges(ranges);");
}
public function assertCkEditorContent($ckEditorCssSelector, $expectedContent) {
$ckEditorId = $this
->getCkEditorId($ckEditorCssSelector);
$ckEditorContent = $this
->getSession()
->getDriver()
->evaluateScript("return CKEDITOR.instances[\"{$ckEditorId}\"].getData();");
static::assertEquals($expectedContent, $ckEditorContent);
}
public function setRawFieldValue($fieldName, $rawValue) {
$this
->getSession()
->executeScript("jQuery('[name=\"{$fieldName}\"]').val('{$rawValue}')");
}
public function expandAllTabs($maxLevel = 3) {
$jsScript = 'jQuery(\'details.js-form-wrapper.form-wrapper:not([open]) > summary\').click().length';
$numOfOpen = $this
->getSession()
->evaluateScript($jsScript);
$this
->assertWaitOnAjaxRequest();
for ($i = 0; $i < $maxLevel && $numOfOpen > 0; $i++) {
$numOfOpen = $this
->getSession()
->evaluateScript($jsScript);
$this
->assertWaitOnAjaxRequest();
}
}
public function runCron() {
$this
->drupalGet('admin/config/system/cron');
$this
->getSession()
->getPage()
->find('xpath', '//input[@name="op"]')
->click();
}
protected function clickSave() {
$page = $this
->getSession()
->getPage();
$page
->find('xpath', '//div[@data-drupal-selector="edit-actions"]/input[@id="edit-submit"]')
->click();
}
protected function setPublishedStatus($status = TRUE) {
$page = $this
->getSession()
->getPage();
$this
->scrollElementInView('#edit-status-value');
if ($status) {
$page
->find('xpath', '//*[@id="edit-status-value"]')
->check();
}
else {
$page
->find('xpath', '//*[@id="edit-status-value"]')
->uncheck();
}
}
protected function setModerationState($state) {
$page = $this
->getSession()
->getPage();
$page
->find('xpath', '//*[@id="edit-moderation-state-0"]')
->selectOption($state);
}
protected function isForkPullRequest() {
$pullRequestSlag = getenv('TRAVIS_PULL_REQUEST_SLUG');
$repoSlag = getenv('TRAVIS_REPO_SLUG');
return !empty($pullRequestSlag) && $pullRequestSlag !== $repoSlag;
}
protected function getCkEditorId($ckEditorCssSelector) {
$this
->getSession()
->wait(10000, "(waitForCk = CKEDITOR.instances[jQuery(\"{$ckEditorCssSelector}\").attr('id')]) && waitForCk.instanceReady");
$ckEditor = $this
->getSession()
->getPage()
->find('css', $ckEditorCssSelector);
return $ckEditor
->getAttribute('id');
}
public function assertWaitOnAjaxRequest($timeout = 10000, $message = 'Unable to complete AJAX request.') {
$attach_error_handler = <<<JS
(function() {
window.addEventListener('error', function (event) {
document.body.innerHTML += '<div class="ajax-error">' + event.message + '</div>';
});
}());
JS;
$this
->getSession()
->evaluateScript($attach_error_handler);
usleep(5000);
$condition = <<<JS
(function() {
function isAjaxing(instance) {
return instance && instance.ajaxing === true;
}
return (
// Assert no AJAX request is running (via jQuery or Drupal) and no
// animation is running.
(typeof jQuery === 'undefined' || (jQuery.active === 0 && jQuery(':animated').length === 0)) &&
(typeof Drupal === 'undefined' || typeof Drupal.ajax === 'undefined' || !Drupal.ajax.instances.some(isAjaxing))
);
}())
JS;
$result = $this
->getSession()
->wait($timeout, $condition);
if (!$result) {
$rows = Database::getConnection()
->select('watchdog', 'w')
->fields('w')
->condition('type', 'php')
->orderBy('wid', 'DESC')
->execute()
->fetchAll();
$php_log_entries = [];
foreach ($rows as $row) {
$variables = @unserialize($row->variables);
if ($variables === NULL) {
$message = Xss::filterAdmin($row->message);
}
else {
$message = new FormattableMarkup(Xss::filterAdmin($row->message), $variables);
}
$php_log_entries[] = (string) $message;
}
$this
->assertSame([], $php_log_entries);
$errors = $this
->getSession()
->getPage()
->findAll('css', '.ajax-error');
foreach ($errors as $error) {
$message .= ' ' . $error
->getText();
}
throw new \RuntimeException($message);
}
}
}