Move into nested docroot

This commit is contained in:
Rob Davies 2017-02-13 15:31:17 +00:00
parent 83a0d3a149
commit c8b70abde9
13405 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,109 @@
<?php
namespace Zumba\Mink\Driver;
use Behat\Mink\Driver\CoreDriver;
use Behat\Mink\Exception\DriverException;
use Behat\Mink\Session;
use Zumba\GastonJS\Browser\Browser;
/**
* Class BasePhantomJSDriver
* @package Zumba\Mink\Driver
*/
class BasePhantomJSDriver extends CoreDriver {
/** @var Session */
protected $session;
/** @var Browser */
protected $browser;
/** @var string */
protected $phantomHost;
/** @var \Twig_Loader_Filesystem */
protected $templateLoader;
/** @var \Twig_Environment */
protected $templateEnv;
/**
* Instantiates the driver
* @param string $phantomHost browser "api" oriented host
* @param string $templateCache where we are going to store the templates cache
*/
public function __construct($phantomHost, $templateCache = null) {
$this->phantomHost = $phantomHost;
$this->browser = new Browser($phantomHost);
$this->templateLoader = new \Twig_Loader_Filesystem(realpath(__DIR__ . '/Resources/Script'));
$this->templateEnv = new \Twig_Environment($this->templateLoader, array('cache' => $this->templateCacheSetup($templateCache), 'strict_variables' => true));
}
/**
* Sets up the cache template location for the scripts we are going to create with the driver
* @param $templateCache
* @return string
* @throws DriverException
*/
protected function templateCacheSetup($templateCache) {
$cacheDir = $templateCache;
if ($templateCache === null) {
$cacheDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . "jcalderonzumba" . DIRECTORY_SEPARATOR . "phantomjs";
if (!file_exists($cacheDir)) {
mkdir($cacheDir, 0777, true);
}
}
if (!file_exists($cacheDir)) {
throw new DriverException("Template cache $cacheDir directory does not exist");
}
return $cacheDir;
}
/**
* Helper to find a node element given an xpath
* @param string $xpath
* @param int $max
* @returns int
* @throws DriverException
*/
protected function findElement($xpath, $max = 1) {
$elements = $this->browser->find("xpath", $xpath);
if (!isset($elements["page_id"]) || !isset($elements["ids"]) || count($elements["ids"]) !== $max) {
throw new DriverException("Failed to get elements with given $xpath");
}
return $elements;
}
/**
* {@inheritdoc}
* @param Session $session
*/
public function setSession(Session $session) {
$this->session = $session;
}
/**
* @return Browser
*/
public function getBrowser() {
return $this->browser;
}
/**
* @return \Twig_Environment
*/
public function getTemplateEnv() {
return $this->templateEnv;
}
/**
* Returns a javascript script via twig template engine
* @param $templateName
* @param $viewData
* @return string
*/
public function javascriptTemplateRender($templateName, $viewData) {
/** @var $templateEngine \Twig_Environment */
$templateEngine = $this->getTemplateEnv();
return $templateEngine->render($templateName, $viewData);
}
}

View file

@ -0,0 +1,45 @@
<?php
namespace Zumba\Mink\Driver;
use Zumba\GastonJS\Cookie;
/**
* Trait CookieTrait
* @package Zumba\Mink\Driver
*/
trait CookieTrait {
/**
* Sets a cookie on the browser, if null value then delete it
* @param string $name
* @param string $value
*/
public function setCookie($name, $value = null) {
if ($value === null) {
$this->browser->removeCookie($name);
}
//TODO: set the cookie with domain, not with url, meaning www.aaa.com or .aaa.com
if ($value !== null) {
$urlData = parse_url($this->getCurrentUrl());
$cookie = array("name" => $name, "value" => $value, "domain" => $urlData["host"]);
$this->browser->setCookie($cookie);
}
}
/**
* Gets a cookie by its name if exists, else it will return null
* @param string $name
* @return string
*/
public function getCookie($name) {
$cookies = $this->browser->cookies();
foreach ($cookies as $cookie) {
if ($cookie instanceof Cookie && strcmp($cookie->getName(), $name) === 0) {
return $cookie->getValue();
}
}
return null;
}
}

