diff --git a/src/Selenium2Driver.php b/src/Selenium2Driver.php index 05d6e321..4a90e66c 100755 --- a/src/Selenium2Driver.php +++ b/src/Selenium2Driver.php @@ -30,6 +30,8 @@ */ class Selenium2Driver extends CoreDriver { + private const W3C_WINDOW_HANDLE_PREFIX = 'w3cwh:'; + /** * Whether the browser has been started * @var bool @@ -64,6 +66,11 @@ class Selenium2Driver extends CoreDriver */ private $timeouts = array(); + /** + * @var string|null + */ + private $initialWindowHandle = null; + /** * @var Escaper */ @@ -340,6 +347,7 @@ public function start() $this->started = true; $this->applyTimeouts(); + $this->initialWindowHandle = $this->getWebDriverSession()->window_handle(); } /** @@ -395,7 +403,20 @@ public function stop() public function reset() { - $this->getWebDriverSession()->deleteAllCookies(); + $webDriverSession = $this->getWebDriverSession(); + + // Close all windows except the initial one. + foreach ($webDriverSession->window_handles() as $windowHandle) { + if ($windowHandle === $this->initialWindowHandle) { + continue; + } + + $webDriverSession->focusWindow($windowHandle); + $webDriverSession->deleteWindow(); + } + + $this->switchToWindow(); + $webDriverSession->deleteAllCookies(); } public function visit(string $url) @@ -425,7 +446,40 @@ public function back() public function switchToWindow(?string $name = null) { - $this->getWebDriverSession()->focusWindow($name ?: ''); + $handle = $name === null + ? $this->initialWindowHandle + : $this->getWindowHandleFromName($name); + + $this->getWebDriverSession()->focusWindow($handle); + } + + /** + * @throws DriverException + */ + private function getWindowHandleFromName(string $name): string + { + // if name is actually prefixed window handle, just remove the prefix + if (strpos($name, self::W3C_WINDOW_HANDLE_PREFIX) === 0) { + return substr($name, strlen(self::W3C_WINDOW_HANDLE_PREFIX)); + } + + // ..otherwise check if any existing window has the specified name + + $origWindowHandle = $this->getWebDriverSession()->window_handle(); + + try { + foreach ($this->getWebDriverSession()->window_handles() as $handle) { + $this->getWebDriverSession()->focusWindow($handle); + + if ($this->evaluateScript('window.name') === $name) { + return $handle; + } + } + + throw new DriverException("Could not find handle of window named \"$name\""); + } finally { + $this->getWebDriverSession()->focusWindow($origWindowHandle); + } } public function switchToIFrame(?string $name = null) @@ -492,12 +546,29 @@ public function getScreenshot() public function getWindowNames() { - return $this->getWebDriverSession()->window_handles(); + $origWindow = $this->getWebDriverSession()->window_handle(); + + try { + $result = array(); + foreach ($this->getWebDriverSession()->window_handles() as $tempWindow) { + $this->getWebDriverSession()->focusWindow($tempWindow); + $result[] = $this->getWindowName(); + } + return $result; + } finally { + $this->getWebDriverSession()->focusWindow($origWindow); + } } public function getWindowName() { - return $this->getWebDriverSession()->window_handle(); + $name = (string) $this->evaluateScript('window.name'); + + if ($name === '') { + $name = self::W3C_WINDOW_HANDLE_PREFIX . $this->getWebDriverSession()->window_handle(); + } + + return $name; } /** @@ -921,11 +992,13 @@ public function wait(int $timeout, string $condition) public function resizeWindow(int $width, int $height, ?string $name = null) { - $window = $this->getWebDriverSession()->window($name ?: 'current'); - \assert($window instanceof Window); - $window->postSize( - array('width' => $width, 'height' => $height) - ); + $this->withWindow($name, function () use ($width, $height) { + $window = $this->getWebDriverSession()->window('current'); + \assert($window instanceof Window); + $window->postSize( + array('width' => $width, 'height' => $height) + ); + }); } public function submitForm(string $xpath) @@ -935,9 +1008,34 @@ public function submitForm(string $xpath) public function maximizeWindow(?string $name = null) { - $window = $this->getWebDriverSession()->window($name ?: 'current'); - \assert($window instanceof Window); - $window->maximize(); + $this->withWindow($name, function () { + $window = $this->getWebDriverSession()->window('current'); + \assert($window instanceof Window); + $window->maximize(); + }); + } + + private function withWindow(?string $name, callable $callback): void + { + if ($name === null) { + $callback(); + + return; + } + + $origName = $this->getWindowName(); + + try { + if ($origName !== $name) { + $this->switchToWindow($name); + } + + $callback(); + } finally { + if ($origName !== $name) { + $this->switchToWindow($origName); + } + } } /**