WebDriverTest.php 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. <?php
  2. /**
  3. * Copyright 2014-2017 Anthon Pang. All Rights Reserved.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. * @package WebDriver
  18. *
  19. * @author Anthon Pang <apang@softwaredevelopment.ca>
  20. * @author Damian Mooyman <damian@silverstripe.com>
  21. */
  22. namespace Test\WebDriver;
  23. use WebDriver\ServiceFactory;
  24. use WebDriver\WebDriver;
  25. /**
  26. * Test WebDriver\WebDriver class
  27. *
  28. * @package WebDriver
  29. *
  30. * @group Functional
  31. */
  32. class WebDriverTest extends \PHPUnit_Framework_TestCase
  33. {
  34. private $driver;
  35. private $session;
  36. private $testDocumentRootUrl = 'http://localhost';
  37. private $testSeleniumRootUrl = 'http://localhost:4444/wd/hub';
  38. /**
  39. * {@inheritdoc}
  40. */
  41. protected function setUp()
  42. {
  43. ServiceFactory::getInstance()->setServiceClass('service.curl', '\\WebDriver\\Service\\CurlService');
  44. if ($url = getenv('ROOT_URL')) {
  45. $this->testDocumentRootUrl = $url;
  46. }
  47. if ($url = getenv('SELENIUM_URL')) {
  48. $this->testSeleniumRootUrl = $url;
  49. }
  50. $this->driver = new WebDriver($this->getTestSeleniumRootUrl());
  51. $this->session = null;
  52. }
  53. /**
  54. * {@inheritdoc}
  55. */
  56. protected function tearDown()
  57. {
  58. if ($this->session) {
  59. $this->session->close();
  60. }
  61. }
  62. /**
  63. * Returns the full url to the test site (corresponding to the root dir of the library).
  64. * You can set this via env var ROOT_URL
  65. *
  66. * @return string
  67. */
  68. protected function getTestDocumentRootUrl()
  69. {
  70. return $this->testDocumentRootUrl;
  71. }
  72. /**
  73. * Returns the full url to the Selenium server used for functional tests
  74. *
  75. * @return string
  76. *
  77. * @todo make this configurable via env var
  78. */
  79. protected function getTestSeleniumRootUrl()
  80. {
  81. return $this->testSeleniumRootUrl;
  82. }
  83. /**
  84. * Is Selenium down?
  85. *
  86. * @param \Exception $exception
  87. *
  88. * @return boolean
  89. */
  90. protected function isSeleniumDown($exception)
  91. {
  92. return preg_match('/Failed to connect to .* Connection refused/', $exception->getMessage()) != false
  93. || strpos($exception->getMessage(), 'couldn\'t connect to host') !== false
  94. || strpos($exception->getMessage(), 'Unable to connect to host') !== false;
  95. }
  96. /**
  97. * Test driver sessions
  98. */
  99. public function testSessions()
  100. {
  101. try {
  102. $this->assertCount(0, $this->driver->sessions());
  103. $this->session = $this->driver->session();
  104. } catch (\Exception $e) {
  105. if ($this->isSeleniumDown($e)) {
  106. $this->markTestSkipped('selenium server not running');
  107. return;
  108. }
  109. throw $e;
  110. }
  111. $this->assertCount(1, $this->driver->sessions());
  112. $this->assertEquals($this->getTestSeleniumRootUrl(), $this->driver->getUrl());
  113. }
  114. /**
  115. * Test driver status
  116. */
  117. public function testStatus()
  118. {
  119. try {
  120. $status = $this->driver->status();
  121. } catch (\Exception $e) {
  122. if ($this->isSeleniumDown($e)) {
  123. $this->markTestSkipped('selenium server not running');
  124. return;
  125. }
  126. throw $e;
  127. }
  128. $this->assertCount(3, $status);
  129. $this->assertTrue(isset($status['java']));
  130. $this->assertTrue(isset($status['os']));
  131. $this->assertTrue(isset($status['build']));
  132. }
  133. /**
  134. * Checks that an error connecting to Selenium gives back the expected exception
  135. */
  136. public function testSeleniumError()
  137. {
  138. try {
  139. $this->driver = new WebDriver($this->getTestSeleniumRootUrl() . '/../invalidurl');
  140. $status = $this->driver->status();
  141. $this->fail('Exception not thrown while connecting to invalid Selenium url');
  142. } catch (\Exception $e) {
  143. if ($this->isSeleniumDown($e)) {
  144. $this->markTestSkipped('selenium server not running');
  145. return;
  146. }
  147. $this->assertEquals('WebDriver\Exception\CurlExec', get_class($e));
  148. }
  149. }
  150. /**
  151. * Checks that a successful command to Selenium which returns an http error response gives back the expected exception
  152. */
  153. public function testSeleniumErrorResponse()
  154. {
  155. try {
  156. $status = $this->driver->status();
  157. } catch (\Exception $e) {
  158. if ($this->isSeleniumDown($e)) {
  159. $this->markTestSkipped('selenium server not running');
  160. return;
  161. }
  162. throw $e;
  163. }
  164. try {
  165. $this->session = $this->driver->session();
  166. $this->session->open($this->getTestDocumentRootUrl().'/test/Assets/index.html');
  167. $element = $this->session->element('id', 'a-quite-unlikely-html-element-id');
  168. $this->fail('Exception not thrown while looking for missing element in page');
  169. } catch (\Exception $e) {
  170. $this->assertEquals('WebDriver\Exception\NoSuchElement', get_class($e));
  171. }
  172. }
  173. /**
  174. * Checks that a successful command to Selenium which returns 'nothing' according to spec does not raise an error
  175. */
  176. public function testSeleniumNoResponse()
  177. {
  178. try {
  179. $status = $this->driver->status();
  180. } catch (\Exception $e) {
  181. if ($this->isSeleniumDown($e)) {
  182. $this->markTestSkipped('selenium server not running');
  183. return;
  184. }
  185. throw $e;
  186. }
  187. $this->session = $this->driver->session();
  188. $timeouts = $this->session->timeouts();
  189. $out = $timeouts->async_script(array('type' => 'implicit', 'ms' => 1000));
  190. $this->assertEquals(null, $out);
  191. }
  192. /**
  193. * Assert that empty response does not trigger exception, but invalid JSON does
  194. */
  195. public function testNonJsonResponse()
  196. {
  197. $mockCurlService = $this->createMock('WebDriver\Service\CurlService');
  198. $mockCurlService->expects($this->once())
  199. ->method('execute')
  200. ->will($this->returnCallback(function ($requestMethod, $url) {
  201. $info = array(
  202. 'url' => $url,
  203. 'request_method' => $requestMethod,
  204. 'http_code' => 200,
  205. );
  206. $result = preg_match('#.*session$#', $url)
  207. ? $result = 'some invalid json'
  208. : $result = '';
  209. return array($result, $info);
  210. }));
  211. ServiceFactory::getInstance()->setService('service.curl', $mockCurlService);
  212. $result = $this->driver->status();
  213. $this->assertNull($result);
  214. // Test /session should error
  215. $this->setExpectedException(
  216. 'WebDriver\Exception\CurlExec',
  217. 'Payload received from webdriver is not valid json: some invalid json'
  218. );
  219. $result = $this->driver->session();
  220. $this->assertNull($result);
  221. }
  222. }