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

У меня есть страница отчетов, которая в основном представляет собой таблицу, из которой вы можете добавлять и удалять столбцы. Когда вы добавляете столбец, данные для этого столбца извлекаются и загружаются с помощью ajax, используя angular.

Рассмотрим этот сценарий Behat:

Given I have a user named "Dillinger Four"
And I am on "/reports"
When I add the "User's Name" column
Then I should see "Dillinger Four"

Как я могу заставить Behat дождаться завершения ajax-вызова angular? Я хотел бы избежать использования сна, так как сон добавляет ненужную задержку и не работает, если вызов занимает слишком много времени.

Я использовал следующее для ожидания кода jquery:

$this->getSession()->wait($duration, '(0 === jQuery.active)');

Я не нашел аналогичного значения для проверки с угловым.


person bitlather    schedule 03.03.2014    source источник
comment
У Behat есть функция вращения: docs.behat.org/cookbook/using_spin_functions.html . .. не совсем то, что я искал, но это может быть настолько хорошо, насколько это возможно.   -  person bitlather    schedule 21.03.2014
comment
Ничего лучше спиннинга я тоже не нашел :(   -  person Matthieu Napoli    schedule 20.06.2014


Ответы (2)


Ваша ссылка выше была полезна, просто чтобы расширить ее и сэкономить немного времени кому-то другому.

/**
 * @Then /^I should see "([^"]*)" if I wait "([^"]*)"$/
 */
public function iShouldSeeIfIWait($text, $time)
{
    $this->spin(function($context) use ($text) {
        $this->assertPageContainsText($text);
        return true;
    }, intval($time) );
}


/**
 * Special function to wait until angular has rendered the page fully, it will keep trying until either
 * the condition is meet or the time runs out.
 * 
 * @param  function  $lambda A anonymous function
 * @param  integer $wait   Wait this length of time
 */
public function spin ($lambda, $wait = 60)
{
    for ($i = 0; $i < $wait; $i++)
    {
        try {
            if ($lambda($this)) {
                return true;
            }
        } catch (Exception $e) {
            // do nothing
        }

        sleep(1);
    }

    $backtrace = debug_backtrace();

    throw new Exception(
        "Timeout thrown by " . $backtrace[1]['class'] . "::" . $backtrace[1]['function'] . "()\n" .
        $backtrace[1]['file'] . ", line " . $backtrace[1]['line']
    );
}

Затем в вашем сценарии используйте:

Затем я должен увидеть «Что-то на странице». если я подожду "5"

person Alan Quigley    schedule 28.03.2014

Вы можете использовать код из библиотеки Angular Protractor для ожидания загрузки. Здесь вы можете найти функцию waitForAngular(). Он просто ожидает функции на стороне клиента с тем же именем. Вот рабочий PHP-код.

class WebContext implements Context
{
    /**
     * @Then the list of products should be:
     */
    public function theListOfProductsShouldBe(TableNode $table)
    {
        $this->waitForAngular();
        // ...
    }

    private function waitForAngular()
    {
        // Wait for angular to load
        $this->getSession()->wait(1000, "typeof angular != 'undefined'");
        // Wait for angular to be testable
        $this->getPage()->evaluateScript(
            'angular.getTestability(document.body).whenStable(function() {
                window.__testable = true;
            })'
        );
        $this->getSession()->wait(1000, 'window.__testable == true');
    }  
}
person Eugene Dounar    schedule 18.11.2014
comment
$this->evaluateScript() должно быть $this->getSession()->evaluateScript(). Чтобы это работало, когда мы не знаем, загружен ли angular, я использовал это: ideone.com/JYO7ug — здесь тоже есть наша версия jQuery. - person Jessica; 30.01.2015
comment
На самом деле это вызывает ошибку в моем наборе, я заметил, что когда мой URL-адрес заканчивается на #, когда эта строка выполняется, страница перезагружается без #, что приводит к загрузке совершенно новой страницы. - person Jessica; 23.08.2015