$GLOBALS['TESTSUITE_BROWSERSTACK_USER'], 'browserstack.key' => $GLOBALS['TESTSUITE_BROWSERSTACK_KEY'], 'browserstack.debug' => false, 'project' => $project_name, 'build' => $build_id, ); if ($build_local) { $capabilities['browserstack.local'] = $build_local; $capabilities['browserstack.localIdentifier'] = $build_id; $capabilities['browserstack.debug'] = true; } $result = array(); $result[] = array( 'browserName' => 'chrome', 'host' => 'hub.browserstack.com', 'port' => 80, 'timeout' => 30000, 'sessionStrategy' => $strategy, 'desiredCapabilities' => $capabilities, ); /* Only one browser for continuous integration for speed */ if (empty($GLOBALS['TESTSUITE_FULL'])) { return $result; } /* $result[] = array( 'browserName' => 'Safari', 'host' => 'hub.browserstack.com', 'port' => 80, 'timeout' => 30000, 'sessionStrategy' => $strategy, 'desiredCapabilities' => array_merge( $capabilities, array( 'os' => 'OS X', 'os_version' => 'Mavericks', ) ) ); */ $result[] = array( 'browserName' => 'firefox', 'host' => 'hub.browserstack.com', 'port' => 80, 'timeout' => 30000, 'sessionStrategy' => $strategy, 'desiredCapabilities' => $capabilities, ); /* TODO: testing is MSIE is currently broken, so disabled $result[] = array( 'browserName' => 'internet explorer', 'host' => 'hub.browserstack.com', 'port' => 80, 'timeout' => 30000, 'sessionStrategy' => $strategy, 'desiredCapabilities' => array_merge( $capabilities, array( 'os' => 'windows', 'os_version' => '7', ) ) ); */ return $result; } elseif (! empty($GLOBALS['TESTSUITE_SELENIUM_HOST'])) { self::$_selenium_enabled = true; return array( array( 'browserName' => $GLOBALS['TESTSUITE_SELENIUM_BROWSER'], 'host' => $GLOBALS['TESTSUITE_SELENIUM_HOST'], 'port' => intval($GLOBALS['TESTSUITE_SELENIUM_PORT']), ) ); } else { return array(); } } /** * Configures the selenium and database link. * * @return void * * @throws Exception */ protected function setUp() { if (! self::$_selenium_enabled) { $this->markTestSkipped('Selenium testing not configured.'); } $caps = $this->getDesiredCapabilities(); $this->setDesiredCapabilities( array_merge( $caps, array('name' => get_class($this) . '__' . $this->getName()) ) ); parent::setUp(); $this->setBrowserUrl($GLOBALS['TESTSUITE_URL']); $this->_mysqli = new mysqli( $GLOBALS['TESTSUITE_SERVER'], $GLOBALS['TESTSUITE_USER'], $GLOBALS['TESTSUITE_PASSWORD'] ); if ($this->_mysqli->connect_errno) { throw new Exception( 'Failed to connect to MySQL (' . $this->_mysqli->error . ')' ); } $this->database_name = $GLOBALS['TESTSUITE_DATABASE'] . mb_substr(md5(rand()), 0, 7); $this->dbQuery( 'CREATE DATABASE IF NOT EXISTS ' . $this->database_name ); $this->dbQuery( 'USE ' . $this->database_name ); } /** * Checks whether user is a superuser. * * @return boolean */ protected function isSuperUser() { $result = $this->dbQuery('SELECT COUNT(*) FROM mysql.user'); if ($result !== false) { $result->free(); return true; } return false; } /** * Skips test if test user is not a superuser. * * @return void */ protected function skipIfNotSuperUser() { if (! $this->isSuperUser()) { $this->markTestSkipped('Test user is not a superuser.'); } } /** * Skips test if pmadb is not configured. * * @return void */ protected function skipIfNotPMADB() { $this->url('chk_rel.php'); if ($this->isElementPresent("byXPath", "//*[@color=\"red\"]")) { $this->markTestSkipped( 'The phpMyAdmin configuration storage is not working.' ); } } /** * Tear Down function for test cases * * @return void */ public function tearDown() { if ($this->_mysqli != null) { $this->dbQuery('DROP DATABASE IF EXISTS ' . $this->database_name); $this->_mysqli->close(); $this->_mysqli = null; } } /** * perform a login * * @param string $username Username * @param string $password Password * * @return void */ public function login($username = '', $password = '') { if ($username == '') { $username = $GLOBALS['TESTSUITE_USER']; } if ($password == '') { $password = $GLOBALS['TESTSUITE_PASSWORD']; } $this->url(''); $this->waitForElementNotPresent('byId', 'cfs-style'); /* Return if already logged in */ if ($this->isSuccessLogin()) { return; } $usernameField = $this->waitForElement('byId', 'input_username'); $usernameField->value($username); $passwordField = $this->byId('input_password'); $passwordField->value($password); $this->byId('input_go')->click(); } /** * Checks whether the login is successful * * @return boolean */ public function isSuccessLogin() { if ($this->isElementPresent("byXPath", "//*[@id=\"serverinfo\"]")) { return true; } else { return false; } } /** * Checks whether the login is unsuccessful * * @return boolean */ public function isUnsuccessLogin() { if ($this->isElementPresent("byCssSelector", "div.error")) { return true; } else { return false; } } /** * Used to go to the homepage * * @return void */ public function gotoHomepage() { $e = $this->byPartialLinkText("Server: "); $e->click(); $this->waitForElementNotPresent('byCssSelector', 'div#loading_parent'); } /** * Executes a database query * * @param string $query SQL Query to be executed * * @return void|boolean|mysqli_result * * @throws Exception */ public function dbQuery($query) { return $this->_mysqli->query($query); } /** * Check if user is logged in to phpmyadmin * * @return boolean Where or not user is logged in */ public function isLoggedIn() { return $this->isElementPresent( 'byXPath', '//*[@id="serverinfo"]/a[1]' ); } /** * Perform a logout, if logged in * * @return void */ public function logOutIfLoggedIn() { if ($this->isLoggedIn()) { $this->byCssSelector("img.icon.ic_s_loggoff")->click(); } } /** * Wait for an element to be present on the page * * @param string $func Locate using - byCss, byXPath, etc * @param string $arg Selector * * @return PHPUnit_Extensions_Selenium2TestCase_Element Element waited for */ public function waitForElement($func, $arg) { $this->timeouts()->implicitWait(10000); $element = call_user_func_array( array($this, $func), array($arg) ); $this->timeouts()->implicitWait(0); return $element; } /** * Wait for an element to disappear * * @param string $func Locate using - byCss, byXPath, etc * @param string $arg Selector * * @return bool Whether or not the element disappeared */ public function waitForElementNotPresent($func, $arg) { while (true) { if (!$this->isElementPresent($func, $arg)) { return true; } usleep(5000); } } /** * Sleeps while waiting for browser to perform an action. * * @todo This method should not be used, but rather there would be * explicit waiting for some elements. * * @return void */ public function sleep() { usleep(5000); } /** * Check if element is present or not * * @param string $func Locate using - byCss, byXPath, etc * @param string $arg Selector * * @return bool Whether or not the element is present */ public function isElementPresent($func, $arg) { try { $element = call_user_func_array( array($this, $func), array($arg) ); } catch (PHPUnit_Extensions_Selenium2TestCase_WebDriverException $e) { // Element not present return false; } catch (InvalidArgumentException $e) { // Element not present return false; } // Element Present return true; } /** * Get table cell data by the ID of the table * * @param string $tableID Table identifier * @param int $row Table row * @param int $column Table column * * @return text Data from the particular table cell */ public function getCellByTableId($tableID, $row, $column) { $sel = "table#{$tableID} tbody tr:nth-child({$row}) " . "td:nth-child({$column})"; $element = $this->byCssSelector( $sel ); return $element->text(); } /** * Get table cell data by the class attribute of the table * * @param string $tableClass Class of the table * @param int $row Table row * @param int $column Table column * * @return text Data from the particular table cell */ public function getCellByTableClass($tableClass, $row, $column) { $sel = "table.{$tableClass} tbody tr:nth-child({$row}) " . "td:nth-child({$column})"; $element = $this->byCssSelector( $sel ); return $element->text(); } /** * Wrapper around keys method to not use it on not supported * browsers. * * @param string $text Keys to send * * @return void */ public function keys($text) { /** * Not supported in Safari Webdriver, see * https://github.com/seleniumhq/selenium-google-code-issue-archive/issues/4136 */ if (mb_strtolower($this->getBrowser()) == 'safari') { $this->markTestSkipped('Can not send keys to Safari browser.'); } parent::keys($text); } /** * Wrapper around moveto method to not use it on not supported * browsers. * * @param object $element element * * @return void */ public function moveto($element) { /** * Not supported in Safari Webdriver, see * https://github.com/seleniumhq/selenium-google-code-issue-archive/issues/4136 */ if (mb_strtolower($this->getBrowser()) == 'safari') { $this->markTestSkipped('MoveTo not supported on Safari browser.'); } parent::moveto($element); } /** * Wrapper around alertText method to not use it on not supported * browsers. * * @return mixed */ public function alertText() { /** * Not supported in Safari Webdriver, see * https://github.com/seleniumhq/selenium-google-code-issue-archive/issues/4136 */ if (mb_strtolower($this->getBrowser()) == 'safari') { $this->markTestSkipped('Alerts not supported on Safari browser.'); } return parent::alertText(); } /** * Type text in textarea (CodeMirror enabled) * * @param string $text Text to type * * @return void */ public function typeInTextArea($text) { /** * Firefox needs some escaping of a text, see * https://github.com/seleniumhq/selenium-google-code-issue-archive/issues/1723 */ if (mb_strtolower($this->getBrowser()) == 'firefox') { $text = str_replace( "(", PHPUnit_Extensions_Selenium2TestCase_Keys::SHIFT . PHPUnit_Extensions_Selenium2TestCase_Keys::NUMPAD9 . PHPUnit_Extensions_Selenium2TestCase_Keys::NULL, $text ); } $this->byClassName("CodeMirror-scroll")->click(); $this->keys($text); } /** * Kills the More link in the menu * * @return void */ public function expandMore() { try { $this->waitForElement('byCssSelector', 'li.submenu > a'); } catch (PHPUnit_Extensions_Selenium2TestCase_WebDriverException $e) { return; } /* We need to resize to ensure it fits into accessible area */ $this->execute( array( 'script' => "$('#topmenu').css('font-size', '50%');" . "$(window).resize()", 'args' => array() ) ); $this->sleep(); } /** * Navigates browser to a table page. * * @param string $table Name of table * * @return void */ public function navigateTable($table) { // go to database page $this->waitForElement("byLinkText", $this->database_name)->click(); /* Wait for loading and expanding tree */ $this->waitForElement( 'byCssSelector', 'li.last.table' ); /* TODO: Timing issue of expanding navigation tree */ $this->sleep(); // go to table page $this->waitForElement( "byXPath", "//*[@id='pma_navigation_tree_content']//a[contains(., '$table')]" )->click(); // Wait for it to load $this->waitForElement( "byXPath", "//a[@class='tabactive' and contains(., 'Browse')]" ); } }