Chris@14: Chris@14: * @author Anthon Pang Chris@14: * @author Fabrizio Branca Chris@14: */ Chris@14: Chris@14: namespace WebDriver; Chris@14: Chris@14: use WebDriver\Exception as WebDriverException; Chris@14: Chris@14: /** Chris@14: * Abstract WebDriver\Container class Chris@14: * Chris@14: * @package WebDriver Chris@14: */ Chris@14: abstract class Container extends AbstractWebDriver Chris@14: { Chris@14: /** Chris@14: * {@inheritdoc} Chris@14: */ Chris@14: public function __construct($url = 'http://localhost:4444/wd/hub') Chris@14: { Chris@14: parent::__construct($url); Chris@14: Chris@14: $locatorStrategy = new \ReflectionClass('WebDriver\LocatorStrategy'); Chris@14: $this->strategies = $locatorStrategy->getConstants(); Chris@14: } Chris@14: Chris@14: /** Chris@14: * Find element: /session/:sessionId/element (POST) Chris@14: * Find child element: /session/:sessionId/element/:id/element (POST) Chris@14: * Search for element on page, starting from the document root. Chris@14: * Chris@14: * @param string $using the locator strategy to use Chris@14: * @param string $value the search target Chris@14: * Chris@14: * @return \WebDriver\Element Chris@14: * Chris@14: * @throws \WebDriver\Exception if element not found, or invalid XPath Chris@14: */ Chris@14: public function element($using = null, $value = null) Chris@14: { Chris@14: $locatorJson = $this->parseArgs('element', func_get_args()); Chris@14: Chris@14: try { Chris@14: $result = $this->curl( Chris@14: 'POST', Chris@14: '/element', Chris@14: $locatorJson Chris@14: ); Chris@14: } catch (WebDriverException\NoSuchElement $e) { Chris@14: throw WebDriverException::factory( Chris@14: WebDriverException::NO_SUCH_ELEMENT, Chris@14: sprintf( Chris@14: "Element not found with %s, %s\n\n%s", Chris@14: $locatorJson['using'], Chris@14: $locatorJson['value'], Chris@14: $e->getMessage() Chris@14: ), Chris@14: $e Chris@14: ); Chris@14: } Chris@14: Chris@14: $element = $this->webDriverElement($result['value']); Chris@14: Chris@14: if ($element === null) { Chris@14: throw WebDriverException::factory( Chris@14: WebDriverException::NO_SUCH_ELEMENT, Chris@14: sprintf( Chris@14: "Element not found with %s, %s\n", Chris@14: $locatorJson['using'], Chris@14: $locatorJson['value'] Chris@14: ) Chris@14: ); Chris@14: } Chris@14: Chris@14: return $element; Chris@14: } Chris@14: Chris@14: /** Chris@14: * Find elements: /session/:sessionId/elements (POST) Chris@14: * Find child elements: /session/:sessionId/element/:id/elements (POST) Chris@14: * Search for multiple elements on page, starting from the document root. Chris@14: * Chris@14: * @param string $using the locator strategy to use Chris@14: * @param string $value the search target Chris@14: * Chris@14: * @return array Chris@14: * Chris@14: * @throws \WebDriver\Exception if invalid XPath Chris@14: */ Chris@14: public function elements($using = null, $value = null) Chris@14: { Chris@14: $locatorJson = $this->parseArgs('elements', func_get_args()); Chris@14: Chris@14: $result = $this->curl( Chris@14: 'POST', Chris@14: '/elements', Chris@14: $locatorJson Chris@14: ); Chris@14: Chris@14: if (!is_array($result['value'])) { Chris@14: return array(); Chris@14: } Chris@14: Chris@14: return array_filter( Chris@14: array_map( Chris@14: array($this, 'webDriverElement'), Chris@14: $result['value'] Chris@14: ) Chris@14: ); Chris@14: } Chris@14: Chris@14: /** Chris@14: * Parse arguments allowing either separate $using and $value parameters, or Chris@14: * as an array containing the JSON parameters Chris@14: * Chris@14: * @param string $method method name Chris@14: * @param array $argv arguments Chris@14: * Chris@14: * @return array Chris@14: * Chris@14: * @throws \WebDriver\Exception if invalid number of arguments to the called method Chris@14: */ Chris@14: private function parseArgs($method, $argv) Chris@14: { Chris@14: $argc = count($argv); Chris@14: Chris@14: switch ($argc) { Chris@14: case 2: Chris@14: $using = $argv[0]; Chris@14: $value = $argv[1]; Chris@14: break; Chris@14: Chris@14: case 1: Chris@14: $arg = $argv[0]; Chris@14: Chris@14: if (is_array($arg)) { Chris@14: $using = $arg['using']; Chris@14: $value = $arg['value']; Chris@14: break; Chris@14: } Chris@14: Chris@14: // fall through Chris@14: default: Chris@14: throw WebDriverException::factory( Chris@14: WebDriverException::JSON_PARAMETERS_EXPECTED, Chris@14: sprintf('Invalid arguments to %s method: %s', $method, print_r($argv, true)) Chris@14: ); Chris@14: } Chris@14: Chris@14: return $this->locate($using, $value); Chris@14: } Chris@14: Chris@14: /** Chris@14: * Return JSON parameter for element / elements command Chris@14: * Chris@14: * @param string $using locator strategy Chris@14: * @param string $value search target Chris@14: * Chris@14: * @return array Chris@14: * Chris@14: * @throws \WebDriver\Exception if invalid locator strategy Chris@14: */ Chris@14: public function locate($using, $value) Chris@14: { Chris@14: if (!in_array($using, $this->strategies)) { Chris@14: throw WebDriverException::factory( Chris@14: WebDriverException::UNKNOWN_LOCATOR_STRATEGY, Chris@14: sprintf('Invalid locator strategy %s', $using) Chris@14: ); Chris@14: } Chris@14: Chris@14: return array( Chris@14: 'using' => $using, Chris@14: 'value' => $value, Chris@14: ); Chris@14: } Chris@14: Chris@14: /** Chris@14: * Return WebDriver\Element wrapper for $value Chris@14: * Chris@14: * @param mixed $value Chris@14: * Chris@14: * @return \WebDriver\Element|null Chris@14: */ Chris@14: protected function webDriverElement($value) Chris@14: { Chris@14: return array_key_exists('ELEMENT', (array) $value) Chris@14: ? new Element( Chris@14: $this->getElementPath($value['ELEMENT']), // url Chris@14: $value['ELEMENT'] // id Chris@14: ) Chris@14: : null; Chris@14: } Chris@14: Chris@14: /** Chris@14: * {@inheritdoc} Chris@14: */ Chris@14: public function __call($name, $arguments) Chris@14: { Chris@14: if (count($arguments) === 1 && in_array(str_replace('_', ' ', $name), $this->strategies)) { Chris@14: return $this->locate($name, $arguments[0]); Chris@14: } Chris@14: Chris@14: // fallback to executing WebDriver commands Chris@14: return parent::__call($name, $arguments); Chris@14: } Chris@14: Chris@14: /** Chris@14: * Get wire protocol URL for an element Chris@14: * Chris@14: * @param string $elementId Chris@14: * Chris@14: * @return string Chris@14: */ Chris@14: abstract protected function getElementPath($elementId); Chris@14: }