Как заставить Behat ждать вызова AJAX?

Сценарий: Измените и сохраните незавершенное изменение в кампании

Given I click on the Campaign section folder
And I press Save in the selected Campaign
Then I should see an error balloon informing the changes cannot be saved

Дело в том, что этот «баллон с ошибкой» на последнем шаге представляет собой вызов ajax, который затем принесет зеленый или красный шар в зависимости от успеха операции. В настоящее время то, что я делаю, это после «И я нажимаю Сохранить ...», я делаю сон (3), чтобы дать время для появления этого воздушного шара. Это не кажется очень умным, потому что вы тратите время впустую, а также потому, что иногда обработка этого вызова может занять больше или меньше времени.

Как вы, ребята, заставляете свои поведенческие тесты ждать завершения Ajax, а не просто усыплять зверей?

большое спасибо за любой отзыв!


person Community    schedule 25.09.2012    source источник


Ответы (3)


Это делается путем ожидания того, что ваши невыполненные вызовы ajax достигнут 0. jQuery.active проверит именно это для вас.

В вашем FeatureContext.php вы можете сделать что-то вроде;

public function iShouldSeeAnErrorBalloon($title)
{
    $time = 5000; // time should be in milliseconds
    $this->getSession()->wait($time, '(0 === jQuery.active)');
    // asserts below
}

И убедитесь, что вы используете драйвер Mink, который запускает javascript и ajax (по умолчанию это не так).

person Clarence    schedule 25.09.2012

Я делаю это, ожидая изменения DOM в результате вызова Ajax. Я создал подкласс DocumentElement, назвав его AsyncDocumentElement и переопределив метод findAll:

public function findAll($selector, $locator, $waitms=5000)
{
    $xpath = $this->getSession()->getSelectorsHandler()->selectorToXpath($selector, $locator);

    // add parent xpath before element selector
    if (0 === strpos($xpath, '/')) {
        $xpath = $this->getXpath().$xpath;
    } else {
        $xpath = $this->getXpath().'/'.$xpath;
    }

    $page = $this->getSession()->getPage();

    // my code to wait until the xpath expression provides an element
    if ($waitms && !($this->getSession()->getDriver() instanceof \Behat\Symfony2Extension\Driver\KernelDriver)) {
        $templ = 'document.evaluate("%s", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null ).snapshotLength > 0;';

        $waitJs = sprintf($templ, $xpath);

        $this->getSession()->wait($waitms, $waitJs);
    }

    return $this->getSession()->getDriver()->find($xpath);
}

Затем в \Behat\Mink\Session я изменил конструктор, чтобы использовать этот класс.

public function __construct(DriverInterface $driver, SelectorsHandler $selectorsHandler = null)
{
    $driver->setSession($this);

    if (null === $selectorsHandler) {
        $selectorsHandler = new SelectorsHandler();
    }

    $this->driver           = $driver;
    $this->page             = new AsyncDocumentElement($this);
    $this->selectorsHandler = $selectorsHandler;
}

Как только я это сделал, я обнаружил, что мои тесты AngularJS работают. Пока я тестировал только в Firefox.

person krewmarco    schedule 28.10.2014

Если вы используете Prototypejs (например, Magento), эквивалентный код:

public function iShouldSeeAnErrorBalloon($title)
{
    $this->getSession()->wait($duration, '(0 === Ajax.activeRequestCount)');
    // asserts below
}
person Hiep Ho    schedule 12.11.2013
comment
откуда взялась переменная $duration? - person Mladen Danic; 07.04.2014
comment
mink.behat.org/api/behat/mink/session. html#подождите() public void wait(integer time, string condition) Waits some time or until JS condition turns true. - person Steff; 22.05.2014
comment
Просто обновляю эту ссылку, хотя, поскольку я использовал номера строк, она, несомненно, скоро устареет: github.com/Behat/Mink/blob/master/src/Behat/Mink/ - person DanielM; 21.10.2014