PageRenderTime 27ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/tests/test_tools/selenium/php/selenium.php

http://prado3.googlecode.com/
PHP | 555 lines | 476 code | 44 blank | 35 comment | 16 complexity | ada6d391ef92a81daed909a1d5582794 MD5 | raw file
Possible License(s): Apache-2.0, IPL-1.0, LGPL-3.0, LGPL-2.1, BSD-3-Clause
  1. <?php
  2. /**
  3. * Selenium PHP driver. Saves the test command in a "out" queue (in session),
  4. * and for each selenese request, remove the first comand from the "out" queue
  5. * and push the results into the "in" queque (also in session). When "out" queque
  6. * is empty, write the results to disk.
  7. *
  8. * Usage: See ../../example.php
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the BSD License.
  12. *
  13. * Copyright(c) 2004 by Wei Zhuo. All rights reserved.
  14. *
  15. * To contact the author write to {@link mailto:weizhuo[at]gmail[dot]com Wei Zhuo}
  16. * The latest version of PRADO can be obtained from:
  17. * {@link http://prado.sourceforge.net/}
  18. *
  19. * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
  20. * @version $Id: selenium.php 1771 2007-03-26 00:27:59Z xue $
  21. * @package Prado.tests
  22. */
  23. /**
  24. * Selenium automatic client runner,
  25. *
  26. * @author Wei Zhuo<weizhuo[at]gmail[dot]com>
  27. * @version $Id: selenium.php 1771 2007-03-26 00:27:59Z xue $
  28. * @package Prado.tests
  29. */
  30. require_once(dirname(__FILE__).'/results.php');
  31. class SeleniumTestRunner
  32. {
  33. protected $driver;
  34. protected $base_dir = '';
  35. public function __construct($driver=null, $base_dir='../javascript/')
  36. {
  37. if(is_null($driver) && !(php_sapi_name() == 'cli'))
  38. $driver = $_SERVER['SCRIPT_NAME'];
  39. $this->driver = $driver;
  40. $this->base_dir = $base_dir;
  41. }
  42. public function render()
  43. {
  44. if((php_sapi_name() == 'cli')) return;
  45. $file = dirname(__FILE__).'/TestRunner.php';
  46. $driver = $this->driver;
  47. //$base_dir = $this->base_dir;
  48. $base_dir = $driver.'?sr=';
  49. include($file);
  50. }
  51. public function getDriver()
  52. {
  53. return $this->driver;
  54. }
  55. }
  56. class SeleniumTestStorage
  57. {
  58. protected $outputs = array();
  59. protected $tests = array();
  60. protected $options=array();
  61. public function getTests()
  62. {
  63. return $this->tests;
  64. }
  65. public function getOptions()
  66. {
  67. return $this->options;
  68. }
  69. public function addOption($test_name, $option)
  70. {
  71. $this->options[$test_name] = $option;
  72. }
  73. public function addCommand($test_case_id, $command)
  74. {
  75. $data = array($test_case_id, $command);
  76. array_push($this->outputs, $data);
  77. }
  78. public function getCommand()
  79. {
  80. return array_shift($this->outputs);
  81. }
  82. public function addTestCase($command, $trace_details, $test_name, $test_suite)
  83. {
  84. $data = array(0, 0, $command, "", $trace_details, $test_name, $test_suite);
  85. array_push($this->tests, $data);
  86. }
  87. }
  88. class SeleneseInterpreter
  89. {
  90. protected $storage;
  91. protected $tracer;
  92. public function __construct($storage, $tracer)
  93. {
  94. $this->storage = $storage;
  95. $this->tracer = $tracer;
  96. }
  97. public function getTests()
  98. {
  99. return $this->storage->getTests();
  100. }
  101. public function getOptions()
  102. {
  103. return $this->storage->getOptions();
  104. }
  105. public function getCommand()
  106. {
  107. $command = $this->storage->getCommand();
  108. return empty($command) ? "|testComplete|||" : "{$command[1]}<{$command[0]}>";
  109. }
  110. public function __call($func, $args)
  111. {
  112. if($func{0} == '_') return;
  113. $trace = debug_backtrace();
  114. if($this->isTestOptionFunction($func,$args,$trace))
  115. return;
  116. $ID = isset($args[0]) ? $args[0] : "";
  117. $value = isset($args[1]) ? $args[1] : "";
  118. if(strpos(strtolower($func),'htmlpresent') || strpos(strtolower($func),'htmlnotpresent'))
  119. $ID = htmlspecialchars($ID);
  120. $command = array($func, $ID, $value);
  121. if(is_int(strpos(strtolower($func), 'visible')))
  122. $this->addCommand(array('pause','250',''),$trace);
  123. return $this->addCommand($command, $trace);
  124. }
  125. protected function isTestOptionFunction($func,$args,$trace)
  126. {
  127. if(strtolower($func)==='skipcondition')
  128. {
  129. list($trace, $test, $suite) = $this->tracer->getTrace($trace);
  130. $this->storage->addOption($test,$args[0]);
  131. return true;
  132. }
  133. return false;
  134. }
  135. protected function addCommand($command, $trace)
  136. {
  137. list($trace, $test, $suite) = $this->tracer->getTrace($trace);
  138. $test_id = $this->storage->addTestCase($command, $trace, $test, $suite);
  139. $this->storage->addCommand($test_id, $command);
  140. }
  141. }
  142. class SeleniumTestTrace
  143. {
  144. protected $root;
  145. public function __construct($root)
  146. {
  147. $this->root = $root;
  148. }
  149. public function getTrace($trace)
  150. {
  151. $group = array_pop($trace);
  152. $info = $trace[3];
  153. $test = $group['args'][0]->getTestList();
  154. $i = count($test);
  155. $name = $test[$i-2].'::'.$test[$i-1];
  156. $suite = $test[0];
  157. unset($info['object']);
  158. /*
  159. for($i = 0; $i < count($info['args']); $i++)
  160. {
  161. if($info['args'][$i] instanceof TControl)
  162. $info['args'][$i] = $info['args'][$i]->ClientID;
  163. }*/
  164. $file = str_replace($this->root, '', $info['file']);
  165. $info['file'] = substr($file, 1);
  166. return array($info, $name, $suite);
  167. }
  168. }
  169. class SimpleSeleniumProxyServer
  170. {
  171. protected $runner;
  172. protected $int;
  173. protected $result_file;
  174. public function __construct($runner, $int, $result_file)
  175. {
  176. $this->int = $int;
  177. $this->runner = $runner;
  178. $this->result_file = $result_file;
  179. }
  180. public function proxy()
  181. {
  182. return $this->int;
  183. }
  184. public static function getInstance($root='/', $result_file='results.dat', $base_dir='selenium/')
  185. {
  186. static $instance;
  187. if(!isset($instance))
  188. {
  189. $storage = new SeleniumTestStorage();
  190. $tracer = new SeleniumTestTrace($root);
  191. $interpreter = new SeleneseInterpreter($storage, $tracer);
  192. $runner = new SeleniumTestRunner(null, $base_dir);
  193. $instance = new SimpleSeleniumProxyServer($runner, $interpreter, $result_file);
  194. }
  195. $instance->serveResults();
  196. return $instance;
  197. }
  198. public function handleRequest()
  199. {
  200. $client = new SeleniumTestRunnerServer($this->int, $this->runner);
  201. $client->serve();
  202. return true;
  203. }
  204. public function serveResults()
  205. {
  206. if(isset($_POST['result']))
  207. {
  208. $result = new SeleniumTestResult();
  209. $reporter = new SeleniumHtmlReporter($result);
  210. $reporter->render();
  211. exit();
  212. }
  213. }
  214. }
  215. class SeleniumTestSuiteWriter
  216. {
  217. protected $suites;
  218. protected $name;
  219. protected $runner;
  220. function __construct($suites, $name, $runner)
  221. {
  222. $this->suites = $suites;
  223. $this->name = $name;
  224. $this->runner = $runner;
  225. }
  226. protected function renderHeader()
  227. {
  228. $base_dir = $this->runner->getDriver().'?sr=';
  229. include(dirname(__FILE__).'/TestSuiteHeader.php');
  230. $contents = <<<EOD
  231. <tr><td><b>{$this->name}</b></td></tr>
  232. EOD;
  233. echo $contents;
  234. }
  235. public function render()
  236. {
  237. $this->renderHeader();
  238. foreach($this->suites as $name => $suite)
  239. {
  240. $file = $suite[0]['trace']['file'];
  241. $file = strtr($file,'\\','/');
  242. $option = $suite[0]['option']===null?'':' unless="'.$suite[0]['option'].'" ';
  243. $url = $this->runner->getDriver()."?case={$name}&file={$file}";
  244. echo "<tr{$option}>\n";
  245. echo "<td><a href=\"{$url}\">{$name}</a></td>\n";
  246. echo "</tr>\n";
  247. }
  248. echo $this->renderFooter();
  249. }
  250. protected function getJsTraceInfo()
  251. {
  252. $contents = "var prado_trace = {};\n";
  253. foreach($this->suites as $name => $suite)
  254. {
  255. $name = $name;
  256. $contents .= "prado_trace['{$name}'] = [";
  257. $cases = array();
  258. foreach($suite as $testcase)
  259. $cases[] = "'".addslashes(htmlspecialchars(serialize($testcase['trace'])))."'";
  260. $contents .= implode(",\n", $cases)."];\n\n";
  261. }
  262. return $contents;
  263. }
  264. protected function renderFooter()
  265. {
  266. $trace = '';//$this->getJsTraceInfo();
  267. $contents = <<<EOD
  268. </tbody>
  269. </table>
  270. <br />
  271. <em>Not supported in this browser</em>
  272. <table id="skippedTests" cellpadding="1"
  273. cellspacing="1"
  274. border="1"
  275. class="selenium">
  276. <tbody>
  277. <tr><td><b>Skipped Tests</b></td></tr>
  278. </tbody>
  279. </table>
  280. <script type="text/javascript">
  281. /*<![CDATA[*/
  282. $trace
  283. /*]]>*/
  284. </script>
  285. </body>
  286. </html>
  287. EOD;
  288. return $contents;
  289. }
  290. }
  291. class SeleniumTestCaseWriter
  292. {
  293. protected $case;
  294. protected $tests;
  295. function __construct($case, $tests)
  296. {
  297. $this->case = $case;
  298. $this->tests = $tests;
  299. }
  300. protected function renderHeader()
  301. {
  302. $contents = <<<EOD
  303. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  304. <html>
  305. <head>
  306. <title>{$this->case}</title>
  307. <meta content="text/html; charset=UTF-8" http-equiv="content-type">
  308. </head>
  309. <body>
  310. <table cellpadding="1" cellspacing="1" border="1" id=TABLE1>
  311. <tbody>
  312. <tr>
  313. <td rowspan="1" colspan="3"><strong>{$this->case}</strong></td>
  314. </tr>
  315. EOD;
  316. return $contents;
  317. }
  318. public function render()
  319. {
  320. echo $this->renderHeader();
  321. foreach($this->tests as $test)
  322. {
  323. $t = $test['test'];
  324. if($t[0] == "open")
  325. $t[1] = "<a href=\"{$t[1]}\" target=\"_blank\">{$t[1]}</a>";
  326. echo "<tr>\n";
  327. echo "<td>{$t[0]}</td>\n";
  328. echo "<td>{$t[1]}</td>\n";
  329. echo "<td>{$t[2]}</td>\n";
  330. echo "</tr>\n";
  331. }
  332. echo $this->renderFooter();
  333. }
  334. protected function renderFooter()
  335. {
  336. $contents = <<<EOD
  337. </tbody>
  338. </table>
  339. </body>
  340. </html>
  341. EOD;
  342. return $contents;
  343. }
  344. }
  345. class SeleniumTestRunnerServer
  346. {
  347. protected $cases = array();
  348. protected $trace = array();
  349. protected $name;
  350. protected $runner;
  351. public function __construct($int, $runner)
  352. {
  353. $this->runner = $runner;
  354. $this->initialize($int);
  355. }
  356. protected function initialize($int)
  357. {
  358. $options = $int->getOptions();
  359. foreach($int->getTests() as $command)
  360. {
  361. $case = $command[5];
  362. $option=isset($options[$case])?$options[$case]:null;
  363. $this->cases[$case][] =
  364. array('test' => $command[2],
  365. 'trace' => $command[4], 'option'=>$option);
  366. if(is_null($this->name))
  367. $this->name = $command[6];
  368. }
  369. }
  370. function serve()
  371. {
  372. if($this->isTestSuiteRequest())
  373. {
  374. $testSuite = new SeleniumTestSuiteWriter($this->cases,
  375. $this->name, $this->runner);
  376. $testSuite->render();
  377. }
  378. else if($this->isTestCaseRequest())
  379. {
  380. if(($case = $this->getTestCaseRequest()) !== false)
  381. {
  382. $testCase = new SeleniumTestCaseWriter($case, $this->getTestCase());
  383. $testCase->render();
  384. }
  385. }
  386. else
  387. {
  388. $this->runner->render();
  389. }
  390. }
  391. protected function isTestSuiteRequest()
  392. {
  393. return isset($_GET['testSuites']);
  394. }
  395. protected function isTestCaseRequest()
  396. {
  397. return isset($_GET['case']);
  398. }
  399. public function isClientRequest()
  400. {
  401. return !$this->isTestSuiteRequest() && !$this->isTestCaseRequest();
  402. }
  403. protected function getTestCaseRequest()
  404. {
  405. $case = $_GET['case'];
  406. if(isset($this->cases[$case]))
  407. return $case;
  408. else return false;
  409. }
  410. protected function getTestCase()
  411. {
  412. $case = $_GET['case'];
  413. if(isset($this->cases[$case]))
  414. return $this->cases[$case];
  415. else
  416. return array();
  417. }
  418. }
  419. class SeleniumTestCase extends UnitTestCase
  420. {
  421. protected $selenium;
  422. protected $Page;
  423. const KONQUEROR='browserVersion.isKonqueror';
  424. const OPERA='browserVersion.isOpera';
  425. const CHROME='browserVersion.isChrome';
  426. const INTERNET_EXPLORER='browserVersion.isIE';
  427. const SAFARI='browserVersion.isSafari';
  428. const KHTML='browserVersion.khtml';
  429. const FIREFOX='browserVersion.isFirefox';
  430. const MOZILLA='browserVersion.isMozilla';
  431. const GECKO='browserVersion.isGecko';
  432. protected $options=array();
  433. function __construct()
  434. {
  435. $server = SimpleSeleniumProxyServer::getInstance();
  436. if(!is_null($server))
  437. $this->selenium = $server->proxy();
  438. parent::__construct();
  439. }
  440. function getPage($class)
  441. {
  442. $info = new ReflectionClass($class);
  443. return Prado::getApplication()->getTestPage($info->getFileName());
  444. }
  445. function __call($func, $args)
  446. {
  447. if(count($args) == 0)
  448. return $this->selenium->{$func}();
  449. else if (count($args) == 1)
  450. return $this->selenium->{$func}($args[0]);
  451. else if (count($args) == 2)
  452. return $this->selenium->{$func}($args[0], $args[1]);
  453. }
  454. function disabled()
  455. {
  456. $this->selenium->skipCondition('DISABLED');
  457. }
  458. function skipBrowsers()
  459. {
  460. $conditions = $this->getBrowserOptions(func_get_args());
  461. $this->selenium->skipCondition($conditions);
  462. }
  463. protected function getBrowserOptions($arg_list)
  464. {
  465. $browsers=array();
  466. foreach($arg_list as $arg)
  467. {
  468. if(is_array($arg))
  469. $browsers[] = '('.implode(' && ', $arg).')';
  470. else
  471. $browsers[] = $arg;
  472. }
  473. return implode(' || ', $browsers);
  474. }
  475. function targetBrowsers()
  476. {
  477. $conditions = $this->getBrowserOptions(func_get_args());
  478. $this->selenium->skipCondition("!(".$conditions.")");
  479. }
  480. }
  481. ?>