How to make Behat wait for an AJAX call?

前端 未结 3 771
被撕碎了的回忆
被撕碎了的回忆 2020-12-14 12:15

Scenario: Modify and save an incomplete change to a Campaign

Given I click on the Campaign section folder
And I press Save in the selected Campaign
Then I sh         


        
相关标签:
3条回答
  • 2020-12-14 12:46

    This is done by waiting for your outstanding ajax calls to hit 0. jQuery.active will check just that for you.

    In your FeatureContext.php, you can do something like;

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

    And do make sure you use a Mink Driver that runs javascript and ajax (the default does not).

    0 讨论(0)
  • 2020-12-14 12:48

    I do it by waiting for the DOM to change as a result of the Ajax Call. I made a subclass of DocumentElement, calling it AsyncDocumentElement and overriding the findAll method:

    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);
    }
    

    Then in \Behat\Mink\Session I changed the constructor to use that class.

    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;
    }
    

    Once I did this, I found my AngularJS tests were working. So far, I've only tested in Firefox.

    0 讨论(0)
  • 2020-12-14 12:58

    In case you are using Prototypejs (e.g Magento), the equivalent code is:

    public function iShouldSeeAnErrorBalloon($title)
    {
        $this->getSession()->wait($duration, '(0 === Ajax.activeRequestCount)');
        // asserts below
    }
    
    0 讨论(0)
提交回复
热议问题