View file

@ -0,0 +1,168 @@
<?php
namespace Zumba\Mink\Driver;
use Behat\Mink\Exception\DriverException;
/**
* Trait FormManipulationTrait
* @package Zumba\Mink\Driver
*/
trait FormManipulationTrait {
/**
* Returns the value of a given xpath element
* @param string $xpath
* @return string
* @throws DriverException
*/
public function getValue($xpath) {
$this->findElement($xpath, 1);
$javascript = $this->javascriptTemplateRender("get_value.js.twig", array("xpath" => $xpath));
return $this->browser->evaluate($javascript);
}
/**
* @param string $xpath
* @param string $value
* @throws DriverException
*/
public function setValue($xpath, $value) {
$this->findElement($xpath, 1);
//This stuff is BECAUSE the way the driver works for setting values when being checkboxes, radios, etc.
if (is_bool($value)) {
$value = $this->boolToString($value);
}
$javascript = $this->javascriptTemplateRender("set_value.js.twig", array("xpath" => $xpath, "value" => json_encode($value)));
$this->browser->evaluate($javascript);
}
/**
* Submits a form given an xpath selector
* @param string $xpath
* @throws DriverException
*/
public function submitForm($xpath) {
$element = $this->findElement($xpath, 1);
$tagName = $this->browser->tagName($element["page_id"], $element["ids"][0]);
if (strcmp(strtolower($tagName), "form") !== 0) {
throw new DriverException("Can not submit something that is not a form");
}
$this->browser->trigger($element["page_id"], $element["ids"][0], "submit");
}
/**
* Helper method needed for twig and javascript stuff
* @param $boolValue
* @return string
*/
protected function boolToString($boolValue) {
if ($boolValue === true) {
return "1";
}
return "0";
}
/**
* Selects an option
* @param string $xpath
* @param string $value
* @param bool $multiple
* @return bool
* @throws DriverException
*/
public function selectOption($xpath, $value, $multiple = false) {
$element = $this->findElement($xpath, 1);
$tagName = strtolower($this->browser->tagName($element["page_id"], $element["ids"][0]));
$attributes = $this->browser->attributes($element["page_id"], $element["ids"][0]);
if (!in_array($tagName, array("input", "select"))) {
throw new DriverException(sprintf('Impossible to select an option on the element with XPath "%s" as it is not a select or radio input', $xpath));
}
if ($tagName === "input" && $attributes["type"] != "radio") {
throw new DriverException(sprintf('Impossible to select an option on the element with XPath "%s" as it is not a select or radio input', $xpath));
}
return $this->browser->selectOption($element["page_id"], $element["ids"][0], $value, $multiple);
}
/**
* Check control over an input element of radio or checkbox type
* @param $xpath
* @return bool
* @throws DriverException
*/
protected function inputCheckableControl($xpath) {
$element = $this->findElement($xpath, 1);
$tagName = strtolower($this->browser->tagName($element["page_id"], $element["ids"][0]));
$attributes = $this->browser->attributes($element["page_id"], $element["ids"][0]);
if ($tagName != "input") {
throw new DriverException("Can not check when the element is not of the input type");
}
if (!in_array($attributes["type"], array("checkbox", "radio"))) {
throw new DriverException("Can not check when the element is not checkbox or radio");
}
return true;
}
/**
* We click on the checkbox or radio when possible and needed
* @param string $xpath
* @throws DriverException
*/
public function check($xpath) {
$this->inputCheckableControl($xpath);
$javascript = $this->javascriptTemplateRender("check_element.js.twig", array("xpath" => $xpath, "check" => "true"));
$this->browser->evaluate($javascript);
}
/**
* We click on the checkbox or radio when possible and needed
* @param string $xpath
* @throws DriverException
*/
public function uncheck($xpath) {
$this->inputCheckableControl($xpath);
$javascript = $this->javascriptTemplateRender("check_element.js.twig", array("xpath" => $xpath, "check" => "false"));
$this->browser->evaluate($javascript);
}
/**
* Checks if the radio or checkbox is checked
* @param string $xpath
* @return bool
* @throws DriverException
*/
public function isChecked($xpath) {
$this->findElement($xpath, 1);
$javascript = $this->javascriptTemplateRender("is_checked.js.twig", array("xpath" => $xpath));
$checked = $this->browser->evaluate($javascript);
if ($checked === null) {
throw new DriverException("Can not check when the element is not checkbox or radio");
}
return $checked;
}
/**
* Checks if the option is selected or not
* @param string $xpath
* @return bool
* @throws DriverException
*/
public function isSelected($xpath) {
$elements = $this->findElement($xpath, 1);
$javascript = $this->javascriptTemplateRender("is_selected.js.twig", array("xpath" => $xpath));
$tagName = $this->browser->tagName($elements["page_id"], $elements["ids"][0]);
if (strcmp(strtolower($tagName), "option") !== 0) {
throw new DriverException("Can not assert on element that is not an option");
}
return $this->browser->evaluate($javascript);
}
}

