updated core to 8.6.1 via composer
This commit is contained in:
@@ -2,14 +2,14 @@
|
||||
|
||||
namespace Drupal\FunctionalJavascriptTests\Ajax;
|
||||
|
||||
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
|
||||
/**
|
||||
* Tests Ajax callbacks on FAPI elements.
|
||||
*
|
||||
* @group Ajax
|
||||
*/
|
||||
class AjaxCallbacksTest extends JavascriptTestBase {
|
||||
class AjaxCallbacksTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@@ -23,11 +23,9 @@ class AjaxCallbacksTest extends JavascriptTestBase {
|
||||
|
||||
// Test Ajax callback when date changes.
|
||||
$this->drupalGet('ajax_forms_test_ajax_element_form');
|
||||
$this->assertSession()->responseContains('No date yet selected');
|
||||
$this->getSession()->getPage()->fillField('edit-date', '2016-01-01');
|
||||
$this->assertSession()->assertWaitOnAjaxRequest();
|
||||
$this->assertSession()->responseNotContains('No date yet selected');
|
||||
$this->assertSession()->responseContains('2016-01-01');
|
||||
$this->assertNotEmpty($this->getSession()->getPage()->find('xpath', '//div[@id="ajax_date_value"][text()="No date yet selected"]'));
|
||||
$this->getSession()->executeScript('jQuery("[data-drupal-selector=edit-date]").val("2016-01-01").trigger("change");');
|
||||
$this->assertNotEmpty($this->assertSession()->waitForElement('xpath', '//div[@id="ajax_date_value"]/div[text()="2016-01-01"]'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -37,14 +35,10 @@ class AjaxCallbacksTest extends JavascriptTestBase {
|
||||
|
||||
// Test Ajax callback when datetime changes.
|
||||
$this->drupalGet('ajax_forms_test_ajax_element_form');
|
||||
$this->assertSession()->responseContains('No datetime selected.');
|
||||
$this->getSession()->getPage()->fillField('edit-datetime-date', '2016-01-01');
|
||||
$this->assertSession()->assertWaitOnAjaxRequest();
|
||||
$this->assertSession()->responseNotContains('No datetime selected.');
|
||||
$this->assertSession()->responseContains('2016-01-01');
|
||||
$this->getSession()->getPage()->fillField('edit-datetime-time', '12:00:00');
|
||||
$this->assertSession()->assertWaitOnAjaxRequest();
|
||||
$this->assertSession()->responseContains('2016-01-01 12:00:00');
|
||||
$this->assertNotEmpty($this->getSession()->getPage()->find('xpath', '//div[@id="ajax_datetime_value"][text()="No datetime selected."]'));
|
||||
$this->getSession()->executeScript('jQuery("[data-drupal-selector=edit-datetime-date]").val("2016-01-01");');
|
||||
$this->getSession()->executeScript('jQuery("[data-drupal-selector=edit-datetime-time]").val("12:00:00").trigger("change");');
|
||||
$this->assertNotEmpty($this->assertSession()->waitForElement('xpath', '//div[@id="ajax_datetime_value"]/div[text()="2016-01-01 12:00:00"]'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\FunctionalJavascriptTests\Ajax;
|
||||
|
||||
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
|
||||
use Drupal\Core\Form\FormBuilderInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
|
||||
/**
|
||||
* Tests the usage of form caching for AJAX forms.
|
||||
*
|
||||
* @group Ajax
|
||||
*/
|
||||
class AjaxFormCacheTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['ajax_test', 'ajax_forms_test'];
|
||||
|
||||
/**
|
||||
* Tests the usage of form cache for AJAX forms.
|
||||
*/
|
||||
public function testFormCacheUsage() {
|
||||
/** @var \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface $key_value_expirable */
|
||||
$key_value_expirable = \Drupal::service('keyvalue.expirable')->get('form');
|
||||
$this->drupalLogin($this->rootUser);
|
||||
|
||||
// Ensure that the cache is empty.
|
||||
$this->assertEqual(0, count($key_value_expirable->getAll()));
|
||||
|
||||
// Visit an AJAX form that is not cached, 3 times.
|
||||
$uncached_form_url = Url::fromRoute('ajax_forms_test.commands_form');
|
||||
$this->drupalGet($uncached_form_url);
|
||||
$this->drupalGet($uncached_form_url);
|
||||
$this->drupalGet($uncached_form_url);
|
||||
|
||||
// The number of cache entries should not have changed.
|
||||
$this->assertEqual(0, count($key_value_expirable->getAll()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests AJAX forms in blocks.
|
||||
*/
|
||||
public function testBlockForms() {
|
||||
$this->container->get('module_installer')->install(['block', 'search']);
|
||||
$this->rebuildContainer();
|
||||
$this->container->get('router.builder')->rebuild();
|
||||
$this->drupalLogin($this->rootUser);
|
||||
|
||||
$this->drupalPlaceBlock('search_form_block', ['weight' => -5]);
|
||||
$this->drupalPlaceBlock('ajax_forms_test_block');
|
||||
|
||||
$this->drupalGet('');
|
||||
$session = $this->getSession();
|
||||
|
||||
// Select first option and trigger ajax update.
|
||||
$session->getPage()->selectFieldOption('edit-test1', 'option1');
|
||||
|
||||
// DOM update: The InsertCommand in the AJAX response changes the text
|
||||
// in the option element to 'Option1!!!'.
|
||||
$opt1_selector = $this->assertSession()->waitForElement('css', "select[data-drupal-selector='edit-test1'] option:contains('Option 1!!!')");
|
||||
$this->assertNotEmpty($opt1_selector);
|
||||
$this->assertTrue($opt1_selector->isSelected());
|
||||
|
||||
// Confirm option 3 exists.
|
||||
$page = $session->getPage();
|
||||
$opt3_selector = $page->find('xpath', '//select[@data-drupal-selector="edit-test1"]//option[@value="option3"]');
|
||||
$this->assertNotEmpty($opt3_selector);
|
||||
|
||||
// Confirm success message appears after a submit.
|
||||
$page->findButton('edit-submit')->click();
|
||||
$this->assertSession()->waitForButton('edit-submit');
|
||||
$updated_page = $session->getPage();
|
||||
$updated_page->hasContent('Submission successful.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests AJAX forms on pages with a query string.
|
||||
*/
|
||||
public function testQueryString() {
|
||||
$this->container->get('module_installer')->install(['block']);
|
||||
$this->drupalLogin($this->rootUser);
|
||||
|
||||
$this->drupalPlaceBlock('ajax_forms_test_block');
|
||||
|
||||
$url = Url::fromRoute('entity.user.canonical', ['user' => $this->rootUser->id()], ['query' => ['foo' => 'bar']]);
|
||||
$this->drupalGet($url);
|
||||
|
||||
$session = $this->getSession();
|
||||
// Select first option and trigger ajax update.
|
||||
$session->getPage()->selectFieldOption('edit-test1', 'option1');
|
||||
|
||||
// DOM update: The InsertCommand in the AJAX response changes the text
|
||||
// in the option element to 'Option1!!!'.
|
||||
$opt1_selector = $this->assertSession()->waitForElement('css', "option:contains('Option 1!!!')");
|
||||
$this->assertNotEmpty($opt1_selector);
|
||||
|
||||
$url->setOption('query', [
|
||||
'foo' => 'bar',
|
||||
FormBuilderInterface::AJAX_FORM_REQUEST => 1,
|
||||
MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax',
|
||||
]);
|
||||
$this->assertUrl($url);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
namespace Drupal\FunctionalJavascriptTests\Ajax;
|
||||
|
||||
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
|
||||
/**
|
||||
* Tests the Ajax image buttons work with key press events.
|
||||
*
|
||||
* @group Ajax
|
||||
*/
|
||||
class AjaxFormImageButtonTest extends JavascriptTestBase {
|
||||
class AjaxFormImageButtonTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
namespace Drupal\FunctionalJavascriptTests\Ajax;
|
||||
|
||||
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
|
||||
/**
|
||||
* Performs tests on AJAX forms in cached pages.
|
||||
*
|
||||
* @group Ajax
|
||||
*/
|
||||
class AjaxFormPageCacheTest extends JavascriptTestBase {
|
||||
class AjaxFormPageCacheTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@@ -41,7 +41,6 @@ class AjaxFormPageCacheTest extends JavascriptTestBase {
|
||||
*/
|
||||
public function testSimpleAJAXFormValue() {
|
||||
$this->drupalGet('ajax_forms_test_get_form');
|
||||
$this->assertEquals($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Page was not cached.');
|
||||
$build_id_initial = $this->getFormBuildId();
|
||||
|
||||
// Changing the value of a select input element, triggers a AJAX
|
||||
@@ -55,8 +54,8 @@ class AjaxFormPageCacheTest extends JavascriptTestBase {
|
||||
|
||||
// Wait for the DOM to update. The HtmlCommand will update
|
||||
// #ajax_selected_color to reflect the color change.
|
||||
$green_div = $this->assertSession()->waitForElement('css', "#ajax_selected_color div:contains('green')");
|
||||
$this->assertNotNull($green_div, 'DOM update: The selected color DIV is green.');
|
||||
$green_span = $this->assertSession()->waitForElement('css', "#ajax_selected_color:contains('green')");
|
||||
$this->assertNotNull($green_span, 'DOM update: The selected color SPAN is green.');
|
||||
|
||||
// Confirm the operation of the UpdateBuildIdCommand.
|
||||
$build_id_first_ajax = $this->getFormBuildId();
|
||||
@@ -67,8 +66,8 @@ class AjaxFormPageCacheTest extends JavascriptTestBase {
|
||||
$session->getPage()->selectFieldOption('select', 'red');
|
||||
|
||||
// Wait for the DOM to update.
|
||||
$red_div = $this->assertSession()->waitForElement('css', "#ajax_selected_color div:contains('red')");
|
||||
$this->assertNotNull($red_div, 'DOM update: The selected color DIV is red.');
|
||||
$red_span = $this->assertSession()->waitForElement('css', "#ajax_selected_color:contains('red')");
|
||||
$this->assertNotNull($red_span, 'DOM update: The selected color SPAN is red.');
|
||||
|
||||
// Confirm the operation of the UpdateBuildIdCommand.
|
||||
$build_id_second_ajax = $this->getFormBuildId();
|
||||
@@ -77,7 +76,6 @@ class AjaxFormPageCacheTest extends JavascriptTestBase {
|
||||
// Emulate a push of the reload button and then repeat the test sequence
|
||||
// this time with a page loaded from the cache.
|
||||
$session->reload();
|
||||
$this->assertEquals($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
|
||||
$build_id_from_cache_initial = $this->getFormBuildId();
|
||||
$this->assertEquals($build_id_initial, $build_id_from_cache_initial, 'Build id is the same as on the first request');
|
||||
|
||||
@@ -86,8 +84,8 @@ class AjaxFormPageCacheTest extends JavascriptTestBase {
|
||||
$session->getPage()->selectFieldOption('select', 'green');
|
||||
|
||||
// Wait for the DOM to update.
|
||||
$green_div2 = $this->assertSession()->waitForElement('css', "#ajax_selected_color div:contains('green')");
|
||||
$this->assertNotNull($green_div2, 'DOM update: After reload - the selected color DIV is green.');
|
||||
$green_span2 = $this->assertSession()->waitForElement('css', "#ajax_selected_color:contains('green')");
|
||||
$this->assertNotNull($green_span2, 'DOM update: After reload - the selected color SPAN is green.');
|
||||
|
||||
$build_id_from_cache_first_ajax = $this->getFormBuildId();
|
||||
$this->assertNotEquals($build_id_from_cache_initial, $build_id_from_cache_first_ajax, 'Build id is changed in the simpletest-DOM on first AJAX submission');
|
||||
@@ -98,8 +96,8 @@ class AjaxFormPageCacheTest extends JavascriptTestBase {
|
||||
$session->getPage()->selectFieldOption('select', 'red');
|
||||
|
||||
// Wait for the DOM to update.
|
||||
$red_div2 = $this->assertSession()->waitForElement('css', "#ajax_selected_color div:contains('red')");
|
||||
$this->assertNotNull($red_div2, 'DOM update: After reload - the selected color DIV is red.');
|
||||
$red_span2 = $this->assertSession()->waitForElement('css', "#ajax_selected_color:contains('red')");
|
||||
$this->assertNotNull($red_span2, 'DOM update: After reload - the selected color SPAN is red.');
|
||||
|
||||
$build_id_from_cache_second_ajax = $this->getFormBuildId();
|
||||
$this->assertNotEquals($build_id_from_cache_first_ajax, $build_id_from_cache_second_ajax, 'Build id changes on subsequent AJAX submissions');
|
||||
@@ -115,7 +113,9 @@ class AjaxFormPageCacheTest extends JavascriptTestBase {
|
||||
$this->drupalGet('ajax_validation_test');
|
||||
// Changing the value of the textfield will trigger an AJAX
|
||||
// request/response.
|
||||
$this->getSession()->getPage()->fillField('drivertext', 'some dumb text');
|
||||
$field = $this->getSession()->getPage()->findField('drivertext');
|
||||
$field->setValue('some dumb text');
|
||||
$field->blur();
|
||||
|
||||
// When the AJAX command updates the DOM a <ul> unsorted list
|
||||
// "message__list" structure will appear on the page echoing back the
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\FunctionalJavascriptTests\Ajax;
|
||||
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
|
||||
/**
|
||||
* Tests that form elements in groups work correctly with AJAX.
|
||||
*
|
||||
* @group Ajax
|
||||
*/
|
||||
class AjaxInGroupTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['ajax_forms_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalLogin($this->drupalCreateUser(['access content']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits forms with select and checkbox elements via Ajax.
|
||||
*/
|
||||
public function testSimpleAjaxFormValue() {
|
||||
$this->drupalGet('/ajax_forms_test_get_form');
|
||||
|
||||
$assert_session = $this->assertSession();
|
||||
$assert_session->responseContains('Test group');
|
||||
$assert_session->responseContains('AJAX checkbox in a group');
|
||||
|
||||
$session = $this->getSession();
|
||||
$checkbox_original = $session->getPage()->findField('checkbox_in_group');
|
||||
$this->assertNotNull($checkbox_original, 'The checkbox_in_group is on the page.');
|
||||
$original_id = $checkbox_original->getAttribute('id');
|
||||
|
||||
// Triggers a AJAX request/response.
|
||||
$checkbox_original->check();
|
||||
|
||||
// The response contains a new nested "test group" form element, similar
|
||||
// to the one already in the DOM except for a change in the form build id.
|
||||
$checkbox_new = $assert_session->waitForElement('xpath', "//input[@name='checkbox_in_group' and not(@id='$original_id')]");
|
||||
$this->assertNotNull($checkbox_new, 'DOM update: clicking the checkbox refreshed the checkbox_in_group structure');
|
||||
|
||||
$assert_session->responseContains('Test group');
|
||||
$assert_session->responseContains('AJAX checkbox in a group');
|
||||
$assert_session->responseContains('AJAX checkbox in a nested group');
|
||||
$assert_session->responseContains('Another AJAX checkbox in a nested group');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
namespace Drupal\FunctionalJavascriptTests\Ajax;
|
||||
|
||||
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
|
||||
/**
|
||||
* Tests AJAX responses.
|
||||
*
|
||||
* @group Ajax
|
||||
*/
|
||||
class AjaxTest extends JavascriptTestBase {
|
||||
class AjaxTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@@ -82,4 +82,119 @@ class AjaxTest extends JavascriptTestBase {
|
||||
$this->assertNotContains($fake_library, $libraries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that various AJAX responses with DOM elements are correctly inserted.
|
||||
*
|
||||
* After inserting DOM elements, Drupal JavaScript behaviors should be
|
||||
* reattached and all top-level elements of type Node.ELEMENT_NODE need to be
|
||||
* part of the context.
|
||||
*/
|
||||
public function testInsertAjaxResponse() {
|
||||
$render_single_root = [
|
||||
'pre-wrapped-div' => '<div class="pre-wrapped">pre-wrapped<script> var test;</script></div>',
|
||||
'pre-wrapped-span' => '<span class="pre-wrapped">pre-wrapped<script> var test;</script></span>',
|
||||
'pre-wrapped-whitespace' => ' <div class="pre-wrapped-whitespace">pre-wrapped-whitespace</div>' . "\n",
|
||||
'not-wrapped' => 'not-wrapped',
|
||||
'comment-string-not-wrapped' => '<!-- COMMENT -->comment-string-not-wrapped',
|
||||
'comment-not-wrapped' => '<!-- COMMENT --><div class="comment-not-wrapped">comment-not-wrapped</div>',
|
||||
'svg' => '<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10"><rect x="0" y="0" height="10" width="10" fill="green"/></svg>',
|
||||
'empty' => '',
|
||||
];
|
||||
$render_multiple_root_unwrapper = [
|
||||
'mixed' => ' foo <!-- COMMENT --> foo bar<div class="a class"><p>some string</p></div> additional not wrapped strings, <!-- ANOTHER COMMENT --> <p>final string</p>',
|
||||
'top-level-only' => '<div>element #1</div><div>element #2</div>',
|
||||
'top-level-only-pre-whitespace' => ' <div>element #1</div><div>element #2</div> ',
|
||||
'top-level-only-middle-whitespace-span' => '<span>element #1</span> <span>element #2</span>',
|
||||
'top-level-only-middle-whitespace-div' => '<div>element #1</div> <div>element #2</div>',
|
||||
];
|
||||
|
||||
// This is temporary behavior for BC reason.
|
||||
$render_multiple_root_wrapper = [];
|
||||
foreach ($render_multiple_root_unwrapper as $key => $render) {
|
||||
$render_multiple_root_wrapper["$key--effect"] = '<div>' . $render . '</div>';
|
||||
}
|
||||
|
||||
$expected_renders = array_merge(
|
||||
$render_single_root,
|
||||
$render_multiple_root_wrapper,
|
||||
$render_multiple_root_unwrapper
|
||||
);
|
||||
|
||||
// Checking default process of wrapping Ajax content.
|
||||
foreach ($expected_renders as $render_type => $expected) {
|
||||
$this->assertInsert($render_type, $expected);
|
||||
}
|
||||
|
||||
// Checking custom ajaxWrapperMultipleRootElements wrapping.
|
||||
$custom_wrapper_multiple_root = <<<JS
|
||||
(function($, Drupal){
|
||||
Drupal.theme.ajaxWrapperMultipleRootElements = function (elements) {
|
||||
return $('<div class="my-favorite-div"></div>').append(elements);
|
||||
};
|
||||
}(jQuery, Drupal));
|
||||
JS;
|
||||
$expected = '<div class="my-favorite-div"><span>element #1</span> <span>element #2</span></div>';
|
||||
$this->assertInsert('top-level-only-middle-whitespace-span--effect', $expected, $custom_wrapper_multiple_root);
|
||||
|
||||
// Checking custom ajaxWrapperNewContent wrapping.
|
||||
$custom_wrapper_new_content = <<<JS
|
||||
(function($, Drupal){
|
||||
Drupal.theme.ajaxWrapperNewContent = function (elements) {
|
||||
return $('<div class="div-wrapper-forever"></div>').append(elements);
|
||||
};
|
||||
}(jQuery, Drupal));
|
||||
JS;
|
||||
$expected = '<div class="div-wrapper-forever"></div>';
|
||||
$this->assertInsert('empty', $expected, $custom_wrapper_new_content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert insert.
|
||||
*
|
||||
* @param string $render_type
|
||||
* Render type.
|
||||
* @param string $expected
|
||||
* Expected result.
|
||||
* @param string $script
|
||||
* Script for additional theming.
|
||||
*/
|
||||
public function assertInsert($render_type, $expected, $script = '') {
|
||||
// Check insert to block element.
|
||||
$this->drupalGet('ajax-test/insert-block-wrapper');
|
||||
$this->getSession()->executeScript($script);
|
||||
$this->clickLink("Link html $render_type");
|
||||
$this->assertWaitPageContains('<div class="ajax-target-wrapper"><div id="ajax-target">' . $expected . '</div></div>');
|
||||
|
||||
$this->drupalGet('ajax-test/insert-block-wrapper');
|
||||
$this->getSession()->executeScript($script);
|
||||
$this->clickLink("Link replaceWith $render_type");
|
||||
$this->assertWaitPageContains('<div class="ajax-target-wrapper">' . $expected . '</div>');
|
||||
|
||||
// Check insert to inline element.
|
||||
$this->drupalGet('ajax-test/insert-inline-wrapper');
|
||||
$this->getSession()->executeScript($script);
|
||||
$this->clickLink("Link html $render_type");
|
||||
$this->assertWaitPageContains('<div class="ajax-target-wrapper"><span id="ajax-target-inline">' . $expected . '</span></div>');
|
||||
|
||||
$this->drupalGet('ajax-test/insert-inline-wrapper');
|
||||
$this->getSession()->executeScript($script);
|
||||
$this->clickLink("Link replaceWith $render_type");
|
||||
$this->assertWaitPageContains('<div class="ajax-target-wrapper">' . $expected . '</div>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that page contains an expected value after waiting.
|
||||
*
|
||||
* @param string $expected
|
||||
* A needle text.
|
||||
*/
|
||||
protected function assertWaitPageContains($expected) {
|
||||
$page = $this->getSession()->getPage();
|
||||
$this->assertTrue($page->waitFor(10, function () use ($page, $expected) {
|
||||
// Clear content from empty styles and "processed" classes after effect.
|
||||
$content = str_replace([' class="processed"', ' processed', ' style=""'], '', $page->getContent());
|
||||
return stripos($content, $expected) !== FALSE;
|
||||
}), "Page contains expected value: $expected");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
namespace Drupal\FunctionalJavascriptTests\Ajax;
|
||||
|
||||
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
|
||||
/**
|
||||
* Tests the compatibility of the ajax.es6.js file.
|
||||
*
|
||||
* @group Ajax
|
||||
*/
|
||||
class BackwardCompatibilityTest extends JavascriptTestBase {
|
||||
class BackwardCompatibilityTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\FunctionalJavascriptTests\Ajax;
|
||||
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
|
||||
/**
|
||||
* Tests the throbber.
|
||||
*
|
||||
* @group Ajax
|
||||
*/
|
||||
class ThrobberTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = [
|
||||
'node',
|
||||
'views',
|
||||
'views_ui',
|
||||
'views_ui_test_field',
|
||||
'hold_test',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$admin_user = $this->drupalCreateUser([
|
||||
'administer views',
|
||||
]);
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests theming throbber element.
|
||||
*/
|
||||
public function testThemingThrobberElement() {
|
||||
$session = $this->getSession();
|
||||
$web_assert = $this->assertSession();
|
||||
$page = $session->getPage();
|
||||
|
||||
$custom_ajax_progress_indicator_fullscreen = <<<JS
|
||||
Drupal.theme.ajaxProgressIndicatorFullscreen = function () {
|
||||
return '<div class="custom-ajax-progress-fullscreen"></div>';
|
||||
};
|
||||
JS;
|
||||
$custom_ajax_progress_throbber = <<<JS
|
||||
Drupal.theme.ajaxProgressThrobber = function (message) {
|
||||
return '<div class="custom-ajax-progress-throbber"></div>';
|
||||
};
|
||||
JS;
|
||||
$custom_ajax_progress_message = <<<JS
|
||||
Drupal.theme.ajaxProgressMessage = function (message) {
|
||||
return '<div class="custom-ajax-progress-message">Hold door!</div>';
|
||||
};
|
||||
JS;
|
||||
|
||||
$this->drupalGet('admin/structure/views/view/content');
|
||||
$this->waitForNoElement('.ajax-progress-fullscreen');
|
||||
|
||||
// Test theming fullscreen throbber.
|
||||
$session->executeScript($custom_ajax_progress_indicator_fullscreen);
|
||||
hold_test_response(TRUE);
|
||||
$page->clickLink('Content: Published (grouped)');
|
||||
$this->assertNotNull($web_assert->waitForElement('css', '.custom-ajax-progress-fullscreen'), 'Custom ajaxProgressIndicatorFullscreen.');
|
||||
hold_test_response(FALSE);
|
||||
$this->waitForNoElement('.custom-ajax-progress-fullscreen');
|
||||
|
||||
// Test theming throbber message.
|
||||
$web_assert->waitForElementVisible('css', '[data-drupal-selector="edit-options-group-info-add-group"]');
|
||||
$session->executeScript($custom_ajax_progress_message);
|
||||
hold_test_response(TRUE);
|
||||
$page->pressButton('Add another item');
|
||||
$this->assertNotNull($web_assert->waitForElement('css', '.ajax-progress-throbber .custom-ajax-progress-message'), 'Custom ajaxProgressMessage.');
|
||||
hold_test_response(FALSE);
|
||||
$this->waitForNoElement('.ajax-progress-throbber');
|
||||
|
||||
// Test theming throbber.
|
||||
$web_assert->waitForElementVisible('css', '[data-drupal-selector="edit-options-group-info-group-items-3-title"]');
|
||||
$session->executeScript($custom_ajax_progress_throbber);
|
||||
hold_test_response(TRUE);
|
||||
$page->pressButton('Add another item');
|
||||
$this->assertNotNull($web_assert->waitForElement('css', '.custom-ajax-progress-throbber'), 'Custom ajaxProgressThrobber.');
|
||||
hold_test_response(FALSE);
|
||||
$this->waitForNoElement('.custom-ajax-progress-throbber');
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for an element to be removed from the page.
|
||||
*
|
||||
* @param string $selector
|
||||
* CSS selector.
|
||||
* @param int $timeout
|
||||
* (optional) Timeout in milliseconds, defaults to 10000.
|
||||
*
|
||||
* @todo Remove in https://www.drupal.org/node/2892440.
|
||||
*/
|
||||
protected function waitForNoElement($selector, $timeout = 10000) {
|
||||
$condition = "(typeof jQuery !== 'undefined' && jQuery('$selector').length === 0)";
|
||||
$this->assertJsCondition($condition, $timeout);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\FunctionalJavascriptTests;
|
||||
|
||||
/**
|
||||
* Tests if we can execute JavaScript in the browser.
|
||||
*
|
||||
* @group javascript
|
||||
*/
|
||||
class BrowserWithJavascriptTest extends WebDriverTestBase {
|
||||
|
||||
public function testJavascript() {
|
||||
$this->drupalGet('<front>');
|
||||
$session = $this->getSession();
|
||||
|
||||
$session->resizeWindow(400, 300);
|
||||
$javascript = <<<JS
|
||||
(function(){
|
||||
var w = window,
|
||||
d = document,
|
||||
e = d.documentElement,
|
||||
g = d.getElementsByTagName('body')[0],
|
||||
x = w.innerWidth || e.clientWidth || g.clientWidth,
|
||||
y = w.innerHeight || e.clientHeight|| g.clientHeight;
|
||||
return x == 400 && y == 300;
|
||||
}());
|
||||
JS;
|
||||
$this->assertJsCondition($javascript);
|
||||
}
|
||||
|
||||
public function testAssertJsCondition() {
|
||||
$this->drupalGet('<front>');
|
||||
$session = $this->getSession();
|
||||
|
||||
$session->resizeWindow(500, 300);
|
||||
$javascript = <<<JS
|
||||
(function(){
|
||||
var w = window,
|
||||
d = document,
|
||||
e = d.documentElement,
|
||||
g = d.getElementsByTagName('body')[0],
|
||||
x = w.innerWidth || e.clientWidth || g.clientWidth,
|
||||
y = w.innerHeight || e.clientHeight|| g.clientHeight;
|
||||
return x == 400 && y == 300;
|
||||
}());
|
||||
JS;
|
||||
|
||||
// We expected the following assertion to fail because the window has been
|
||||
// re-sized to have a width of 500 not 400.
|
||||
$this->setExpectedException(\PHPUnit_Framework_AssertionFailedError::class);
|
||||
$this->assertJsCondition($javascript, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests creating screenshots.
|
||||
*/
|
||||
public function testCreateScreenshot() {
|
||||
$this->drupalGet('<front>');
|
||||
$this->createScreenshot('public://screenshot.jpg');
|
||||
$this->assertFileExists('public://screenshot.jpg');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
namespace Drupal\FunctionalJavascriptTests\Core\Form;
|
||||
|
||||
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
|
||||
/**
|
||||
* Tests for form grouping elements.
|
||||
*
|
||||
* @group form
|
||||
*/
|
||||
class FormGroupingElementsTest extends JavascriptTestBase {
|
||||
class FormGroupingElementsTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* Required modules.
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@ use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\Core\Language\Language;
|
||||
use Drupal\Core\Session\UserSession;
|
||||
use Drupal\Core\Test\HttpClientMiddleware\TestHttpClientMiddleware;
|
||||
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
@@ -17,7 +17,7 @@ use Symfony\Component\HttpFoundation\RequestStack;
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class SelectProfileFormTest extends JavascriptTestBase {
|
||||
class SelectProfileFormTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
namespace Drupal\FunctionalJavascriptTests\Core;
|
||||
|
||||
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
|
||||
/**
|
||||
* Tests for the machine name field.
|
||||
*
|
||||
* @group field
|
||||
*/
|
||||
class MachineNameTest extends JavascriptTestBase {
|
||||
class MachineNameTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* Required modules.
|
||||
@@ -59,7 +59,6 @@ class MachineNameTest extends JavascriptTestBase {
|
||||
|
||||
// Get page and session.
|
||||
$page = $this->getSession()->getPage();
|
||||
$assert_session = $this->assertSession();
|
||||
|
||||
// Get elements from the page.
|
||||
$title_1 = $page->findField('machine_name_1_label');
|
||||
@@ -111,6 +110,36 @@ class MachineNameTest extends JavascriptTestBase {
|
||||
|
||||
// Validate if the element contains the correct value.
|
||||
$this->assertEquals($test_values[1]['expected'], $machine_name_1_field->getValue(), 'The ID field value must be equal to the php generated machine name');
|
||||
|
||||
$assert = $this->assertSession();
|
||||
$this->drupalGet('/form-test/form-test-machine-name-validation');
|
||||
|
||||
// Test errors after with no AJAX.
|
||||
$assert->buttonExists('Save')->press();
|
||||
$assert->pageTextContains('Machine-readable name field is required.');
|
||||
// Ensure only the first machine name field has an error.
|
||||
$this->assertTrue($assert->fieldExists('id')->hasClass('error'));
|
||||
$this->assertFalse($assert->fieldExists('id2')->hasClass('error'));
|
||||
|
||||
// Test a successful submit after using AJAX.
|
||||
$assert->fieldExists('Name')->setValue('test 1');
|
||||
$assert->fieldExists('id')->setValue('test_1');
|
||||
$assert->selectExists('snack')->selectOption('apple');
|
||||
$assert->assertWaitOnAjaxRequest();
|
||||
$assert->buttonExists('Save')->press();
|
||||
$assert->pageTextContains('The form_test_machine_name_validation_form form has been submitted successfully.');
|
||||
|
||||
// Test errors after using AJAX.
|
||||
$assert->fieldExists('Name')->setValue('duplicate');
|
||||
$this->assertJsCondition('document.forms[0].id.value === "duplicate"');
|
||||
$assert->fieldExists('id2')->setValue('duplicate2');
|
||||
$assert->selectExists('snack')->selectOption('potato');
|
||||
$assert->assertWaitOnAjaxRequest();
|
||||
$assert->buttonExists('Save')->press();
|
||||
$assert->pageTextContains('The machine-readable name is already in use. It must be unique.');
|
||||
// Ensure both machine name fields both have errors.
|
||||
$this->assertTrue($assert->fieldExists('id')->hasClass('error'));
|
||||
$this->assertTrue($assert->fieldExists('id2')->hasClass('error'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Drupal\FunctionalJavascriptTests\Core\Session;
|
||||
|
||||
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
use Drupal\menu_link_content\Entity\MenuLinkContent;
|
||||
|
||||
/**
|
||||
@@ -10,7 +10,7 @@ use Drupal\menu_link_content\Entity\MenuLinkContent;
|
||||
*
|
||||
* @group session
|
||||
*/
|
||||
class SessionTest extends JavascriptTestBase {
|
||||
class SessionTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
namespace Drupal\FunctionalJavascriptTests\Dialog;
|
||||
|
||||
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
|
||||
/**
|
||||
* Tests the JavaScript functionality of the dialog position.
|
||||
*
|
||||
* @group dialog
|
||||
*/
|
||||
class DialogPositionTest extends JavascriptTestBase {
|
||||
class DialogPositionTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
||||
@@ -3,12 +3,21 @@
|
||||
namespace Drupal\FunctionalJavascriptTests;
|
||||
|
||||
use Behat\Mink\Driver\Selenium2Driver;
|
||||
use WebDriver\ServiceFactory;
|
||||
|
||||
/**
|
||||
* Provides a driver for Selenium testing.
|
||||
*/
|
||||
class DrupalSelenium2Driver extends Selenium2Driver {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct($browserName = 'firefox', $desiredCapabilities = NULL, $wdHost = 'http://localhost:4444/wd/hub') {
|
||||
parent::__construct($browserName, $desiredCapabilities, $wdHost);
|
||||
ServiceFactory::getInstance()->setServiceClass('service.curl', WebDriverCurlService::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
||||
+4
-4
@@ -3,7 +3,7 @@
|
||||
namespace Drupal\FunctionalJavascriptTests\EntityReference;
|
||||
|
||||
use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
|
||||
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
use Drupal\simpletest\ContentTypeCreationTrait;
|
||||
use Drupal\simpletest\NodeCreationTrait;
|
||||
|
||||
@@ -12,7 +12,7 @@ use Drupal\simpletest\NodeCreationTrait;
|
||||
*
|
||||
* @group entity_reference
|
||||
*/
|
||||
class EntityReferenceAutocompleteWidgetTest extends JavascriptTestBase {
|
||||
class EntityReferenceAutocompleteWidgetTest extends WebDriverTestBase {
|
||||
|
||||
use ContentTypeCreationTrait;
|
||||
use EntityReferenceTestTrait;
|
||||
@@ -63,7 +63,7 @@ class EntityReferenceAutocompleteWidgetTest extends JavascriptTestBase {
|
||||
$page = $this->getSession()->getPage();
|
||||
$assert_session = $this->assertSession();
|
||||
|
||||
$autocomplete_field = $page->findField($field_name . '[0][target_id]');
|
||||
$autocomplete_field = $assert_session->waitForElement('css', '[name="' . $field_name . '[0][target_id]"].ui-autocomplete-input');
|
||||
$autocomplete_field->setValue('Test');
|
||||
$this->getSession()->getDriver()->keyDown($autocomplete_field->getXpath(), ' ');
|
||||
$assert_session->waitOnAutocomplete();
|
||||
@@ -87,7 +87,7 @@ class EntityReferenceAutocompleteWidgetTest extends JavascriptTestBase {
|
||||
$this->drupalGet('node/add/page');
|
||||
$page = $this->getSession()->getPage();
|
||||
|
||||
$autocomplete_field = $page->findField($field_name . '[0][target_id]');
|
||||
$autocomplete_field = $assert_session->waitForElement('css', '[name="' . $field_name . '[0][target_id]"].ui-autocomplete-input');
|
||||
$autocomplete_field->setValue('Test');
|
||||
$this->getSession()->getDriver()->keyDown($autocomplete_field->getXpath(), ' ');
|
||||
$assert_session->waitOnAutocomplete();
|
||||
|
||||
@@ -100,6 +100,7 @@ JS;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for a button (input[type=submit|image|button|reset], button) with
|
||||
* specified locator and returns it.
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\FunctionalJavascriptTests;
|
||||
|
||||
/**
|
||||
* Tests Drupal settings retrieval in JavascriptTestBase tests.
|
||||
*
|
||||
* @group javascript
|
||||
*/
|
||||
class JavascriptGetDrupalSettingsTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['test_page_test'];
|
||||
|
||||
/**
|
||||
* Tests retrieval of Drupal settings.
|
||||
*
|
||||
* @see \Drupal\FunctionalJavascriptTests\WebDriverTestBase::getDrupalSettings()
|
||||
*/
|
||||
public function testGetDrupalSettings() {
|
||||
$this->drupalLogin($this->drupalCreateUser());
|
||||
$this->drupalGet('test-page');
|
||||
|
||||
// Check that we can read the JS settings.
|
||||
$js_settings = $this->getDrupalSettings();
|
||||
$this->assertSame('azAZ09();.,\\\/-_{}', $js_settings['test-setting']);
|
||||
|
||||
// Dynamically change the setting using Javascript.
|
||||
$script = <<<EndOfScript
|
||||
(function () {
|
||||
drupalSettings['test-setting'] = 'foo';
|
||||
})();
|
||||
EndOfScript;
|
||||
|
||||
$this->getSession()->evaluateScript($script);
|
||||
|
||||
// Check that the setting has been changed.
|
||||
$js_settings = $this->getDrupalSettings();
|
||||
$this->assertSame('foo', $js_settings['test-setting']);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,200 +2,33 @@
|
||||
|
||||
namespace Drupal\FunctionalJavascriptTests;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Zumba\GastonJS\Exception\DeadClient;
|
||||
@trigger_error('The ' . __NAMESPACE__ . '\JavascriptTestBase is deprecated in Drupal 8.5.x and will be removed before Drupal 9.0.0. Instead, use ' . __NAMESPACE__ . '\WebDriverTestBase. See https://www.drupal.org/node/2945059', E_USER_DEPRECATED);
|
||||
|
||||
use Zumba\Mink\Driver\PhantomJSDriver;
|
||||
|
||||
/**
|
||||
* Runs a browser test using a driver that supports Javascript.
|
||||
* Runs a browser test using PhantomJS.
|
||||
*
|
||||
* Base class for testing browser interaction implemented in JavaScript.
|
||||
*
|
||||
* @deprecated in Drupal 8.6.x, will be removed before Drupal 9.0.0.
|
||||
* Use \Drupal\FunctionalJavascriptTests\WebDriverTestBase instead
|
||||
*
|
||||
* @see https://www.drupal.org/node/2945059
|
||||
*/
|
||||
abstract class JavascriptTestBase extends BrowserTestBase {
|
||||
abstract class JavascriptTestBase extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* To use a webdriver based approach, please use DrupalSelenium2Driver::class.
|
||||
* We will switch the default later.
|
||||
*/
|
||||
protected $minkDefaultDriverClass = PhantomJSDriver::class;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initMink() {
|
||||
if ($this->minkDefaultDriverClass === DrupalSelenium2Driver::class) {
|
||||
$this->minkDefaultDriverArgs = ['chrome', NULL, 'http://localhost:4444/'];
|
||||
}
|
||||
elseif ($this->minkDefaultDriverClass === PhantomJSDriver::class) {
|
||||
// Set up the template cache used by the PhantomJS mink driver.
|
||||
$path = $this->tempFilesDirectory . DIRECTORY_SEPARATOR . 'browsertestbase-templatecache';
|
||||
$this->minkDefaultDriverArgs = [
|
||||
'http://127.0.0.1:8510',
|
||||
$path,
|
||||
];
|
||||
if (!file_exists($path)) {
|
||||
mkdir($path);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return parent::initMink();
|
||||
}
|
||||
catch (DeadClient $e) {
|
||||
$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&');
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
$this->markTestSkipped('An unexpected error occurred while starting Mink: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function tearDown() {
|
||||
if ($this->mink) {
|
||||
// Wait for all requests to finish. It is possible that an AJAX request is
|
||||
// still on-going.
|
||||
$result = $this->getSession()->wait(5000, '(typeof(jQuery)=="undefined" || (0 === jQuery.active && 0 === jQuery(\':animated\').length))');
|
||||
if (!$result) {
|
||||
// If the wait is unsuccessful, there may still be an AJAX request in
|
||||
// progress. If we tear down now, then this AJAX request may fail with
|
||||
// missing database tables, because tear down will have removed them.
|
||||
// Rather than allow it to fail, throw an explicit exception now
|
||||
// explaining what the problem is.
|
||||
throw new \RuntimeException('Unfinished AJAX requests while tearing down a test');
|
||||
}
|
||||
}
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getMinkDriverArgs() {
|
||||
if ($this->minkDefaultDriverClass === DrupalSelenium2Driver::class) {
|
||||
return getenv('MINK_DRIVER_ARGS_WEBDRIVER') ?: getenv('MINK_DRIVER_ARGS_PHANTOMJS') ?: parent::getMinkDriverArgs();
|
||||
}
|
||||
elseif ($this->minkDefaultDriverClass === PhantomJSDriver::class) {
|
||||
return getenv('MINK_DRIVER_ARGS_PHANTOMJS') ?: parent::getMinkDriverArgs();
|
||||
}
|
||||
return parent::getMinkDriverArgs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the element with the given CSS selector is visible.
|
||||
*
|
||||
* @param string $css_selector
|
||||
* The CSS selector identifying the element to check.
|
||||
* @param string $message
|
||||
* Optional message to show alongside the assertion.
|
||||
*
|
||||
* @deprecated in Drupal 8.1.x, will be removed before Drupal 8.3.x. Use
|
||||
* \Behat\Mink\Element\NodeElement::isVisible() instead.
|
||||
*/
|
||||
protected function assertElementVisible($css_selector, $message = '') {
|
||||
$this->assertTrue($this->getSession()->getDriver()->isVisible($this->cssSelectToXpath($css_selector)), $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the element with the given CSS selector is not visible.
|
||||
*
|
||||
* @param string $css_selector
|
||||
* The CSS selector identifying the element to check.
|
||||
* @param string $message
|
||||
* Optional message to show alongside the assertion.
|
||||
*
|
||||
* @deprecated in Drupal 8.1.x, will be removed before Drupal 8.3.x. Use
|
||||
* \Behat\Mink\Element\NodeElement::isVisible() instead.
|
||||
*/
|
||||
protected function assertElementNotVisible($css_selector, $message = '') {
|
||||
$this->assertFalse($this->getSession()->getDriver()->isVisible($this->cssSelectToXpath($css_selector)), $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for the given time or until the given JS condition becomes TRUE.
|
||||
*
|
||||
* @param string $condition
|
||||
* JS condition to wait until it becomes TRUE.
|
||||
* @param int $timeout
|
||||
* (Optional) Timeout in milliseconds, defaults to 10000.
|
||||
* @param string $message
|
||||
* (optional) A message to display with the assertion. If left blank, a
|
||||
* default message will be displayed.
|
||||
*
|
||||
* @throws \PHPUnit_Framework_AssertionFailedError
|
||||
*
|
||||
* @see \Behat\Mink\Driver\DriverInterface::evaluateScript()
|
||||
*/
|
||||
protected function assertJsCondition($condition, $timeout = 10000, $message = '') {
|
||||
$message = $message ?: "Javascript condition met:\n" . $condition;
|
||||
$result = $this->getSession()->getDriver()->wait($timeout, $condition);
|
||||
$this->assertTrue($result, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a screenshot.
|
||||
*
|
||||
* @param string $filename
|
||||
* The file name of the resulting screenshot. If using the default phantomjs
|
||||
* driver then this should be a JPG filename.
|
||||
* @param bool $set_background_color
|
||||
* (optional) By default this method will set the background color to white.
|
||||
* Set to FALSE to override this behaviour.
|
||||
*
|
||||
* @throws \Behat\Mink\Exception\UnsupportedDriverActionException
|
||||
* When operation not supported by the driver.
|
||||
* @throws \Behat\Mink\Exception\DriverException
|
||||
* When the operation cannot be done.
|
||||
*/
|
||||
protected function createScreenshot($filename, $set_background_color = TRUE) {
|
||||
$session = $this->getSession();
|
||||
if ($set_background_color) {
|
||||
$session->executeScript("document.body.style.backgroundColor = 'white';");
|
||||
}
|
||||
$image = $session->getScreenshot();
|
||||
file_put_contents($filename, $image);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function assertSession($name = NULL) {
|
||||
return new WebDriverWebAssert($this->getSession($name), $this->baseUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current Drupal javascript settings and parses into an array.
|
||||
*
|
||||
* Unlike BrowserTestBase::getDrupalSettings(), this implementation reads the
|
||||
* current values of drupalSettings, capturing all changes made via javascript
|
||||
* after the page was loaded.
|
||||
*
|
||||
* @return array
|
||||
* The Drupal javascript settings array.
|
||||
*
|
||||
* @see \Drupal\Tests\BrowserTestBase::getDrupalSettings()
|
||||
*/
|
||||
protected function getDrupalSettings() {
|
||||
$script = <<<EndOfScript
|
||||
(function () {
|
||||
if (typeof drupalSettings !== 'undefined') {
|
||||
return drupalSettings;
|
||||
}
|
||||
})();
|
||||
EndOfScript;
|
||||
|
||||
return $this->getSession()->evaluateScript($script) ?: [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getHtmlOutputHeaders() {
|
||||
// The webdriver API does not support fetching headers.
|
||||
return '';
|
||||
// Return a WebAssert that supports status code and header assertions.
|
||||
return new JSWebAssert($this->getSession($name), $this->baseUrl);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,26 +2,14 @@
|
||||
|
||||
namespace Drupal\FunctionalJavascriptTests;
|
||||
|
||||
use Zumba\Mink\Driver\PhantomJSDriver;
|
||||
|
||||
/**
|
||||
* Runs a browser test using PhantomJS.
|
||||
*
|
||||
* Base class for testing browser interaction implemented in JavaScript.
|
||||
* @deprecated in Drupal 8.6.0, will be removed before Drupal 9.0.0.
|
||||
* Use \Drupal\FunctionalJavascriptTests\WebDriverTestBase instead
|
||||
*
|
||||
* BC layer for testing browser interaction implemented in JavaScript.
|
||||
*/
|
||||
abstract class LegacyJavascriptTestBase extends JavascriptTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $minkDefaultDriverClass = PhantomJSDriver::class;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function assertSession($name = NULL) {
|
||||
// Return a WebAssert that supports status code and header assertions.
|
||||
return new JSWebAssert($this->getSession($name), $this->baseUrl);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
namespace Drupal\FunctionalJavascriptTests\Tests;
|
||||
|
||||
use Behat\Mink\Element\NodeElement;
|
||||
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
|
||||
/**
|
||||
* Tests for the JSWebAssert class.
|
||||
*
|
||||
* @group javascript
|
||||
*/
|
||||
class JSWebAssertTest extends JavascriptTestBase {
|
||||
class JSWebAssertTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* Required modules.
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\FunctionalJavascriptTests;
|
||||
|
||||
use WebDriver\Service\CurlService;
|
||||
use WebDriver\Exception\CurlExec;
|
||||
use WebDriver\Exception as WebDriverException;
|
||||
|
||||
/**
|
||||
* Provides a curl service to interact with Selenium driver.
|
||||
*
|
||||
* Extends WebDriver\Service\CurlService to solve problem with race conditions,
|
||||
* when multiple processes requests.
|
||||
*/
|
||||
class WebDriverCurlService extends CurlService {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function execute($requestMethod, $url, $parameters = NULL, $extraOptions = []) {
|
||||
$extraOptions += [
|
||||
CURLOPT_FAILONERROR => TRUE,
|
||||
];
|
||||
$retries = 0;
|
||||
while ($retries < 10) {
|
||||
try {
|
||||
$customHeaders = [
|
||||
'Content-Type: application/json;charset=UTF-8',
|
||||
'Accept: application/json;charset=UTF-8',
|
||||
];
|
||||
|
||||
$curl = curl_init($url);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
|
||||
|
||||
switch ($requestMethod) {
|
||||
case 'GET':
|
||||
break;
|
||||
|
||||
case 'POST':
|
||||
if ($parameters && is_array($parameters)) {
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($parameters));
|
||||
}
|
||||
else {
|
||||
$customHeaders[] = 'Content-Length: 0';
|
||||
}
|
||||
|
||||
// Suppress "Expect: 100-continue" header automatically added by
|
||||
// cURL that causes a 1 second delay if the remote server does not
|
||||
// support Expect.
|
||||
$customHeaders[] = 'Expect:';
|
||||
|
||||
curl_setopt($curl, CURLOPT_POST, TRUE);
|
||||
break;
|
||||
|
||||
case 'DELETE':
|
||||
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
|
||||
break;
|
||||
|
||||
case 'PUT':
|
||||
if ($parameters && is_array($parameters)) {
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($parameters));
|
||||
}
|
||||
else {
|
||||
$customHeaders[] = 'Content-Length: 0';
|
||||
}
|
||||
|
||||
// Suppress "Expect: 100-continue" header automatically added by
|
||||
// cURL that causes a 1 second delay if the remote server does not
|
||||
// support Expect.
|
||||
$customHeaders[] = 'Expect:';
|
||||
|
||||
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT');
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($extraOptions as $option => $value) {
|
||||
curl_setopt($curl, $option, $value);
|
||||
}
|
||||
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $customHeaders);
|
||||
|
||||
$rawResult = trim(curl_exec($curl));
|
||||
|
||||
$info = curl_getinfo($curl);
|
||||
$info['request_method'] = $requestMethod;
|
||||
|
||||
if (array_key_exists(CURLOPT_FAILONERROR, $extraOptions) && $extraOptions[CURLOPT_FAILONERROR] && CURLE_GOT_NOTHING !== ($errno = curl_errno($curl)) && $error = curl_error($curl)) {
|
||||
curl_close($curl);
|
||||
|
||||
throw WebDriverException::factory(WebDriverException::CURL_EXEC, sprintf("Curl error thrown for http %s to %s%s\n\n%s", $requestMethod, $url, $parameters && is_array($parameters) ? ' with params: ' . json_encode($parameters) : '', $error));
|
||||
}
|
||||
|
||||
curl_close($curl);
|
||||
|
||||
$result = json_decode($rawResult, TRUE);
|
||||
if (isset($result['status']) && $result['status'] === WebDriverException::STALE_ELEMENT_REFERENCE) {
|
||||
usleep(100000);
|
||||
$retries++;
|
||||
continue;
|
||||
}
|
||||
return [$rawResult, $info];
|
||||
}
|
||||
catch (CurlExec $exception) {
|
||||
$retries++;
|
||||
}
|
||||
}
|
||||
throw WebDriverException::factory(WebDriverException::CURL_EXEC, sprintf("Curl error thrown for http %s to %s%s\n\n%s", $requestMethod, $url, $parameters && is_array($parameters) ? ' with params: ' . json_encode($parameters) : '', $error));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\FunctionalJavascriptTests;
|
||||
|
||||
use Behat\Mink\Exception\DriverException;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Zumba\GastonJS\Exception\DeadClient;
|
||||
use Zumba\Mink\Driver\PhantomJSDriver;
|
||||
|
||||
/**
|
||||
* Runs a browser test using a driver that supports Javascript.
|
||||
*
|
||||
* Base class for testing browser interaction implemented in JavaScript.
|
||||
*/
|
||||
abstract class WebDriverTestBase extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* To use a legacy phantomjs based approach, please use PhantomJSDriver::class.
|
||||
*/
|
||||
protected $minkDefaultDriverClass = DrupalSelenium2Driver::class;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initMink() {
|
||||
if ($this->minkDefaultDriverClass === DrupalSelenium2Driver::class) {
|
||||
$this->minkDefaultDriverArgs = ['chrome', NULL, 'http://localhost:4444'];
|
||||
}
|
||||
elseif ($this->minkDefaultDriverClass === PhantomJSDriver::class) {
|
||||
// Set up the template cache used by the PhantomJS mink driver.
|
||||
$path = $this->tempFilesDirectory . DIRECTORY_SEPARATOR . 'browsertestbase-templatecache';
|
||||
$this->minkDefaultDriverArgs = [
|
||||
'http://127.0.0.1:8510',
|
||||
$path,
|
||||
];
|
||||
if (!file_exists($path)) {
|
||||
mkdir($path);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return parent::initMink();
|
||||
}
|
||||
catch (DeadClient $e) {
|
||||
$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&');
|
||||
}
|
||||
catch (DriverException $e) {
|
||||
if ($this->minkDefaultDriverClass === DrupalSelenium2Driver::class) {
|
||||
$this->markTestSkipped("The test wasn't able to connect to your webdriver instance. For more information read core/tests/README.md.\n\nThe original message while starting Mink: {$e->getMessage()}");
|
||||
}
|
||||
else {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
$this->markTestSkipped('An unexpected error occurred while starting Mink: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function tearDown() {
|
||||
if ($this->mink) {
|
||||
// Wait for all requests to finish. It is possible that an AJAX request is
|
||||
// still on-going.
|
||||
$result = $this->getSession()->wait(5000, '(typeof(jQuery)=="undefined" || (0 === jQuery.active && 0 === jQuery(\':animated\').length))');
|
||||
if (!$result) {
|
||||
// If the wait is unsuccessful, there may still be an AJAX request in
|
||||
// progress. If we tear down now, then this AJAX request may fail with
|
||||
// missing database tables, because tear down will have removed them.
|
||||
// Rather than allow it to fail, throw an explicit exception now
|
||||
// explaining what the problem is.
|
||||
throw new \RuntimeException('Unfinished AJAX requests while tearing down a test');
|
||||
}
|
||||
}
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getMinkDriverArgs() {
|
||||
if ($this->minkDefaultDriverClass === DrupalSelenium2Driver::class) {
|
||||
return getenv('MINK_DRIVER_ARGS_WEBDRIVER') ?: getenv('MINK_DRIVER_ARGS_PHANTOMJS') ?: parent::getMinkDriverArgs();
|
||||
}
|
||||
elseif ($this->minkDefaultDriverClass === PhantomJSDriver::class) {
|
||||
return getenv('MINK_DRIVER_ARGS_PHANTOMJS') ?: parent::getMinkDriverArgs();
|
||||
}
|
||||
return parent::getMinkDriverArgs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the element with the given CSS selector is visible.
|
||||
*
|
||||
* @param string $css_selector
|
||||
* The CSS selector identifying the element to check.
|
||||
* @param string $message
|
||||
* Optional message to show alongside the assertion.
|
||||
*
|
||||
* @deprecated in Drupal 8.1.0, will be removed before Drupal 9.0.0. Use
|
||||
* \Behat\Mink\Element\NodeElement::isVisible() instead.
|
||||
*/
|
||||
protected function assertElementVisible($css_selector, $message = '') {
|
||||
$this->assertTrue($this->getSession()->getDriver()->isVisible($this->cssSelectToXpath($css_selector)), $message);
|
||||
@trigger_error('The ' . __METHOD__ . ' method is deprecated since version 8.1.0 and will be removed in 9.0.0. Use \Behat\Mink\Element\NodeElement::isVisible() instead.', E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the element with the given CSS selector is not visible.
|
||||
*
|
||||
* @param string $css_selector
|
||||
* The CSS selector identifying the element to check.
|
||||
* @param string $message
|
||||
* Optional message to show alongside the assertion.
|
||||
*
|
||||
* @deprecated in Drupal 8.1.0, will be removed before Drupal 9.0.0. Use
|
||||
* \Behat\Mink\Element\NodeElement::isVisible() instead.
|
||||
*/
|
||||
protected function assertElementNotVisible($css_selector, $message = '') {
|
||||
$this->assertFalse($this->getSession()->getDriver()->isVisible($this->cssSelectToXpath($css_selector)), $message);
|
||||
@trigger_error('The ' . __METHOD__ . ' method is deprecated since version 8.1.0 and will be removed in 9.0.0. Use \Behat\Mink\Element\NodeElement::isVisible() instead.', E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for the given time or until the given JS condition becomes TRUE.
|
||||
*
|
||||
* @param string $condition
|
||||
* JS condition to wait until it becomes TRUE.
|
||||
* @param int $timeout
|
||||
* (Optional) Timeout in milliseconds, defaults to 10000.
|
||||
* @param string $message
|
||||
* (optional) A message to display with the assertion. If left blank, a
|
||||
* default message will be displayed.
|
||||
*
|
||||
* @throws \PHPUnit_Framework_AssertionFailedError
|
||||
*
|
||||
* @see \Behat\Mink\Driver\DriverInterface::evaluateScript()
|
||||
*/
|
||||
protected function assertJsCondition($condition, $timeout = 10000, $message = '') {
|
||||
$message = $message ?: "Javascript condition met:\n" . $condition;
|
||||
$result = $this->getSession()->getDriver()->wait($timeout, $condition);
|
||||
$this->assertTrue($result, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a screenshot.
|
||||
*
|
||||
* @param string $filename
|
||||
* The file name of the resulting screenshot. If using the default phantomjs
|
||||
* driver then this should be a JPG filename.
|
||||
* @param bool $set_background_color
|
||||
* (optional) By default this method will set the background color to white.
|
||||
* Set to FALSE to override this behaviour.
|
||||
*
|
||||
* @throws \Behat\Mink\Exception\UnsupportedDriverActionException
|
||||
* When operation not supported by the driver.
|
||||
* @throws \Behat\Mink\Exception\DriverException
|
||||
* When the operation cannot be done.
|
||||
*/
|
||||
protected function createScreenshot($filename, $set_background_color = TRUE) {
|
||||
$session = $this->getSession();
|
||||
if ($set_background_color) {
|
||||
$session->executeScript("document.body.style.backgroundColor = 'white';");
|
||||
}
|
||||
$image = $session->getScreenshot();
|
||||
file_put_contents($filename, $image);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function assertSession($name = NULL) {
|
||||
return new WebDriverWebAssert($this->getSession($name), $this->baseUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current Drupal javascript settings and parses into an array.
|
||||
*
|
||||
* Unlike BrowserTestBase::getDrupalSettings(), this implementation reads the
|
||||
* current values of drupalSettings, capturing all changes made via javascript
|
||||
* after the page was loaded.
|
||||
*
|
||||
* @return array
|
||||
* The Drupal javascript settings array.
|
||||
*
|
||||
* @see \Drupal\Tests\BrowserTestBase::getDrupalSettings()
|
||||
*/
|
||||
protected function getDrupalSettings() {
|
||||
$script = <<<EndOfScript
|
||||
(function () {
|
||||
if (typeof drupalSettings !== 'undefined') {
|
||||
return drupalSettings;
|
||||
}
|
||||
})();
|
||||
EndOfScript;
|
||||
|
||||
return $this->getSession()->evaluateScript($script) ?: [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getHtmlOutputHeaders() {
|
||||
// The webdriver API does not support fetching headers.
|
||||
return '';
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user