Как да накарам 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)');

Не намерих подобна стойност за проверка с angular.


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

Можете да използвате код от библиотеката Tractor на Angular, за да изчакате зареждането. Тук можете да намерите функция 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