From 98215a603fb798cdb4178e49061977544aaa45b7 Mon Sep 17 00:00:00 2001 From: wei <> Date: Sat, 10 Dec 2005 11:49:29 +0000 Subject: Initial import selenium functional test framework. --- tests/FunctionalTests/selenium/php/TestRunner.php | 156 +++++++ tests/FunctionalTests/selenium/php/results.php | 166 ++++++++ tests/FunctionalTests/selenium/php/selenium.php | 485 ++++++++++++++++++++++ 3 files changed, 807 insertions(+) create mode 100644 tests/FunctionalTests/selenium/php/TestRunner.php create mode 100644 tests/FunctionalTests/selenium/php/results.php create mode 100644 tests/FunctionalTests/selenium/php/selenium.php (limited to 'tests/FunctionalTests/selenium/php') diff --git a/tests/FunctionalTests/selenium/php/TestRunner.php b/tests/FunctionalTests/selenium/php/TestRunner.php new file mode 100644 index 00000000..fb3cefb3 --- /dev/null +++ b/tests/FunctionalTests/selenium/php/TestRunner.php @@ -0,0 +1,156 @@ + + + + + + + + + + +Prado Functional Test Runner + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Selenium TestRunner

+
+ +
+ Execute Tests + +
+ + + +
+ +
+ + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Elapsed:00.00
TestsCommands
0run0passed
0failed0failed
0incomplete
+ +
+ Tools + + + + +
+ +
+ + + diff --git a/tests/FunctionalTests/selenium/php/results.php b/tests/FunctionalTests/selenium/php/results.php new file mode 100644 index 00000000..2ad9c56b --- /dev/null +++ b/tests/FunctionalTests/selenium/php/results.php @@ -0,0 +1,166 @@ +parse_data(); + $this->browser = $_SERVER['HTTP_USER_AGENT']; + $this->date = time(); + } + + protected function parse_data() + { + $this->result = $_POST['result']; // failed || passed + $this->totalTime = $_POST['totalTime']; + $this->numTestPasses = $_POST['numTestPasses']; + $this->numTestFailures = $_POST['numTestFailures']; + $this->numCommandPasses = $_POST['numCommandPasses']; + $this->numCommandFailures = $_POST['numCommandFailures']; + $this->numCommandErrors = $_POST['numCommandErrors']; + + foreach($_POST['tests'] as $test) + { + $case = new SeleniumTestCaseResult(); + $case->name = $test['testcase']; + $case->commands = $test['commands']; + for($i = 0; $i < count($case->commands); $i++) + { + $trace = $case->commands[$i]['trace']; + $trace = html_entity_decode($trace); + $case->commands[$i]['trace'] = @unserialize($trace); + if($case->commands[$i]['result'] == 'failed') + { + $case->result = 'failed'; + array_push($case->failures, $case->commands[$i]); + } + } + + $this->suites[$case->name] = $case; + } + + } +} + +class SeleniumHtmlReporter +{ + protected $test; + + public function __construct($result) + { + $this->test = $result; + } + + protected function renderHeader() + { + $contents = << + +Functional Test Results + + + + +EOD; + return $contents; + } + + public function render() + { + echo $this->renderHeader(); + echo $this->renderBody(); + echo $this->renderFooter(); + } + + protected function renderBody() + { + /* SeleniumTestResult */ + $test = $this->test; + $total = count($test->suites); + $date = @strftime('%Y-%m-%d %H:%M',$test->date); +$contents = <<Functional Test Results +
+ {$total} test cases completed, + {$test->numTestPasses} passes + ({$test->numCommandPasses} commands), and + {$test->numTestFailures} fails + ({$test->numCommandErrors} commands). +
+
+ {$date}, {$test->browser} +
+EOD; + $count = 1; + foreach($test->suites as $suite) + { + foreach($suite->failures as $error) + $contents .= $this->getErrorMsg($error, $count++); + } + + return $contents; + } + + + protected function getErrorMsg($info, $count) + { + $args = array(); + foreach($info['trace']['args'] as $arg) + $args[] = "'{$arg}'"; + $args = implode(",", $args); + $parity = $count%2==0 ? 'even' : 'odd'; +$msg = << + #{$count}. + "{$info['msg']}" in + + {$info['trace']['class']}::{$info['trace']['function']}({$args}) + + near + + {$info['trace']['file']}:({$info['trace']['line']}) + + +EOD; + return $msg; + } + + protected function renderFooter() + { + return ""; + } +} + + +?> \ No newline at end of file diff --git a/tests/FunctionalTests/selenium/php/selenium.php b/tests/FunctionalTests/selenium/php/selenium.php new file mode 100644 index 00000000..a06a6eab --- /dev/null +++ b/tests/FunctionalTests/selenium/php/selenium.php @@ -0,0 +1,485 @@ + + * @version $Revision: 1.66 $ $Date: Wed Nov 02 10:13:17 EST 2005 10:13:17 $ + * @package Prado.tests + */ + +/** + * Selenium automatic client runner, + * + * @author Wei Zhuo + * @version $Revision: 1.66 $ $Date: Fri Nov 04 13:20:12 EST 2005 13:20:12 $ + * @package Prado.tests + */ + +require_once(dirname(__FILE__).'/results.php'); + +class SeleniumTestRunner +{ + protected $driver; + protected $base_dir = ''; + + public function __construct($driver=null, $base_dir='../javascript/') + { + if(is_null($driver) && !(php_sapi_name() == 'cli')) + $driver = $_SERVER['SCRIPT_NAME']; + $this->driver = $driver; + $this->base_dir = $base_dir; + } + + public function render() + { + if((php_sapi_name() == 'cli')) return; + $file = dirname(__FILE__).'/TestRunner.php'; + $driver = $this->driver; + $base_dir = $this->base_dir; + include($file); + } + + public function getDriver() + { + return $this->driver; + } +} + +class SeleniumTestStorage +{ + protected $outputs = array(); + protected $tests = array(); + + public function getTests() + { + return $this->tests; + } + + public function addCommand($test_case_id, $command) + { + $data = array($test_case_id, $command); + array_push($this->outputs, $data); + } + + public function getCommand() + { + return array_shift($this->outputs); + } + + public function addTestCase($command, $trace_details, $test_name, $test_suite) + { + $data = array(0, 0, $command, "", $trace_details, $test_name, $test_suite); + array_push($this->tests, $data); + } +} + +class SeleneseInterpreter +{ + protected $storage; + protected $tracer; + + public function __construct($storage, $tracer) + { + $this->storage = $storage; + $this->tracer = $tracer; + } + + public function getTests() + { + return $this->storage->getTests(); + } + + public function getCommand() + { + $command = $this->storage->getCommand(); + return empty($command) ? "|testComplete|||" : "{$command[1]}<{$command[0]}>"; + } + + public function __call($func, $args) + { + if($func{0} == '_') return; + $ID = isset($args[0]) ? $args[0] : ""; + if($ID instanceof TControl) + $ID = $ID->ClientID; + $value = isset($args[1]) ? $args[1] : ""; + $command = "|{$func}|{$ID}|{$value}|"; + $trace = debug_backtrace(); + return $this->addCommand($command, $trace); + } + + protected function addCommand($command, $trace) + { + list($trace, $test, $suite) = $this->tracer->getTrace($trace); + $test_id = $this->storage->addTestCase($command, $trace, $test, $suite); + $this->storage->addCommand($test_id, $command); + } +} + +class SeleniumTestTrace +{ + protected $root; + + public function __construct($root) + { + $this->root = $root; + } + + public function getTrace($trace) + { + $group = array_pop($trace); + $info = $trace[3]; + $test = $group['args'][0]->getTestStack(); + $i = count($test); + $name = $test[1].'::'.$test[$i-1]; + $suite = $test[0]; + unset($info['object']); + for($i = 0; $i < count($info['args']); $i++) + { + if($info['args'][$i] instanceof TControl) + $info['args'][$i] = $info['args'][$i]->ClientID; + } + $file = str_replace($this->root, '', $info['file']); + $info['file'] = substr($file, 1); + return array($info, $name, $suite); + } +} + +class SeleniumReporter extends SimpleReporter +{ + function getTestStack() + { + return $this->_test_stack; + } +} + +class SimpleSeleniumProxyServer// extends SeleniumProxyServer +{ + protected $runner; + protected $int; + protected $result_file; + + public function __construct($runner, $int, $result_file) + { + $this->int = $int; + $this->runner = $runner; + $this->result_file = $result_file; + } + + public function proxy() + { + return $this->int; + } + + + public static function getInstance($root='/', $result_file='results.dat', $base_dir='selenium/') + { + static $instance; + if(!isset($instance)) + { + $storage = new SeleniumTestStorage(); + $tracer = new SeleniumTestTrace($root); + $interpreter = new SeleneseInterpreter($storage, $tracer); + $runner = new SeleniumTestRunner(null, $base_dir); + $instance = new SimpleSeleniumProxyServer($runner, $interpreter, $result_file); + } + $instance->serveResults(); + return $instance; + } + + public function handleRequest() + { + $client = new SeleniumTestRunnerServer($this->int, $this->runner); + $client->serve(); + return true; + } + + public function serveResults() + { + $result = null; + + if(isset($_POST['result'])) + { + $result = new SeleniumTestResult(); + file_put_contents($this->result_file, serialize($result)); + } + else if(isset($_GET['results'])) + { + if(is_file($this->result_file)) + $result = unserialize(file_get_contents($this->result_file)); + } + if(!is_null($result)) + { + $reporter = new SeleniumHtmlReporter($result); + $reporter->render(); + exit(); + } + } + +} + +class SeleniumTestSuiteWriter +{ + protected $suites; + protected $name; + protected $runner; + + function __construct($suites, $name, $runner) + { + $this->suites = $suites; + $this->name = $name; + $this->runner = $runner; + + } + + protected function renderHeader() + { + $contents = << + + +Test Suite + + + + + + + + +EOD; + return $contents; + } + + public function render() + { + echo $this->renderHeader(); + foreach($this->suites as $name => $suite) + { + $file = $suite[0]['trace']['file']; + $url = $this->runner->getDriver()."?case={$name}&file={$file}"; + echo "\n"; + echo "\n"; + echo "\n"; + } + echo $this->renderFooter(); + } + + protected function getJsTraceInfo() + { + $contents = "var prado_trace = {};\n"; + foreach($this->suites as $name => $suite) + { + $name = $name; + $contents .= "prado_trace['{$name}'] = new Array();\n"; + foreach($suite as $testcase) + { + $trace = addslashes(htmlspecialchars(serialize($testcase['trace']))); + $contents .= "prado_trace['{$name}'].push('{$trace}')\n"; + } + } + return $contents; + } + + protected function renderFooter() + { + $trace = $this->getJsTraceInfo(); + $contents = << +
{$this->name}
{$name}
+ + + +EOD; + return $contents; + } +} + +class SeleniumTestCaseWriter +{ + protected $case; + protected $tests; + + function __construct($case, $tests) + { + $this->case = $case; + $this->tests = $tests; + } + + protected function renderHeader() + { + $contents = << + + +{$this->case} + + + + + + + + +EOD; + return $contents; + } + + public function render() + { + echo $this->renderHeader(); + foreach($this->tests as $test) + { + $t = explode('|', $test['test']); + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + } + echo $this->renderFooter(); + } + + protected function renderFooter() + { + $contents = << +
{$this->case}
{$t[1]}{$t[2]}{$t[3]}
+ + +EOD; + return $contents; + } +} + +class SeleniumTestRunnerServer +{ + protected $cases = array(); + protected $trace = array(); + protected $name; + protected $runner; + + public function __construct($int, $runner) + { + $this->runner = $runner; + $this->initialize($int); + } + + protected function initialize($int) + { + foreach($int->getTests() as $command) + { + $case = $command[5]; + $this->cases[$case][] = + array('test' => $command[2], 'trace' => $command[4]); + if(is_null($this->name)) + $this->name = $command[6]; + } + } + + function serve() + { + if($this->isTestSuiteRequest()) + { + $testSuite = new SeleniumTestSuiteWriter($this->cases, + $this->name, $this->runner); + $testSuite->render(); + } + else if($this->isTestCaseRequest()) + { + if(($case = $this->getTestCaseRequest()) !== false) + { + + $testCase = new SeleniumTestCaseWriter($case, $this->getTestCase()); + $testCase->render(); + } + } + else + { + $this->runner->render(); + } + } + + protected function isTestSuiteRequest() + { + return isset($_GET['testSuites']); + } + + protected function isTestCaseRequest() + { + return isset($_GET['case']); + } + + public function isClientRequest() + { + return !$this->isTestSuiteRequest() && !$this->isTestCaseRequest(); + } + + protected function getTestCaseRequest() + { + $case = $_GET['case']; + if(isset($this->cases[$case])) + return $case; + else return false; + } + + protected function getTestCase() + { + $case = $_GET['case']; + if(isset($this->cases[$case])) + return $this->cases[$case]; + else + return array(); + } +} + + +class SeleniumTestCase extends UnitTestCase +{ + protected $selenium; + protected $Page; + + function __construct() + { + $server = SimpleSeleniumProxyServer::getInstance(); + if(!is_null($server)) + $this->selenium = $server->proxy(); + } + + public function initPage($file) + { + $this->Page = prado::getApplication()->getTestPage($file); + } + + function __call($func, $args) + { + if(count($args) == 0) + return $this->selenium->{$func}(); + else if (count($args) == 1) + return $this->selenium->{$func}($args[0]); + else if (count($args) == 2) + return $this->selenium->{$func}($args[0], $args[1]); + } +} + +?> \ No newline at end of file -- cgit v1.2.3