View file

@ -0,0 +1,40 @@
<?php
namespace Zumba\Mink\Driver;
/**
* Class HeadersTrait
* @package Zumba\Mink\Driver
*/
trait HeadersTrait {
/**
* Gets the current request response headers
* Should be called only after a request, other calls are undefined behaviour
* @return array
*/
public function getResponseHeaders() {
return $this->browser->responseHeaders();
}
/**
* Current request status code response
* @return int
*/
public function getStatusCode() {
return $this->browser->getStatusCode();
}
/**
* The name say its all
* @param string $name
* @param string $value
*/
public function setRequestHeader($name, $value) {
$header = array();
$header[$name] = $value;
//TODO: as a limitation of the driver it self, we will send permanent for the moment
$this->browser->addHeader($header, true);
}
}

View file

@ -0,0 +1,49 @@
<?php
namespace Zumba\Mink\Driver;
use Behat\Mink\Exception\DriverException;
/**
* Class JavascriptTrait
* @package Zumba\Mink\Driver
*/
trait JavascriptTrait {
/**
* Executes a script on the browser
* @param string $script
*/
public function executeScript($script) {
$this->browser->execute($script);
}
/**
* Evaluates a script and returns the result
* @param string $script
* @return mixed
*/
public function evaluateScript($script) {
return $this->browser->evaluate($script);
}
/**
* Waits some time or until JS condition turns true.
*
* @param integer $timeout timeout in milliseconds
* @param string $condition JS condition
* @return boolean
* @throws DriverException When the operation cannot be done
*/
public function wait($timeout, $condition) {
$start = microtime(true);
$end = $start + $timeout / 1000.0;
do {
$result = $this->browser->evaluate($condition);
usleep(100000);
} while (microtime(true) < $end && !$result);
return (bool)$result;
}
}

View file

@ -0,0 +1,95 @@
<?php
namespace Zumba\Mink\Driver;
use Behat\Mink\Exception\DriverException;
/**
* Class KeyboardTrait
* @package Zumba\Mink\Driver
*/
trait KeyboardTrait {
/**
* Does some normalization for the char we want to do keyboard events with.
* @param $char
* @throws DriverException
* @return string
*/
protected function normalizeCharForKeyEvent($char) {
if (!is_int($char) && !is_string($char)) {
throw new DriverException("Unsupported key type, can only be integer or string");
}
if (is_string($char) && strlen($char) !== 1) {
throw new DriverException("Key can only have ONE character");
}
$key = $char;
if (is_int($char)) {
$key = chr($char);
}
return $key;
}
/**
* Does some control and normalization for the key event modifier
* @param $modifier
* @return string
* @throws DriverException
*/
protected function keyEventModifierControl($modifier) {
if ($modifier === null) {
$modifier = "none";
}
if (!in_array($modifier, array("none", "alt", "ctrl", "shift", "meta"))) {
throw new DriverException("Unsupported key modifier $modifier");
}
return $modifier;
}
/**
* Send a key-down event to the browser element
* @param $xpath
* @param $char
* @param string $modifier
* @throws DriverException
*/
public function keyDown($xpath, $char, $modifier = null) {
$element = $this->findElement($xpath, 1);
$key = $this->normalizeCharForKeyEvent($char);
$modifier = $this->keyEventModifierControl($modifier);
return $this->browser->keyEvent($element["page_id"], $element["ids"][0], "keydown", $key, $modifier);
}
/**
* @param string $xpath
* @param string $char
* @param string $modifier
* @throws DriverException
*/
public function keyPress($xpath, $char, $modifier = null) {
$element = $this->findElement($xpath, 1);
$key = $this->normalizeCharForKeyEvent($char);
$modifier = $this->keyEventModifierControl($modifier);
return $this->browser->keyEvent($element["page_id"], $element["ids"][0], "keypress", $key, $modifier);
}
/**
* Pressed up specific keyboard key.
*
* @param string $xpath
* @param string|integer $char could be either char ('b') or char-code (98)
* @param string $modifier keyboard modifier (could be 'ctrl', 'alt', 'shift' or 'meta')
*
* @throws DriverException When the operation cannot be done
*/
public function keyUp($xpath, $char, $modifier = null) {
$this->findElement($xpath, 1);
$element = $this->findElement($xpath, 1);
$key = $this->normalizeCharForKeyEvent($char);
$modifier = $this->keyEventModifierControl($modifier);
return $this->browser->keyEvent($element["page_id"], $element["ids"][0], "keyup", $key, $modifier);
}
}

