Some information that can help when writing Selenium tests (feel free to improve):
How to setup Selenium?
- CR: Test Drupal using webDriver (https://www.drupal.org/node/2941464)
- #2941560: Add testing with webdriver instructions for other operating systems
The golden rule for stable test
The golden rule remains the same: wait result after js-command, before continuing the test.
# BAD!
$page->pressButton('Show row weights');
$page->selectFieldOption('fields[name][region]', 'content');
# GOOD!
$page->pressButton('Show row weights');
$this->assertSession()->waitForElementVisible('css', '[name="fields[name][region]"]');
$page->selectFieldOption('fields[name][region]', 'content');
How to get response headers and status code?
TL;DR; Give up this desire.
Selenium driver does not support this feature (https://github.com/seleniumhq/selenium-google-code-issue-archive/issues/141).
Yes, this is a super doubtful decision, but that's life.
Here is some list of ideas in case it is absolutely necessary:
- Move part of the test to a lower level (like BTB).
- Implement the logging of headers with the help-test-module (service listening to the Response event).
- Implement the logging with the browser settings (this seems to be able to Firefox, but not to Chrome).
- Get response headers via javascript code, when ajax request.
- Use proxy server, like BrowserMob.
Do not try to decorate any classes from vendor libraries (like instaclick/CurlService). They contain response headers to the request to the driver, but not to the site.
getText() returns empty string for unvisible elements
Therefore, you need to make sure that the element is visible before call $element->getText().
Another solution is a combination getHtml()/strip_tags().
In general, there is a high probability of failure Selenium test for most operations with invisible elements.
Selenium cannot get 'node text' type element.
You can find the element using the text() sign:
# OK!
$page->find('xpath', '//div[text()="I love Selenium"]'));
But you can not get a 'text' element.
# ERROR!
$page->find('css', '#message')->find('xpath', 'text()');
This can be difficult when you want to get outside tags text:
<div id="message">
<span>trash trash</span>I love Selenium
</div>For get 'I love Selenium' you can use various manipulations to delete tags-with-content, or JS script like:
$script = "return jQuery('#message').clone().children().remove().end().text();";
$result = $this->getSession()->evaluateScript($script));
Exception "StaleElementReference"
Unfortunately, I do not know the best solution to this problem (maybe you know?). It is officially considered that it occurs when you are working with an Mink-element that contains a reference to an obsolete HTML-element. But you can get it even with a newly received item :(
A few recommendations to little reduce it for problem places:
- Before get element, make sure that all ajax requests done (
assertWaitOnAjaxRequest(), meh). - Make several attempts using
while() { try/catch }.
The width of the window is sometimes important.
For some css/js rules the width of the browser window is important. By default, the driver runs browser in a fairly narrow window, so be careful. You can use:
$this->getSession()->resizeWindow($width, $height);
#or
$this->getSession()->maximizeWindow()But make sure that the operation done before page loaded (or js-script running).
The 'change'/'click' sometimes do not help
It's not so much about Selenium as Drupal note.
Sometimes for AJAX buttons you need an 'mousedown' event (#2616184-52: Right click should not submit buttons with Ajax behaviors). So, instead of $element->press() (or click()), you need something like:
$this->getSession()->executeScript('jQuery("YOUR-SELECTOR").mousedown();');
Sometimes, for AJAX events you need not only to set value, but also switch the focus, like:
$element->setValue();
$element->blur();
Sometimes, to get the desired effect (example, for hide contextual links), you need to simulate a cursor event:
$element->mouseOver();
$this->getSession()->executeScript("jQuery('YOUR-SELECTOR').trigger('mouseleave')");
Multiple upload file
More stable method to upload 1 file (because it better support remote path):
$field->attachFile($path_to_file);
For multiple upload you can use
$field->setValue(implode("\n", $array_with_paths);
For support remote path see #2947517: Selenium driver: API to get remote file paths.
| Comment | File | Size | Author |
|---|---|---|---|
| #4 | dragTo.patch | 3.83 KB | Anonymous (not verified) |
Comments
Comment #1
Anonymous (not verified) commentedvaplas created an issue. See original summary.
Comment #2
Anonymous (not verified) commentedComment #3
MixologicThis is magnificent. Thank you for documenting all of this.
I started work on merging together the patch in #2942900-49: Convert JavascriptTestBase Tests to use DrupalSelenium2Driver with the existing work and rerolling, I ran into an issue where the tests would pass, but some would randomly fail with
Exception "StaleElementReference"After re-running the random fails I was able to determine that it was *always* related to the
dragTo, and the three places it seems to happen is thus:\Drupal\Tests\field_layout\FunctionalJavascript\FieldLayoutTest
http://cgit.drupalcode.org/drupal/tree/core/modules/field_layout/tests/s...
$field_test_text_row->find('css', '.handle')->dragTo($first_region_row);http://cgit.drupalcode.org/drupal/tree/core/modules/field_layout/tests/s...
and
\Drupal\Tests\field_ui\FunctionalJavascript\EntityDisplayTest
$extra_field_row->find('css', '.handle')->dragTo($disabled_region_row);http://cgit.drupalcode.org/drupal/tree/core/modules/field_ui/tests/src/F...
Still investigating a solution to how to handle these dragTo fields, but I figured I would throw this out there as something to sort out.
Comment #4
Anonymous (not verified) commentedThank you, @Mixologic!
Unfortunately, I can not reproduce the error in these places (obviously due to the slower machine).
However, the our tabledrag.js (or rather field_ui.js) is also a pretty insidious thing. It completely changes the HTML of the table, which even results in the removal of the change messages (#2663738: Moving a field to another region clears the changed fields and message).
Therefore, there are two assumptions about how these places can be strengthened:
Attached the patch to their implementation.
PS:
And yes, looks like in all three places nothing is checked (except maybe risky-checking). Because "Save" button always leads to a 'Your settings have been saved.' message :)
Comment #12
cilefen commented