Question

I have a reporting page that is basically a table you can add and remove columns from. When you add a column, the data for that column is fetched and loaded with ajax, using angular.

Consider this Behat scenario:

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"

How can I make Behat wait until angular's ajax call completes? I would like to avoid using a sleep, since sleeps add unnecessary delay and will fail if the call takes too long.

I used the following to wait for jquery code:

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

I haven't found a similar value to check with angular.

No correct solution

OTHER TIPS

Your link above was helpful, just to expand on it and save someone else a little time.

/**
 * @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']
    );
}

Then in your Scenario use:

Then I should see "Something on the page." if I wait "5"

You can use code from Angular's Protractor library to wait for loading. Here you can find a function waitForAngular(). It simply waits for a client-side function with the same name Here's working PHP code.

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');
    }  
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top