View file

@ -0,0 +1,57 @@
<?php
namespace Zumba\Mink\Driver;
use Behat\Mink\Exception\DriverException;
/**
* Class MouseTrait
* @package Zumba\Mink\Driver
*/
trait MouseTrait {
/**
* Generates a mouseover event on the given element by xpath
* @param string $xpath
* @throws DriverException
*/
public function mouseOver($xpath) {
$element = $this->findElement($xpath, 1);
$this->browser->hover($element["page_id"], $element["ids"][0]);
}
/**
* Clicks if possible on an element given by xpath
* @param string $xpath
* @return mixed
* @throws DriverException
*/
public function click($xpath) {
$elements = $this->findElement($xpath, 1);
$this->browser->click($elements["page_id"], $elements["ids"][0]);
}
/**
* {@inheritdoc}
*/
/**
* Double click on element found via xpath
* @param string $xpath
* @throws DriverException
*/
public function doubleClick($xpath) {
$elements = $this->findElement($xpath, 1);
$this->browser->doubleClick($elements["page_id"], $elements["ids"][0]);
}
/**
* Right click on element found via xpath
* @param string $xpath
* @throws DriverException
*/
public function rightClick($xpath) {
$elements = $this->findElement($xpath, 1);
$this->browser->rightClick($elements["page_id"], $elements["ids"][0]);
}
}

View file

@ -0,0 +1,49 @@
<?php
namespace Zumba\Mink\Driver;
/**
* Trait NavigationTrait
* @package Zumba\Mink\Driver
*/
trait NavigationTrait {
/**
* Visits a given url
* @param string $url
*/
public function visit($url) {
$this->browser->visit($url);
}
/**
* Gets the current url if any
* @return string
*/
public function getCurrentUrl() {
return $this->browser->currentUrl();
}
/**
* Reloads the page if possible
*/
public function reload() {
$this->browser->reload();
}
/**
* Goes forward if possible
*/
public function forward() {
$this->browser->goForward();
}
/**
* Goes back if possible
*/
public function back() {
$this->browser->goBack();
}
}

View file

