TimeTrex/vendor/phpunit/phpunit-selenium/PHPUnit/Extensions/Selenium2TestCase.php

639 lines
20 KiB
PHP
Raw Normal View History

2022-12-13 07:10:06 +01:00
<?php
/**
* PHPUnit
*
* Copyright (c) 2010-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Sebastian Bergmann nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package PHPUnit_Selenium
* @author Giorgio Sironi <info@giorgiosironi.com>
* @copyright 2010-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 1.2.0
*/
namespace PHPUnit\Extensions;
use Exception;
use InvalidArgumentException;
use PHPUnit\Extensions\Selenium2TestCase\Element;
use PHPUnit\Extensions\Selenium2TestCase\Element\Select;
use PHPUnit\Extensions\Selenium2TestCase\ElementCriteria;
use PHPUnit\Extensions\Selenium2TestCase\KeysHolder;
use PHPUnit\Extensions\Selenium2TestCase\NoSeleniumException;
use PHPUnit\Extensions\Selenium2TestCase\Session;
use PHPUnit\Extensions\Selenium2TestCase\Session\Timeouts;
use PHPUnit\Extensions\Selenium2TestCase\SessionStrategy;
use PHPUnit\Extensions\Selenium2TestCase\SessionStrategy\Isolated;
use PHPUnit\Extensions\Selenium2TestCase\SessionStrategy\Shared;
use PHPUnit\Extensions\Selenium2TestCase\URL;
use PHPUnit\Extensions\Selenium2TestCase\WaitUntil;
use PHPUnit\Extensions\Selenium2TestCase\Window;
use PHPUnit\Extensions\SeleniumCommon\RemoteCoverage;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestResult;
use PHPUnit\Util\InvalidArgumentHelper;
use RuntimeException;
use Throwable;
/**
* TestCase class that uses Selenium 2
* (WebDriver API and JsonWire protocol) to provide
* the functionality required for web testing.
*
* @package PHPUnit_Selenium
* @author Giorgio Sironi <info@giorgiosironi.com>
* @copyright 2010-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @version Release: @package_version@
* @link http://www.phpunit.de/
* @since Class available since Release 1.2.0
* @method void acceptAlert() Press OK on an alert, or confirms a dialog
* @method mixed alertText() alertText($value = NULL) Gets the alert dialog text, or sets the text for a prompt dialog
* @method void back()
* @method Element byClassName() byClassName($value)
* @method Element byCssSelector() byCssSelector($value)
* @method Element byId() byId($value)
* @method Element byLinkText() byLinkText($value)
* @method Element byPartialLinkText() byPartialLinkText($value)
* @method Element byName() byName($value)
* @method Element byTag() byTag($value)
* @method Element byXPath() byXPath($value)
* @method void click() click(int $button = 0) Click any mouse button (at the coordinates set by the last moveto command).
* @method void clickOnElement() clickOnElement($id)
* @method string currentScreenshot() BLOB of the image file
* @method void dismissAlert() Press Cancel on an alert, or does not confirm a dialog
* @method void doubleclick() Double clicks (at the coordinates set by the last moveto command).
* @method Element element() element(ElementCriteria $criteria) Retrieves an element
* @method array elements() elements(ElementCriteria $criteria) Retrieves an array of Element instances
* @method string execute() execute($javaScriptCode) Injects arbitrary JavaScript in the page and returns the last
* @method string executeAsync() executeAsync($javaScriptCode) Injects arbitrary JavaScript and wait for the callback (last element of arguments) to be called
* @method void forward()
* @method void frame() frame(mixed $element) Changes the focus to a frame in the page (by frameCount of type int, htmlId of type string, htmlName of type string or element of type Element)
* @method void moveto() moveto(Element $element) Move the mouse by an offset of the specificed element.
* @method void refresh()
* @method Select select() select($element)
* @method string source() Returns the HTML source of the page
* @method Timeouts timeouts()
* @method string title()
* @method void|string url() url($url = NULL)
* @method ElementCriteria using() using($strategy) Factory Method for Criteria objects
* @method void window() window($name) Changes the focus to another window
* @method string windowHandle() Retrieves the current window handle
* @method string windowHandles() Retrieves a list of all available window handles
* @method string keys($string) Send a sequence of key strokes to the active element.
* @method string file($file_path) Upload a local file. Returns the fully qualified path to the transferred file.
* @method array log(string $type) Get the log for a given log type. Log buffer is reset after each request.
* @method array logTypes() Get available log types.
* @method void closeWindow() Close the current window.
* @method void stop() Close the current window and clear session data.
* @method Element active() Get the element on the page that currently has focus.
* @method Window currentWindow() get the current Window Object
*/
abstract class Selenium2TestCase extends TestCase
{
const VERSION = '9.0.0';
/**
* @var string override to provide code coverage data from the server
*/
protected $coverageScriptUrl;
/**
* @var Session
*/
private $session;
/**
* @var array
*/
private $parameters;
/**
* @var SessionStrategy
*/
protected static $sessionStrategy;
/**
* @var SessionStrategy
*/
protected static $browserSessionStrategy;
/**
* Default timeout for wait until, ms
*
* @var int
*/
private static $defaultWaitUntilTimeout = 0;
/**
* Default timeout for wait until, ms
*
* @var int
*/
private static $defaultWaitUntilSleepInterval = 500;
/**
* @var SessionStrategy
*/
protected $localSessionStrategy;
/**
* @var array
*/
private static $lastBrowserParams;
/**
* @var string
*/
private $testId;
/**
* @var boolean
*/
private $collectCodeCoverageInformation;
/**
* @var KeysHolder
*/
private $keysHolder;
/**
* @param boolean
*/
private static $keepSessionOnFailure = FALSE;
/**
* @param boolean
*/
public static function shareSession($shareSession)
{
if (!is_bool($shareSession)) {
throw new InvalidArgumentException("The shared session support can only be switched on or off.");
}
if (!$shareSession) {
self::$sessionStrategy = self::defaultSessionStrategy();
} else {
self::$sessionStrategy = new Shared(
self::defaultSessionStrategy(), self::$keepSessionOnFailure
);
}
}
public static function keepSessionOnFailure($keepSession)
{
if (!is_bool($keepSession)) {
throw new InvalidArgumentException("The keep session on fail support can only be switched on or off.");
}
if ($keepSession){
self::$keepSessionOnFailure = TRUE;
}
}
private static function sessionStrategy()
{
if (!self::$sessionStrategy) {
self::$sessionStrategy = self::defaultSessionStrategy();
}
return self::$sessionStrategy;
}
private static function defaultSessionStrategy()
{
return new Isolated;
}
/**
* Get the default timeout for WaitUntil
* @return int the default timeout
*/
public static function defaultWaitUntilTimeout(){
return self::$defaultWaitUntilTimeout;
}
/**
* Set the default timeout for WaitUntil
* @param int $timeout the new default timeout
*/
public static function setDefaultWaitUntilTimeout($timeout){
$timeout = (int) $timeout;
self::$defaultWaitUntilTimeout = $timeout > 0 ? $timeout : 0;
}
/**
* Get the default sleep delay for WaitUntil
* @return int
*/
public static function defaultWaitUntilSleepInterval(){
return self::$defaultWaitUntilSleepInterval;
}
/**
* Set default sleep delay for WaitUntil
* @param int $sleepDelay the new default sleep delay
*/
public static function setDefaultWaitUntilSleepInterval($sleepDelay){
$sleepDelay = (int) $sleepDelay;
self::$defaultWaitUntilSleepInterval = $sleepDelay > 0 ? $sleepDelay : 0;
}
public function __construct($name = NULL, array $data = array(), $dataName = '')
{
parent::__construct($name, $data, $dataName);
$this->parameters = array(
'host' => 'localhost',
'port' => 4444,
'browser' => NULL,
'browserName' => NULL,
'desiredCapabilities' => array(),
'seleniumServerRequestsTimeout' => 60,
'secure' => FALSE
);
$this->keysHolder = new KeysHolder();
}
public function setupSpecificBrowser($params)
{
if (isset($params['keepSession'])) {
$this->keepSessionOnFailure(TRUE);
}
$this->setUpSessionStrategy($params);
$params = array_merge($this->parameters, $params);
$this->setHost($params['host']);
$this->setPort($params['port']);
$this->setBrowser($params['browserName']);
$this->parameters['browser'] = $params['browser'];
$this->setDesiredCapabilities($params['desiredCapabilities']);
$this->setSeleniumServerRequestsTimeout(
$params['seleniumServerRequestsTimeout']);
}
protected function setUpSessionStrategy($params)
{
// This logic enables us to have a session strategy reused for each
// item in self::$browsers. We don't want them both to share one
// and we don't want each test for a specific browser to have a
// new strategy
if ($params == self::$lastBrowserParams) {
// do nothing so we use the same session strategy for this
// browser
} elseif (isset($params['sessionStrategy'])) {
$strat = $params['sessionStrategy'];
if ($strat != "isolated" && $strat != "shared") {
throw new InvalidArgumentException("Session strategy must be either 'isolated' or 'shared'");
} elseif ($strat == "isolated") {
self::$browserSessionStrategy = new Isolated;
} else {
self::$browserSessionStrategy = new Shared(self::defaultSessionStrategy(), self::$keepSessionOnFailure);
}
} else {
self::$browserSessionStrategy = self::defaultSessionStrategy();
}
self::$lastBrowserParams = $params;
$this->localSessionStrategy = self::$browserSessionStrategy;
}
private function getStrategy()
{
if ($this->localSessionStrategy) {
return $this->localSessionStrategy;
} else {
return self::sessionStrategy();
}
}
public function prepareSession()
{
try {
if (!$this->session) {
$this->session = $this->getStrategy()->session($this->parameters);
}
} catch (NoSeleniumException $e) {
$this->markTestSkipped("The Selenium Server is not active on host {$this->parameters['host']} at port {$this->parameters['port']}.");
}
return $this->session;
}
public function run(TestResult $result = NULL): TestResult
{
$this->testId = get_class($this) . '__' . $this->getName();
if ($result === NULL) {
$result = $this->createResult();
}
$this->collectCodeCoverageInformation = $result->getCollectCodeCoverageInformation() && $this->coverageScriptUrl;
parent::run($result);
if ($this->collectCodeCoverageInformation) {
$coverage = new RemoteCoverage(
$this->coverageScriptUrl,
$this->testId
);
$result->getCodeCoverage()->append(
$coverage->get(), $this
);
}
// do not call this before to give the time to the Listeners to run
$this->getStrategy()->endOfTest($this->session);
return $result;
}
/**
* @throws RuntimeException
* @throws Exception
*/
protected function runTest()
{
$this->prepareSession();
$thrownException = NULL;
if ($this->collectCodeCoverageInformation) {
$this->url($this->coverageScriptUrl); // phpunit_coverage.php won't do anything if the cookie isn't set, which is exactly what we want
$this->session->cookie()->add('PHPUNIT_SELENIUM_TEST_ID', $this->testId)->set();
}
try {
$this->setUpPage();
$result = parent::runTest();
if (!empty($this->verificationErrors)) {
$this->fail(implode("\n", $this->verificationErrors));
}
} catch (Exception $e) {
$thrownException = $e;
}
if ($this->collectCodeCoverageInformation) {
$this->session->cookie()->remove('PHPUNIT_SELENIUM_TEST_ID');
}
if (NULL !== $thrownException) {
throw $thrownException;
}
return $result;
}
public static function suite($className)
{
return SeleniumTestSuite::fromTestCaseClass($className);
}
public function onNotSuccessfulTest(Throwable $e): void
{
$this->getStrategy()->notSuccessfulTest();
parent::onNotSuccessfulTest($e);
}
/**
* Delegate method calls to the Session.
*
* @param string $command
* @param array $arguments
* @return mixed
*/
public function __call($command, $arguments)
{
if ($this->session === NULL) {
throw new \PHPUnit\Extensions\Selenium2TestCase\Exception("There is currently no active session to execute the '$command' command. You're probably trying to set some option in setUp() with an incorrect setter name. You may consider using setUpPage() instead.");
}
$result = call_user_func_array(
array($this->session, $command), $arguments
);
return $result;
}
/**
* @param string $host
* @throws InvalidArgumentException
*/
public function setHost($host)
{
if (!is_string($host)) {
throw InvalidArgumentHelper::factory(1, 'string');
}
$this->parameters['host'] = $host;
}
public function getHost()
{
return $this->parameters['host'];
}
/**
* @param integer $port
* @throws InvalidArgumentException
*/
public function setPort($port)
{
if (!is_int($port)) {
throw InvalidArgumentHelper::factory(1, 'integer');
}
$this->parameters['port'] = $port;
}
public function getPort()
{
return $this->parameters['port'];
}
/**
* @param boolean $secure
* @throws InvalidArgumentException
*/
public function setSecure($secure)
{
if(!is_bool($secure)) {
throw InvalidArgumentHelper::factory(1, 'boolean');
}
$this->parameters['secure'] = $secure;
}
public function getSecure()
{
return $this->parameters['secure'];
}
/**
* @param string $browser
* @throws InvalidArgumentException
*/
public function setBrowser($browserName)
{
if (!is_string($browserName)) {
throw InvalidArgumentHelper::factory(1, 'string');
}
$this->parameters['browserName'] = $browserName;
}
public function getBrowser()
{
return $this->parameters['browserName'];
}
/**
* @param string $browserUrl
* @throws InvalidArgumentException
*/
public function setBrowserUrl($browserUrl)
{
if (!is_string($browserUrl)) {
throw InvalidArgumentHelper::factory(1, 'string');
}
$this->parameters['browserUrl'] = new URL($browserUrl);
}
public function getBrowserUrl()
{
if (isset($this->parameters['browserUrl'])) {
return $this->parameters['browserUrl'];
}
return '';
}
/**
* @see http://code.google.com/p/selenium/wiki/JsonWireProtocol
*/
public function setDesiredCapabilities(array $capabilities)
{
$this->parameters['desiredCapabilities'] = $capabilities;
}
public function getDesiredCapabilities()
{
return $this->parameters['desiredCapabilities'];
}
/**
* @param int $timeout seconds
*/
public function setSeleniumServerRequestsTimeout($timeout)
{
$this->parameters['seleniumServerRequestsTimeout'] = $timeout;
}
public function getSeleniumServerRequestsTimeout()
{
return $this->parameters['seleniumServerRequestsTimeout'];
}
/**
* Get test id (generated internally)
* @return string
*/
public function getTestId()
{
return $this->testId;
}
/**
* Get Selenium2 current session id
* @return string
*/
public function getSessionId()
{
if ($this->session) {
return $this->session->id();
}
return FALSE;
}
/**
* Wait until callback isn't null or timeout occurs
*
* @param $callback
* @param null $timeout
* @return mixed
*/
public function waitUntil($callback, $timeout = NULL)
{
$waitUntil = new WaitUntil($this);
return $waitUntil->run($callback, $timeout);
}
/**
* Sends a special key
* Deprecated due to issues with IE webdriver. Use keys() method instead
* @deprecated
* @param string $name
* @throws \PHPUnit\Extensions\Selenium2TestCase\Exception
* @see KeysHolder
*/
public function keysSpecial($name)
{
$names = explode(',', $name);
foreach ($names as $key) {
$this->keys($this->keysHolder->specialKey(trim($key)));
}
}
/**
* setUp method that is called after the session has been prepared.
* It is possible to use session-specific commands like url() here.
*/
public function setUpPage()
{
}
/**
* Check whether an alert box is present
*/
public function alertIsPresent()
{
try {
$this->alertText();
return TRUE;
} catch (Exception $e) {
return NULL;
}
}
}