1<?php 2 3namespace Facebook\WebDriver\Support\Events; 4 5use Facebook\WebDriver\Exception\UnsupportedOperationException; 6use Facebook\WebDriver\Exception\WebDriverException; 7use Facebook\WebDriver\Interactions\Touch\WebDriverTouchScreen; 8use Facebook\WebDriver\JavaScriptExecutor; 9use Facebook\WebDriver\WebDriver; 10use Facebook\WebDriver\WebDriverBy; 11use Facebook\WebDriver\WebDriverDispatcher; 12use Facebook\WebDriver\WebDriverElement; 13use Facebook\WebDriver\WebDriverOptions; 14use Facebook\WebDriver\WebDriverTargetLocator; 15use Facebook\WebDriver\WebDriverWait; 16 17class EventFiringWebDriver implements WebDriver, JavaScriptExecutor 18{ 19 /** 20 * @var WebDriver 21 */ 22 protected $driver; 23 24 /** 25 * @var WebDriverDispatcher 26 */ 27 protected $dispatcher; 28 29 /** 30 * @param WebDriver $driver 31 * @param WebDriverDispatcher $dispatcher 32 */ 33 public function __construct(WebDriver $driver, WebDriverDispatcher $dispatcher = null) 34 { 35 $this->dispatcher = $dispatcher ?: new WebDriverDispatcher(); 36 if (!$this->dispatcher->getDefaultDriver()) { 37 $this->dispatcher->setDefaultDriver($this); 38 } 39 $this->driver = $driver; 40 } 41 42 /** 43 * @return WebDriverDispatcher 44 */ 45 public function getDispatcher() 46 { 47 return $this->dispatcher; 48 } 49 50 /** 51 * @return WebDriver 52 */ 53 public function getWebDriver() 54 { 55 return $this->driver; 56 } 57 58 /** 59 * @param mixed $url 60 * @throws WebDriverException 61 * @return $this 62 */ 63 public function get($url) 64 { 65 $this->dispatch('beforeNavigateTo', $url, $this); 66 67 try { 68 $this->driver->get($url); 69 } catch (WebDriverException $exception) { 70 $this->dispatchOnException($exception); 71 throw $exception; 72 } 73 $this->dispatch('afterNavigateTo', $url, $this); 74 75 return $this; 76 } 77 78 /** 79 * @param WebDriverBy $by 80 * @throws WebDriverException 81 * @return array 82 */ 83 public function findElements(WebDriverBy $by) 84 { 85 $this->dispatch('beforeFindBy', $by, null, $this); 86 $elements = []; 87 88 try { 89 foreach ($this->driver->findElements($by) as $element) { 90 $elements[] = $this->newElement($element); 91 } 92 } catch (WebDriverException $exception) { 93 $this->dispatchOnException($exception); 94 throw $exception; 95 } 96 97 $this->dispatch('afterFindBy', $by, null, $this); 98 99 return $elements; 100 } 101 102 /** 103 * @param WebDriverBy $by 104 * @throws WebDriverException 105 * @return EventFiringWebElement 106 */ 107 public function findElement(WebDriverBy $by) 108 { 109 $this->dispatch('beforeFindBy', $by, null, $this); 110 111 try { 112 $element = $this->newElement($this->driver->findElement($by)); 113 } catch (WebDriverException $exception) { 114 $this->dispatchOnException($exception); 115 throw $exception; 116 } 117 118 $this->dispatch('afterFindBy', $by, null, $this); 119 120 return $element; 121 } 122 123 /** 124 * @param string $script 125 * @param array $arguments 126 * @throws WebDriverException 127 * @return mixed 128 */ 129 public function executeScript($script, array $arguments = []) 130 { 131 if (!$this->driver instanceof JavaScriptExecutor) { 132 throw new UnsupportedOperationException( 133 'driver does not implement JavaScriptExecutor' 134 ); 135 } 136 137 $this->dispatch('beforeScript', $script, $this); 138 139 try { 140 $result = $this->driver->executeScript($script, $arguments); 141 } catch (WebDriverException $exception) { 142 $this->dispatchOnException($exception); 143 throw $exception; 144 } 145 146 $this->dispatch('afterScript', $script, $this); 147 148 return $result; 149 } 150 151 /** 152 * @param string $script 153 * @param array $arguments 154 * @throws WebDriverException 155 * @return mixed 156 */ 157 public function executeAsyncScript($script, array $arguments = []) 158 { 159 if (!$this->driver instanceof JavaScriptExecutor) { 160 throw new UnsupportedOperationException( 161 'driver does not implement JavaScriptExecutor' 162 ); 163 } 164 165 $this->dispatch('beforeScript', $script, $this); 166 167 try { 168 $result = $this->driver->executeAsyncScript($script, $arguments); 169 } catch (WebDriverException $exception) { 170 $this->dispatchOnException($exception); 171 throw $exception; 172 } 173 $this->dispatch('afterScript', $script, $this); 174 175 return $result; 176 } 177 178 /** 179 * @throws WebDriverException 180 * @return $this 181 */ 182 public function close() 183 { 184 try { 185 $this->driver->close(); 186 187 return $this; 188 } catch (WebDriverException $exception) { 189 $this->dispatchOnException($exception); 190 throw $exception; 191 } 192 } 193 194 /** 195 * @throws WebDriverException 196 * @return string 197 */ 198 public function getCurrentURL() 199 { 200 try { 201 return $this->driver->getCurrentURL(); 202 } catch (WebDriverException $exception) { 203 $this->dispatchOnException($exception); 204 throw $exception; 205 } 206 } 207 208 /** 209 * @throws WebDriverException 210 * @return string 211 */ 212 public function getPageSource() 213 { 214 try { 215 return $this->driver->getPageSource(); 216 } catch (WebDriverException $exception) { 217 $this->dispatchOnException($exception); 218 throw $exception; 219 } 220 } 221 222 /** 223 * @throws WebDriverException 224 * @return string 225 */ 226 public function getTitle() 227 { 228 try { 229 return $this->driver->getTitle(); 230 } catch (WebDriverException $exception) { 231 $this->dispatchOnException($exception); 232 throw $exception; 233 } 234 } 235 236 /** 237 * @throws WebDriverException 238 * @return string 239 */ 240 public function getWindowHandle() 241 { 242 try { 243 return $this->driver->getWindowHandle(); 244 } catch (WebDriverException $exception) { 245 $this->dispatchOnException($exception); 246 throw $exception; 247 } 248 } 249 250 /** 251 * @throws WebDriverException 252 * @return array 253 */ 254 public function getWindowHandles() 255 { 256 try { 257 return $this->driver->getWindowHandles(); 258 } catch (WebDriverException $exception) { 259 $this->dispatchOnException($exception); 260 throw $exception; 261 } 262 } 263 264 /** 265 * @throws WebDriverException 266 */ 267 public function quit() 268 { 269 try { 270 $this->driver->quit(); 271 } catch (WebDriverException $exception) { 272 $this->dispatchOnException($exception); 273 throw $exception; 274 } 275 } 276 277 /** 278 * @param null|string $save_as 279 * @throws WebDriverException 280 * @return string 281 */ 282 public function takeScreenshot($save_as = null) 283 { 284 try { 285 return $this->driver->takeScreenshot($save_as); 286 } catch (WebDriverException $exception) { 287 $this->dispatchOnException($exception); 288 throw $exception; 289 } 290 } 291 292 /** 293 * @param int $timeout_in_second 294 * @param int $interval_in_millisecond 295 * @throws WebDriverException 296 * @return WebDriverWait 297 */ 298 public function wait($timeout_in_second = 30, $interval_in_millisecond = 250) 299 { 300 try { 301 return $this->driver->wait($timeout_in_second, $interval_in_millisecond); 302 } catch (WebDriverException $exception) { 303 $this->dispatchOnException($exception); 304 throw $exception; 305 } 306 } 307 308 /** 309 * @throws WebDriverException 310 * @return WebDriverOptions 311 */ 312 public function manage() 313 { 314 try { 315 return $this->driver->manage(); 316 } catch (WebDriverException $exception) { 317 $this->dispatchOnException($exception); 318 throw $exception; 319 } 320 } 321 322 /** 323 * @throws WebDriverException 324 * @return EventFiringWebDriverNavigation 325 */ 326 public function navigate() 327 { 328 try { 329 return new EventFiringWebDriverNavigation( 330 $this->driver->navigate(), 331 $this->getDispatcher() 332 ); 333 } catch (WebDriverException $exception) { 334 $this->dispatchOnException($exception); 335 throw $exception; 336 } 337 } 338 339 /** 340 * @throws WebDriverException 341 * @return WebDriverTargetLocator 342 */ 343 public function switchTo() 344 { 345 try { 346 return $this->driver->switchTo(); 347 } catch (WebDriverException $exception) { 348 $this->dispatchOnException($exception); 349 throw $exception; 350 } 351 } 352 353 /** 354 * @throws WebDriverException 355 * @return WebDriverTouchScreen 356 */ 357 public function getTouch() 358 { 359 try { 360 return $this->driver->getTouch(); 361 } catch (WebDriverException $exception) { 362 $this->dispatchOnException($exception); 363 throw $exception; 364 } 365 } 366 367 public function execute($name, $params) 368 { 369 try { 370 return $this->driver->execute($name, $params); 371 } catch (WebDriverException $exception) { 372 $this->dispatchOnException($exception); 373 throw $exception; 374 } 375 } 376 377 /** 378 * @param WebDriverElement $element 379 * @return EventFiringWebElement 380 */ 381 protected function newElement(WebDriverElement $element) 382 { 383 return new EventFiringWebElement($element, $this->getDispatcher()); 384 } 385 386 /** 387 * @param mixed $method 388 * @param mixed ...$arguments 389 */ 390 protected function dispatch($method, ...$arguments) 391 { 392 if (!$this->dispatcher) { 393 return; 394 } 395 396 $this->dispatcher->dispatch($method, $arguments); 397 } 398 399 /** 400 * @param WebDriverException $exception 401 */ 402 protected function dispatchOnException(WebDriverException $exception) 403 { 404 $this->dispatch('onException', $exception, $this); 405 } 406} 407