@ -0,0 +1,72 @@
<?php
namespace Zumba\Mink\Driver;
use Behat\Mink\Exception\DriverException;
/**
* Class PageContentTrait
* @package Zumba\Mink\Driver
*/
trait PageContentTrait {
/**
* @return string
*/
public function getContent() {
return $this->browser->getBody();
}
/**
* Given xpath, will try to get ALL the text, visible and not visible from such xpath
* @param string $xpath
* @return string
* @throws DriverException
*/
public function getText($xpath) {
$elements = $this->findElement($xpath, 1);
//allText works only with ONE element so it will be the first one and also returns new lines that we will remove
$text = $this->browser->allText($elements["page_id"], $elements["ids"][0]);
$text = trim(str_replace(array("\r", "\r\n", "\n"), ' ', $text));
$text = preg_replace('/ {2,}/', ' ', $text);
return $text;
}
/**
* Returns the inner html of a given xpath
* @param string $xpath
* @return string
* @throws DriverException
*/
public function getHtml($xpath) {
$elements = $this->findElement($xpath, 1);
//allText works only with ONE element so it will be the first one
return $this->browser->allHtml($elements["page_id"], $elements["ids"][0], "inner");
}
/**
* Gets the outer html of a given xpath
* @param string $xpath
* @return string
* @throws DriverException
*/
public function getOuterHtml($xpath) {
$elements = $this->findElement($xpath, 1);
//allText works only with ONE element so it will be the first one
return $this->browser->allHtml($elements["page_id"], $elements["ids"][0], "outer");
}
/**
* Returns the binary representation of the current page we are in
* @throws DriverException
* @return string
*/
public function getScreenshot() {
$options = array("full" => true, "selector" => null);
$b64ScreenShot = $this->browser->renderBase64("JPEG", $options);
if (($binaryScreenShot = base64_decode($b64ScreenShot, true)) === false) {
throw new DriverException("There was a problem while doing the screenshot of the current page");
}
return $binaryScreenShot;
}
}

View file

@ -0,0 +1,164 @@
<?php
namespace Zumba\Mink\Driver;
use Behat\Mink\Element\NodeElement;
use Behat\Mink\Exception\DriverException;
/**
* Class PhantomJSDriver
* @package Behat\Mink\Driver
*/
class PhantomJSDriver extends BasePhantomJSDriver {
use SessionTrait;
use NavigationTrait;
use CookieTrait;
use HeadersTrait;
use JavascriptTrait;
use MouseTrait;
use PageContentTrait;
use KeyboardTrait;
use FormManipulationTrait;
use WindowTrait;
/**
* Sets the basic auth user and password
* @param string $user
* @param string $password
*/
public function setBasicAuth($user, $password) {
$this->browser->setHttpAuth($user, $password);
}
/**
* Gets the tag name of a given xpath
* @param string $xpath
* @return string
* @throws DriverException
*/
public function getTagName($xpath) {
$elements = $this->findElement($xpath, 1);
return $this->browser->tagName($elements["page_id"], $elements["ids"][0]);
}
/**
* Gets the attribute value of a given element and name
* @param string $xpath
* @param string $name
* @return string
* @throws DriverException
*/
public function getAttribute($xpath, $name) {
$elements = $this->findElement($xpath, 1);
return $this->browser->attribute($elements["page_id"], $elements["ids"][0], $name);
}
/**
* Check if element given by xpath is visible or not
* @param string $xpath
* @return bool
* @throws DriverException
*/
public function isVisible($xpath) {
$elements = $this->findElement($xpath, 1);
return $this->browser->isVisible($elements["page_id"], $elements["ids"][0]);
}
/**
* Drags one element to another
* @param string $sourceXpath
* @param string $destinationXpath
* @throws DriverException
*/
public function dragTo($sourceXpath, $destinationXpath) {
$sourceElement = $this->findElement($sourceXpath, 1);
$destinationElement = $this->findElement($destinationXpath, 1);
$this->browser->drag($sourceElement["page_id"], $sourceElement["ids"][0], $destinationElement["ids"][0]);
}
/**
* Upload a file to the browser
* @param string $xpath
* @param string $path
* @throws DriverException
*/
public function attachFile($xpath, $path) {
if (!file_exists($path)) {
throw new DriverException("Wow there the file does not exist, you can not upload it");
}
if (($realPath = realpath($path)) === false) {
throw new DriverException("Wow there the file does not exist, you can not upload it");
}
$element = $this->findElement($xpath, 1);
$tagName = $this->getTagName($xpath);
if ($tagName != "input") {
throw new DriverException("The element is not an input element, you can not attach a file to it");
}
$attributes = $this->getBrowser()->attributes($element["page_id"], $element["ids"][0]);
if (!isset($attributes["type"]) || $attributes["type"] != "file") {
throw new DriverException("The element is not an input file type element, you can not attach a file to it");
}
$this->browser->selectFile($element["page_id"], $element["ids"][0], $realPath);
}
/**
* Puts the browser control inside the IFRAME
* You own the control, make sure to go back to the parent calling this method with null
* @param string $name
*/
public function switchToIFrame($name = null) {
//TODO: check response of the calls
if ($name === null) {
$this->browser->popFrame();
return;
} else {
$this->browser->pushFrame($name);
}
}
/**
* Focus on an element
* @param string $xpath
* @throws DriverException
*/
public function focus($xpath) {
$element = $this->findElement($xpath, 1);
$this->browser->trigger($element["page_id"], $element["ids"][0], "focus");
}
/**
* Blur on element
* @param string $xpath
* @throws DriverException
*/
public function blur($xpath) {
$element = $this->findElement($xpath, 1);
$this->browser->trigger($element["page_id"], $element["ids"][0], "blur");
}
/**
* Finds elements with specified XPath query.
* @param string $xpath
* @return NodeElement[]
* @throws DriverException When the operation cannot be done
*/
public function find($xpath) {
$elements = $this->browser->find("xpath", $xpath);
$nodeElements = array();
if (!isset($elements["ids"])) {
return null;
}
foreach ($elements["ids"] as $i => $elementId) {
$nodeElements[] = new NodeElement(sprintf('(%s)[%d]', $xpath, $i + 1), $this->session);
}
return $nodeElements;
}
}

