Open brooke-heaton opened 4 years ago
iWaitForAjaxtoFinish() is also failing for me.
I'm using Drupal Extension 4.1.0 on Drupal 8.9.1.
I have my site set up locally using lando; when I run the tests there, "I wait for AJAX to finish" works as expected.
Lando is using the selenium/standalone-chrome-debug docker image.
However, when I push my changes to github and a build is triggered via CircleCI on Pantheon, the "I wait for AJAX to finish" step gives me the following error:
Pantheon CircleCI uses DMore\Chromedriver instead of selenium standalone chrome:
# Dynamically set Behat configuration parameters
export BEHAT_PARAMS='{"extensions" : {"Behat\\MinkExtension" : {"base_url" : "https://'$TERMINUS_ENV'-'$TERMINUS_SITE'.pantheonsite.io/"}, "Drupal\\DrupalExtension" : {"drush" : { "alias": "@pantheon.'$TERMINUS_SITE'.'$TERMINUS_ENV'" }, { "root": "/app/web" }}}}'
# Start headless Chrome
echo "\n Starting Chrome in headless mode ..."
google-chrome --disable-gpu --headless --remote-debugging-address=0.0.0.0 --remote-debugging-port=9222 --no-sandbox </dev/null &>/dev/null &
Browser crashed (Behat\Mink\Exception\DriverException)
│
╳ Fatal error: Call to a member function call() on null (Behat\Testwork\Call\Exception\FatalThrowableError)
│
└─ @AfterStep # FailAid\Context\FailureContext::gatherStateFactsAfterFailedStep()
Internal error
I also get the same browser crash with code like this:
/**
* Wait for a element.
*
* https://stackoverflow.com/a/49117368/1209486
*
* @When (I )wait :count second(s) until I see the :element element
*/
public function iWaitSecondsForElement($seconds, $element) {
$timeout = $seconds * 1000;
$page = $this->getSession()->getPage();
$page->waitFor("$timeout",
function () use ($page, $element) {
return $page->find('css', "$element");
}
);
}
In both cases, this error only occurs when testing the Pantheon site via CircleCI; it does not occur locally in lando.
Any news here?
Using drupal/drupal-extension v4.1.0 with Drupal 9.2.9
iWaitForAjaxtoFinish() is failing for us on our local VMs, but, strangely, not on our gitlab-ci.
On the VM, we get many "Unable to complete AJAX request" errors.
Taking a look at MinkContext.php ...
... we see that iWaitForAjaxToFinish()
contains a javascript function which returns false if Ajax is still running, and returns true if Ajax is no longer running.
The problem I am having is that the jQuery.active
property is not always available, and, in the cases where jQuery.active
is not available, jQuery.active === 0
is evaluating to false
. Therefore, the javascript function is returning false
, and the $this->getSession()->wait()
times out.
Here is the pull request: https://github.com/jhedstrom/drupalextension/pull/603
In the PR I made this change to the javascript function, to add the check to see if the jQuery.active property was available: jQuery.hasOwnProperty('active') === false
(admittedly, this is verbose ... it does not have to stay that way ... I did it like this for my own clarity while debugging).
return (
// Assert no AJAX request is running (via jQuery or Drupal) and no
// animation is running.
(typeof jQuery === 'undefined' || jQuery.hasOwnProperty('active') === false || (jQuery.active === 0 && jQuery(':animated').length === 0)) &&
d7_not_ajaxing && d8_not_ajaxing
);
Here is some debug code, this helped me investigate what jQuery.active was doing.
public function iWaitForAjaxToFinish($event = null)
{
// DEBUG
$active = <<<JS
(function() {
if (typeof jQuery === 'undefined') {
return "jQuery === 'undefined'";
}
if (jQuery.hasOwnProperty('active') === false) {
return 'jQuery.hasOwnProperty(\'active\') === false';
}
return jQuery.active;
}());
JS;
$active_result = $this->getSession()->evaluateScript($active);
echo $active_result;
// END DEBUG
Running the behat command I now get output like this:
Sometimes, jQuery.active returns an integer (0). Sometimes, jQuery itself is undefined. Sometimes, jQuery is defined but it has no 'active' property <-- this is the case which was not handled properly and was causing the error.
$ ${BEHAT} --config ${CODEBASE_DIR}/tests/behat/behat.gitlab.yml ${BEHAT_OPTIONS} --tags=comments -vvv
@javascript @api @comments @coretest
Feature: Test comments.
Scenario: I disable Google Recaptcha for testing comments. # features/comments.feature:7
Given I am logged in as a user with the "administrator" role # FeatureContext::assertAuthenticatedByRole()
And I am on "/admin/config/services/vue_comments" # Drupal\DrupalExtension\Context\MinkContext::visit()
Then I uncheck the box "Enable Google Captcha" # Drupal\DrupalExtension\Context\MinkContext::assertUncheckBox()
┌─ @BeforeStep # Drupal\DrupalExtension\Context\MinkContext::beforeJavascriptStep()
│
│ 0
│
Then I press "edit-submit" # Drupal\DrupalExtension\Context\MinkContext::pressButton()
│
│ 0
│
└─ @AfterStep # Drupal\DrupalExtension\Context\MinkContext::afterJavascriptStep()
Then I should see "Die Konfigurationsoptionen wurden gespeichert" # Drupal\DrupalExtension\Context\MinkContext::assertPageContainsText()
Scenario: I comment on a recipe. # features/comments.feature:14
Given I am on "/rezepte/rocher-torte-rezept-mit-nutella" # Drupal\DrupalExtension\Context\MinkContext::visit()
And I wait for "Kommentare zu" # Devinci\DevinciExtension\Context\JavascriptContext::iWaitFor()
And I wait for "Kommentare lesen oder abgeben" # Devinci\DevinciExtension\Context\JavascriptContext::iWaitFor()
┌─ @BeforeStep # Drupal\DrupalExtension\Context\MinkContext::beforeJavascriptStep()
│
│ jQuery === 'undefined'
│
Then I click "Kommentare lesen oder abgeben" # Drupal\DrupalExtension\Context\MinkContext::assertClick()
│
│ jQuery === 'undefined'
│
└─ @AfterStep # Drupal\DrupalExtension\Context\MinkContext::afterJavascriptStep()
And I fill in "comment-name" with "Kommentar Name Behat 1" # Drupal\DrupalExtension\Context\MinkContext::fillField()
And I fill in "comment-text" with "Kommentar Text Behat 1" # Drupal\DrupalExtension\Context\MinkContext::fillField()
┌─ @BeforeStep # Drupal\DrupalExtension\Context\MinkContext::beforeJavascriptStep()
│
│ jQuery.hasOwnProperty('active') === false
│
And I click on ".lupus-comments__top__rating .lupus-rating-star:first-of-type" # ContentContext::clickElement()
│
│ jQuery.hasOwnProperty('active') === false
│
└─ @AfterStep # Drupal\DrupalExtension\Context\MinkContext::afterJavascriptStep()
This looks great! Thanks for diving into that. I can merge the PR as it looks good to me.
Facing the same issue
I'm still facing the same issue even with michaellenahan comment.
In my case, the error happens when I return a 403 or a 500 on purpose. I'd like Behat not to stop there, but to actually validate that a message is displayed to the user.
I did a quick digging around but couldn't figure it out. I actually don't really understand how this test works, basically we wait until the result is false and then throw an error. How does it work when the AJAX callback is actually returning a 200? What is stopping the execution of this function not to throw the \RuntimeException?
From a rough guess, I think what triggers my error is that all Drupal.ajax.instances are done but Behat didn't get a 200 response so continue the execution of iWaitForAjaxToFinish which throws the error and break the scenario execution ...
Created pull request
jQuery.active internal value may have negative value in some cases causing inconsistent test results, as jquery supposedly increments the value when an ajax request starts and decrements it when it finishes, it should not influence the identification of active ajax requests
Hope it helps!
I'm consistently getting null
$result
ondrupal-extension/src/Drupal/DrupalExtension/Context/MinkContext.php:156
I'm not clear on where the failure is but this essentially makes any@javascript
Feature impossible. I'm on Drupal v8.7.8
using Lando with theselenium/standalone-chrome:3.141.59-oxygen
chromedriver on PHP 7.2Full error output for reference: