megclaypool
1/14/2019 - 11:15 PM

Behat, MinkExtension & Selenium2 Driver - move, create, delete window or tab (depends on your configurations)

[Behat, MinkExtension & Selenium2 Driver - move, create, delete window or tab (depends on your configurations)]

https://gist.github.com/netraagal/0c8335c310293a3c211c0f8b5cf53b53

<?php
/**
 * some functions to create a new tab/window (it's up to your personal settings),
 * to move between them (to the right, to the left or by it's number in the list of windows.
 * You can also close the current window or close all (the first window will be open as if you
 * close it, the Scenario will fails).
 *
 * I block the actual driver is not an instance of Selenium2 driver, but I don't really remember
 * if it's an obligation :)
 *
 * @author netraagal
 */
namespace App\Features;
use Behat\Mink\Driver\Selenium2Driver;
class WindowFeatureContext extends MinkContext implements SnippetAcceptingContext
{
    /**
     * iOpenANewWindow
     * I use directly count() without -1 because I have noticed the number is not
     * updated directly (if I do count()-1 i will get the second latest)
     *
     * @When /^(?:|I )open a new (?:window|tab)$/
     *
     * @return  FeatureContext
     */
    public function iOpenANewWindow(): self
    {
        $driver = $this->getSession()->getDriver();
        if (!$driver instanceof Selenium2Driver)
            return $this;
        $driver->executeScript("window.open('/','_blank');");        
        $this->iSwitchToTheWindow(count($driver->getWindowNames()), true);
        return $this;
    }
    /**
     * iOpenANewWindowUrl
     *
     * @When /^(?:|I )open (?:|a )new (?:window|tab) on "(?P<url>[^"]+)"$/
     *
     * @param   string  $url
     * @return  FeatureContext
     */
    public function iOpenANewWindowUrl(string $url): self
    {
        $driver = $this->getSession()->getDriver();
        if (!$driver instanceof Selenium2Driver)
            return $this;
        $driver->executeScript("window.open('".$url."','_blank');");        
        $this->iSwitchToTheWindow(count($driver->getWindowNames()), true);
        return $this;
    }
    /**
     * iSwitchToTheWindow
     * the $internalFunction allows me to not be bothered by the problem I mention in the iOpenANewWindow function
     * or if the user want to use a window which do not exists (less than 0 or more than the max of windows)
     *
     * @When /^(?:|I )switch to (?:|the )(?:window|tab) "(?P<nb>\d+)"$/
     *
     * @param   int    $nb
     * @param   bool   $internalFunction
     * @return  FeatureContext
     */
    public function iSwitchToTheWindow(int $nb, bool $internalFunction = false): self
    {
        $driver = $this->getSession()->getDriver();
        if (!$driver instanceof Selenium2Driver)
            return $this;
        $windowNames = $driver->getWindowNames();
        if (!$internalFunction && ( $nb < 0 || $nb >= count($windowNames) ) )
        {
            throw new \Exception(
                sprintf(
                    "Error : index of window out of bounds, given '%b' but number of windows is '%b'",
                    $nb,
                    count($windowNames)
                )
            );
        }
        $driver->switchToWindow($windowNames[$nb-1]);
        return $this;
    }
    /**
     * iSwitchToTheLeftWindow
     * if I am on the first window, as for any browser, I go to the last
     *
     * @When /^(?:|I )switch to (?:|the )left (?:window|tab)$/
     *
     * @return  FeatureContext
     */
    public function iSwitchToTheLeftWindow(): self
    {
        $driver = $this->getSession()->getDriver();
        if (!$driver instanceof Selenium2Driver)
            return $this;
        $windowNames = $driver->getWindowNames();
        $current_window = array_search($driver->getWindowName(), $windowNames);
        if ($current_window === 0)
        {
            $driver->switchToWindow($windowNames[count($windowNames)-1]);
        }
        else {
            $driver->switchToWindow($windowNames[$current_window-1]);
        }
        return $this;
    }
    /**
     * iSwitchToTheRightWindow
     * if I am on the last window, as for any browser, I go to the first
     *
     * @When /^(?:|I )switch to (?:|the )right (?:window|tab)$/
     *
     * @return  FeatureContext
     * @throws  Exception
     */
    public function iSwitchToTheRightWindow(): self
    {
        $driver = $this->getSession()->getDriver();
        if (!$driver instanceof Selenium2Driver)
            return $this;
        $windowNames = $driver->getWindowNames();
        $current_window = array_search($driver->getWindowName(), $windowNames);
        if ($current_window === count($windowNames)-1)
        {
            $driver->switchToWindow(0);
        }
        else {
            $driver->switchToWindow($windowNames[$current_window+1]);
        }
        return $this;
    }
    /**
     * reloadTheCurrentWindow
     *
     * @When /^(?:|I )reload (?:|the )current (?:window|tab)$/
     *
     * @return  FeatureContext
     */
    public function reloadTheCurrentWindow(): self
    {
        if (!$this->getSession()->getDriver() instanceof Selenium2Driver)
            return $this;
        $this->getSession()->getDriver()->reload();
        return $this;
    }
    /**
     * iCloseTheCurrentWindow
     *
     * @When /^(?:|I )close (?:|the )current (?:window|tab)$/
     *
     * @return  FeatureContext
     */
    public function iCloseTheCurrentWindow(): self
    {
        if (!$this->getSession()->getDriver() instanceof Selenium2Driver)
            return $this;
        $this->getSession()->getDriver()->executeScript("window.open('','_self').close();");
        
        return $this;
    }
    /**
     * iCloseAllWindows
     * warning : the first tab/window will always be open
     * as the driver must have a page to be functional
     *
     * @When /^(?:|I )close all (?:|the )(?:windows|tabs)$/
     *
     * @return  FeatureContext
     */
    public function iCloseAllWindows(): self
    {
        if (!$this->getSession()->getDriver() instanceof Selenium2Driver)
            return $this;
        $windowNames = $this->getSession()->getDriver()->getWindowNames();
        for ($i = count($windowNames); $i > 0; $i--)
        {
            $this->iSwitchToTheWindow($i, true);
            $this->iCloseTheCurrentWindow();
            $this->waitMilliseconds(500);
        }
        $this->iAmOnHomepage();
        return $this;
    }
}