View file

@ -0,0 +1,35 @@
{% autoescape 'js' %}
(function (xpath, check) {
function getPolterNode(xpath) {
var polterAgent = window.__poltergeist;
var ids = polterAgent.find("xpath", xpath, document);
return polterAgent.get(ids[0]);
}
var pNode = getPolterNode(xpath);
if (check && pNode.element.checked) {
//requested to check the element and is already check, do nothing.
return true;
}
if (!check && pNode.element.checked == false) {
//move along nothing to be done
return true;
}
if (check && pNode.element.checked == false) {
//we have to check the element, we will do so by triggering a click event so all change listeners are aware.
pNode.trigger("click");
pNode.element.checked = true;
}
if (!check && pNode.element.checked) {
//move along nothing to be done
pNode.trigger("click");
pNode.element.checked = false;
return true;
}
return false;
}('{{xpath}}', {{check}}));
{% endautoescape %}

View file

@ -0,0 +1,3 @@
{% autoescape false %}
{{ script }};
{% endautoescape %}

View file

@ -0,0 +1,63 @@
{% autoescape 'js' %}
(function (xpath) {
function getElement(xpath) {
var polterAgent = window.__poltergeist;
var ids = polterAgent.find("xpath", xpath, document);
var polterNode = polterAgent.get(ids[0]);
return polterNode.element;
}
function inputRadioGetValue(element){
var value = null;
var name = element.getAttribute('name');
if (!name){
return null;
}
var fields = window.document.getElementsByName(name);
var i;
var l = fields.length;
for (i = 0; i < l; i++) {
var field = fields.item(i);
if (field.form === element.form && field.checked) {
return field.value;
}
}
return null;
}
var node = getElement(xpath);
var tagName = node.tagName.toLowerCase();
var value = null;
if (tagName == "input") {
var type = node.type.toLowerCase();
if (type == "checkbox") {
value = node.checked ? node.value : null;
} else if (type == "radio") {
value = inputRadioGetValue(node);
} else {
value = node.value;
}
} else if (tagName == "textarea") {
value = node.value;
} else if (tagName == "select") {
if (node.multiple) {
value = [];
for (var i = 0; i < node.options.length; i++) {
if (node.options[i].selected) {
value.push(node.options[i].value);
}
}
} else {
var idx = node.selectedIndex;
if (idx >= 0) {
value = node.options.item(idx).value;
} else {
value = null;
}
}
} else {
value = node.value;
}
return value;
}('{{ xpath }}'));
{% endautoescape %}

View file

