How To Set Pageload Timeout For Selenium With Behat

During testing work, I’ve noticed that sometimes Behat hangs itself by infinite waiting for answer from Selenium. I’ve figured out that I need to configure Selenium timeouts. But how…

Mink has a very weird documentation about settings timeouts. That’s because Mink itself is a just an abstraction layer and a factory of browser drivers.

So, we need to make Mink call some Selenium API function to get this work. Another problem is that Behat\Mink\Driver\DriverInterface itself has no setTimeouts() function.

Let’s take a closer look into Behat\Mink\Driver\Selenium2Driver which implements this interface:

<?php
class Selenium2Driver extends CoreDriver
{
    /**
     * Sets the timeouts to apply to the webdriver session
     * @param array $timeouts The session timeout settings: Array of {script, implicit, page} => time in microsecconds
     * @throws DriverException
     */
    public function setTimeouts($timeouts)
    {
        $this->timeouts = $timeouts;

        if ($this->isStarted()) {
            $this->applyTimeouts();
        }
    }
    
}

Okay, looks like we’ve got that we need, but… that doesn’t work at all!

<?php
$session = $this->mink->getSession($this->lastSession);
if ($driver instanceof Selenium2Driver) {
    $driver->setTimeouts(['page' => 10000]);
}

return $session;

My Session manager initializes the session this way. Nothing changes, some pages still hang the process.

Going deeper!

Selenium2Driver::applyTimeouts() function calls \WebDriver\Session::timeouts() internally. This function is here:

<?php
/**
 * timeouts methods: /session/:sessionId/timeouts (POST)
 * - $session->timeouts($json) - set timeout for an operation
 * - $session->timeouts()->method() - chaining
 *
 * @return \WebDriver\Session|\WebDriver\Timeouts
 */
public function timeouts()
{
    // set timeouts
    if (func_num_args() === 1) {
        $arg = func_get_arg(0); // json

        $this->curl('POST', '/timeouts', $arg);

        return $this;
    }

    if (func_num_args() === 2) {
        $arg = array(
            'type' => func_get_arg(0), // 'script' or 'implicit'
            'ms' => func_get_arg(1),   // timeout in milliseconds
        );

        $this->curl('POST', '/timeouts', $arg);

        return $this;
    }

    // chaining
    return new Timeouts($this->url . '/timeouts');
}

Okay, it knows nothing about ‘page’ type as described in comments…

Solution

After some investigation with Google and Selenium API I found out that timeout type I’m interested in is called ‘page load’

So,

<?php $driver->setTimeouts(['page load' => 10000]);

makes the trick! There is no mention of this nor in Mink docs nor in the code. Maybe, I’ll save a few hours for somebody by publishing this:)

Alex Panshin avatar
About Alex Panshin
Software Engineer from Russia. Interested in PHP, Scala, microservices and Big/Fast Data stuff.
comments powered by HyperComments