@ -0,0 +1,31 @@
{% autoescape 'js' %}
(function (xpath) {
function getElement(xpath, within) {
var result;
if (within === null || within === undefined) {
within = document;
}
result = document.evaluate(xpath, within, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
if (result.snapshotLength !== 1) {
return null;
}
return result.snapshotItem(0);
}
var node = getElement(xpath);
if (node === null) {
return null;
}
if(node.tagName.toLowerCase() != "input"){
return null;
}
if(node.type.toLowerCase() != "checkbox" && node.type.toLowerCase() != "radio"){
return null;
}
return node.checked;
}('{{ xpath }}'));
{% endautoescape %}

View file

@ -0,0 +1,16 @@
{% autoescape 'js' %}
(function (xpath) {
function getElement(xpath) {
var polterAgent = window.__poltergeist;
var ids = polterAgent.find("xpath", xpath, document);
var polterNode = polterAgent.get(ids[0]);
return polterNode.element;
}
var node = getElement(xpath);
if(typeof node.selected == "undefined"){
return null;
}
return node.selected;
}('{{xpath}}'));
{% endautoescape %}

View file

@ -0,0 +1,213 @@
{% autoescape 'js' %}
(function (xpath, value) {
function getElement(xpath, within) {
var result;
if (within === null || within === undefined) {
within = document;
}
result = document.evaluate(xpath, within, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
if (result.snapshotLength !== 1) {
return null;
}
return result.snapshotItem(0);
}
function isInput(element) {
if (element === null || element === undefined) {
return false;
}
return (element.tagName.toLowerCase() == "input");
}
function isTextArea(element) {
if (element === null || element === undefined) {
return false;
}
return (element.tagName.toLowerCase() == "textarea");
}
function isSelect(element) {
if (element === null || element === undefined) {
return false;
}
return (element.tagName.toLowerCase() == "select");
}
function deselectAllOptions(element) {
var i, l = element.options.length;
for (i = 0; i < l; i++) {
element.options[i].selected = false;
}
}
function xpathStringLiteral(s) {
if (s.indexOf('"') === -1)
return '"' + s + '"';
if (s.indexOf("'") === -1)
return "'" + s + "'";
return 'concat("' + s.replace(/"/g, '",\'"\',"') + '")';
}
function clickOnElement(element) {
// create a mouse click event
var event = document.createEvent('MouseEvents');
event.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
// send click to element
element.dispatchEvent(event);
//After dispatching the event let's wait for 2 seconds at least...
return setTimeout(function () {
}, 2);
}
function dispatchChange(element) {
var tagName =element.tagName.toLowerCase();
var elementType = element.getAttribute("type");
if (tagName != "option" || (tagName == "input" && elementType == "radio")){
return true;
}
//Force the change when element is option
var event;
event = document.createEvent('HTMLEvents');
event.initEvent('change', true, false);
element.dispatchEvent(event);
return true;
}
function selectOptionOnElement(element, option, multiple) {
var polterAgent = window.__poltergeist;
var escapedOption = xpathStringLiteral(option);
// The value of an option is the normalized version of its text when it has no value attribute
var optionQuery = ".//option[@value = " + escapedOption + " or (not(@value) and normalize-space(.) = " + escapedOption + ")]";
var ids = polterAgent.find("xpath", optionQuery, element);
var polterNode = polterAgent.get(ids[0]);
var optionElement = polterNode.element;
if (multiple || !element.multiple) {
if (!optionElement.selected) {
clickOnElement(optionElement);
optionElement.selected = true;
}
return dispatchChange(optionElement);
}
deselectAllOptions(element);
clickOnElement(optionElement);
optionElement.selected = true;
return dispatchChange(optionElement);
}
function selectSetValue(element, value) {
var option;
if ((Array.isArray && Array.isArray(value)) || (value instanceof Array)) {
deselectAllOptions(element);
for (option in value) {
if (value.hasOwnProperty(option)) {
selectOptionOnElement(element, value[option], true);
}
}
return true;
}
selectOptionOnElement(element, value, false);
return true;
}
function selectRadioValue(element, value) {
if (element.value === value) {
clickOnElement(element);
element.checked=true;
dispatchChange(element);
return true;
}
var formElements = element.form.elements;
var name = element.getAttribute("name");
var radioElement, i;
if (!name) {
return null;
}
for (i = 0; i < formElements.length; i++) {
radioElement = formElements[i];
if (radioElement.tagName.toLowerCase() == 'input' && radioElement.type.toLowerCase() == 'radio' && radioElement.name === name) {
if (value === radioElement.value) {
clickOnElement(radioElement);
radioElement.checked=true;
dispatchChange(radioElement);
return true;
}
}
}
return null;
}
function inputSetValue(element, value, elementXpath) {
var allowedTypes = ['submit', 'image', 'button', 'reset'];
var elementType = element.type.toLowerCase();
var textLikeInputType = ['file', 'text', 'password', 'url', 'email', 'search', 'number', 'tel', 'range', 'date', 'month', 'week', 'time', 'datetime', 'color', 'datetime-local'];
if (allowedTypes.indexOf(elementType) !== -1) {
return null;
}
if (elementType == "checkbox") {
var booleanValue = false;
if (value == "1" || value == 1) {
booleanValue = true;
} else if (value == "0" || value == 0) {
booleanValue = false;
}
if ((element.checked && !booleanValue) || (!element.checked && booleanValue)) {
clickOnElement(element);
dispatchChange(element);
}
return true;
}
if (elementType == "radio") {
return selectRadioValue(element, value);
}
if (textLikeInputType.indexOf(elementType) !== -1) {
return textAreaSetValue(elementXpath, value);
}
//No support for the moment for file stuff or other input types
return null;
}
function textAreaSetValue(elementXpath, value) {
var polterAgent = window.__poltergeist;
var ids = polterAgent.find("xpath", elementXpath, document);
var polterNode = polterAgent.get(ids[0]);
polterNode.set(value);
return true;
}
var node = getElement(xpath);
if (node === null) {
return null;
}
if (isSelect(node)) {
return selectSetValue(node, value);
}
if (isInput(node)) {
return inputSetValue(node, value, xpath);
}
if (isTextArea(node)) {
return textAreaSetValue(xpath, value);
}
//for the moment everything else also to textArea stuff
return textAreaSetValue(xpath, value);
}('{{xpath}}', JSON.parse('{{ value }}')));
{% endautoescape %}

View file

@ -0,0 +1,50 @@
<?php
namespace Zumba\Mink\Driver;
/**
* Trait SessionTrait
* @package Zumba\Mink\Driver
*/
trait SessionTrait {
/** @var bool */
protected $started;
/**
* Starts a session to be used by the driver client
*/
public function start() {
$this->started = true;
}
/**
* Tells if the session is started or not
* @return bool
*/
public function isStarted() {
return $this->started;
}
/**
* Stops the session completely, clean slate for the browser
* @return bool
*/
public function stop() {
//Since we are using a remote browser "API", stopping is just like resetting, say good bye to cookies
//TODO: In the future we may want to control a start / stop of the remove browser
return $this->reset();
}
/**
* Clears the cookies in the browser, all of them
* @return bool
*/
public function reset() {
$this->getBrowser()->clearCookies();
$this->getBrowser()->reset();
$this->started = false;
return true;
}
}

View file

@ -0,0 +1,64 @@
<?php
namespace Zumba\Mink\Driver;
use Behat\Mink\Exception\DriverException;
/**
* Class WindowTrait
* @package Zumba\Mink\Driver
*/
trait WindowTrait {
/**
* Returns the current page window name
* @return string
*/
public function getWindowName() {
return $this->browser->windowName();
}
/**
* Return all the window handles currently present in phantomjs
* @return array
*/
public function getWindowNames() {
return $this->browser->windowHandles();
}
/**
* Switches to window by name if possible
* @param $name
* @throws DriverException
*/
public function switchToWindow($name = null) {
$handles = $this->browser->windowHandles();
if ($name === null) {
//null means back to the main window
return $this->browser->switchToWindow($handles[0]);
}
$windowHandle = $this->browser->windowHandle($name);
if (!empty($windowHandle)) {
$this->browser->switchToWindow($windowHandle);
} else {
throw new DriverException("Could not find window handle by a given window name: $name");
}
}
/**
* Resizing a window with specified size
* @param int $width
* @param int $height
* @param string $name
* @throws DriverException
*/
public function resizeWindow($width, $height, $name = null) {
if ($name !== null) {
//TODO: add this on the phantomjs stuff
throw new DriverException("Resizing other window than the main one is not supported yet");
}
$this->browser->resize($width, $height);
}
}