Chris@14
|
1 <?php
|
Chris@14
|
2 /**
|
Chris@14
|
3 * Copyright 2004-2017 Facebook. All Rights Reserved.
|
Chris@14
|
4 *
|
Chris@14
|
5 * Licensed under the Apache License, Version 2.0 (the "License");
|
Chris@14
|
6 * you may not use this file except in compliance with the License.
|
Chris@14
|
7 * You may obtain a copy of the License at
|
Chris@14
|
8 *
|
Chris@14
|
9 * http://www.apache.org/licenses/LICENSE-2.0
|
Chris@14
|
10 *
|
Chris@14
|
11 * Unless required by applicable law or agreed to in writing, software
|
Chris@14
|
12 * distributed under the License is distributed on an "AS IS" BASIS,
|
Chris@14
|
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
Chris@14
|
14 * See the License for the specific language governing permissions and
|
Chris@14
|
15 * limitations under the License.
|
Chris@14
|
16 *
|
Chris@14
|
17 * @package WebDriver
|
Chris@14
|
18 *
|
Chris@14
|
19 * @author Justin Bishop <jubishop@gmail.com>
|
Chris@14
|
20 * @author Anthon Pang <apang@softwaredevelopment.ca>
|
Chris@14
|
21 * @author Fabrizio Branca <mail@fabrizio-branca.de>
|
Chris@14
|
22 */
|
Chris@14
|
23
|
Chris@14
|
24 namespace WebDriver;
|
Chris@14
|
25
|
Chris@14
|
26 use WebDriver\Exception as WebDriverException;
|
Chris@14
|
27
|
Chris@14
|
28 /**
|
Chris@14
|
29 * Abstract WebDriver\Container class
|
Chris@14
|
30 *
|
Chris@14
|
31 * @package WebDriver
|
Chris@14
|
32 */
|
Chris@14
|
33 abstract class Container extends AbstractWebDriver
|
Chris@14
|
34 {
|
Chris@14
|
35 /**
|
Chris@14
|
36 * {@inheritdoc}
|
Chris@14
|
37 */
|
Chris@14
|
38 public function __construct($url = 'http://localhost:4444/wd/hub')
|
Chris@14
|
39 {
|
Chris@14
|
40 parent::__construct($url);
|
Chris@14
|
41
|
Chris@14
|
42 $locatorStrategy = new \ReflectionClass('WebDriver\LocatorStrategy');
|
Chris@14
|
43 $this->strategies = $locatorStrategy->getConstants();
|
Chris@14
|
44 }
|
Chris@14
|
45
|
Chris@14
|
46 /**
|
Chris@14
|
47 * Find element: /session/:sessionId/element (POST)
|
Chris@14
|
48 * Find child element: /session/:sessionId/element/:id/element (POST)
|
Chris@14
|
49 * Search for element on page, starting from the document root.
|
Chris@14
|
50 *
|
Chris@14
|
51 * @param string $using the locator strategy to use
|
Chris@14
|
52 * @param string $value the search target
|
Chris@14
|
53 *
|
Chris@14
|
54 * @return \WebDriver\Element
|
Chris@14
|
55 *
|
Chris@14
|
56 * @throws \WebDriver\Exception if element not found, or invalid XPath
|
Chris@14
|
57 */
|
Chris@14
|
58 public function element($using = null, $value = null)
|
Chris@14
|
59 {
|
Chris@14
|
60 $locatorJson = $this->parseArgs('element', func_get_args());
|
Chris@14
|
61
|
Chris@14
|
62 try {
|
Chris@14
|
63 $result = $this->curl(
|
Chris@14
|
64 'POST',
|
Chris@14
|
65 '/element',
|
Chris@14
|
66 $locatorJson
|
Chris@14
|
67 );
|
Chris@14
|
68 } catch (WebDriverException\NoSuchElement $e) {
|
Chris@14
|
69 throw WebDriverException::factory(
|
Chris@14
|
70 WebDriverException::NO_SUCH_ELEMENT,
|
Chris@14
|
71 sprintf(
|
Chris@14
|
72 "Element not found with %s, %s\n\n%s",
|
Chris@14
|
73 $locatorJson['using'],
|
Chris@14
|
74 $locatorJson['value'],
|
Chris@14
|
75 $e->getMessage()
|
Chris@14
|
76 ),
|
Chris@14
|
77 $e
|
Chris@14
|
78 );
|
Chris@14
|
79 }
|
Chris@14
|
80
|
Chris@14
|
81 $element = $this->webDriverElement($result['value']);
|
Chris@14
|
82
|
Chris@14
|
83 if ($element === null) {
|
Chris@14
|
84 throw WebDriverException::factory(
|
Chris@14
|
85 WebDriverException::NO_SUCH_ELEMENT,
|
Chris@14
|
86 sprintf(
|
Chris@14
|
87 "Element not found with %s, %s\n",
|
Chris@14
|
88 $locatorJson['using'],
|
Chris@14
|
89 $locatorJson['value']
|
Chris@14
|
90 )
|
Chris@14
|
91 );
|
Chris@14
|
92 }
|
Chris@14
|
93
|
Chris@14
|
94 return $element;
|
Chris@14
|
95 }
|
Chris@14
|
96
|
Chris@14
|
97 /**
|
Chris@14
|
98 * Find elements: /session/:sessionId/elements (POST)
|
Chris@14
|
99 * Find child elements: /session/:sessionId/element/:id/elements (POST)
|
Chris@14
|
100 * Search for multiple elements on page, starting from the document root.
|
Chris@14
|
101 *
|
Chris@14
|
102 * @param string $using the locator strategy to use
|
Chris@14
|
103 * @param string $value the search target
|
Chris@14
|
104 *
|
Chris@14
|
105 * @return array
|
Chris@14
|
106 *
|
Chris@14
|
107 * @throws \WebDriver\Exception if invalid XPath
|
Chris@14
|
108 */
|
Chris@14
|
109 public function elements($using = null, $value = null)
|
Chris@14
|
110 {
|
Chris@14
|
111 $locatorJson = $this->parseArgs('elements', func_get_args());
|
Chris@14
|
112
|
Chris@14
|
113 $result = $this->curl(
|
Chris@14
|
114 'POST',
|
Chris@14
|
115 '/elements',
|
Chris@14
|
116 $locatorJson
|
Chris@14
|
117 );
|
Chris@14
|
118
|
Chris@14
|
119 if (!is_array($result['value'])) {
|
Chris@14
|
120 return array();
|
Chris@14
|
121 }
|
Chris@14
|
122
|
Chris@14
|
123 return array_filter(
|
Chris@14
|
124 array_map(
|
Chris@14
|
125 array($this, 'webDriverElement'),
|
Chris@14
|
126 $result['value']
|
Chris@14
|
127 )
|
Chris@14
|
128 );
|
Chris@14
|
129 }
|
Chris@14
|
130
|
Chris@14
|
131 /**
|
Chris@14
|
132 * Parse arguments allowing either separate $using and $value parameters, or
|
Chris@14
|
133 * as an array containing the JSON parameters
|
Chris@14
|
134 *
|
Chris@14
|
135 * @param string $method method name
|
Chris@14
|
136 * @param array $argv arguments
|
Chris@14
|
137 *
|
Chris@14
|
138 * @return array
|
Chris@14
|
139 *
|
Chris@14
|
140 * @throws \WebDriver\Exception if invalid number of arguments to the called method
|
Chris@14
|
141 */
|
Chris@14
|
142 private function parseArgs($method, $argv)
|
Chris@14
|
143 {
|
Chris@14
|
144 $argc = count($argv);
|
Chris@14
|
145
|
Chris@14
|
146 switch ($argc) {
|
Chris@14
|
147 case 2:
|
Chris@14
|
148 $using = $argv[0];
|
Chris@14
|
149 $value = $argv[1];
|
Chris@14
|
150 break;
|
Chris@14
|
151
|
Chris@14
|
152 case 1:
|
Chris@14
|
153 $arg = $argv[0];
|
Chris@14
|
154
|
Chris@14
|
155 if (is_array($arg)) {
|
Chris@14
|
156 $using = $arg['using'];
|
Chris@14
|
157 $value = $arg['value'];
|
Chris@14
|
158 break;
|
Chris@14
|
159 }
|
Chris@14
|
160
|
Chris@14
|
161 // fall through
|
Chris@14
|
162 default:
|
Chris@14
|
163 throw WebDriverException::factory(
|
Chris@14
|
164 WebDriverException::JSON_PARAMETERS_EXPECTED,
|
Chris@14
|
165 sprintf('Invalid arguments to %s method: %s', $method, print_r($argv, true))
|
Chris@14
|
166 );
|
Chris@14
|
167 }
|
Chris@14
|
168
|
Chris@14
|
169 return $this->locate($using, $value);
|
Chris@14
|
170 }
|
Chris@14
|
171
|
Chris@14
|
172 /**
|
Chris@14
|
173 * Return JSON parameter for element / elements command
|
Chris@14
|
174 *
|
Chris@14
|
175 * @param string $using locator strategy
|
Chris@14
|
176 * @param string $value search target
|
Chris@14
|
177 *
|
Chris@14
|
178 * @return array
|
Chris@14
|
179 *
|
Chris@14
|
180 * @throws \WebDriver\Exception if invalid locator strategy
|
Chris@14
|
181 */
|
Chris@14
|
182 public function locate($using, $value)
|
Chris@14
|
183 {
|
Chris@14
|
184 if (!in_array($using, $this->strategies)) {
|
Chris@14
|
185 throw WebDriverException::factory(
|
Chris@14
|
186 WebDriverException::UNKNOWN_LOCATOR_STRATEGY,
|
Chris@14
|
187 sprintf('Invalid locator strategy %s', $using)
|
Chris@14
|
188 );
|
Chris@14
|
189 }
|
Chris@14
|
190
|
Chris@14
|
191 return array(
|
Chris@14
|
192 'using' => $using,
|
Chris@14
|
193 'value' => $value,
|
Chris@14
|
194 );
|
Chris@14
|
195 }
|
Chris@14
|
196
|
Chris@14
|
197 /**
|
Chris@14
|
198 * Return WebDriver\Element wrapper for $value
|
Chris@14
|
199 *
|
Chris@14
|
200 * @param mixed $value
|
Chris@14
|
201 *
|
Chris@14
|
202 * @return \WebDriver\Element|null
|
Chris@14
|
203 */
|
Chris@14
|
204 protected function webDriverElement($value)
|
Chris@14
|
205 {
|
Chris@14
|
206 return array_key_exists('ELEMENT', (array) $value)
|
Chris@14
|
207 ? new Element(
|
Chris@14
|
208 $this->getElementPath($value['ELEMENT']), // url
|
Chris@14
|
209 $value['ELEMENT'] // id
|
Chris@14
|
210 )
|
Chris@14
|
211 : null;
|
Chris@14
|
212 }
|
Chris@14
|
213
|
Chris@14
|
214 /**
|
Chris@14
|
215 * {@inheritdoc}
|
Chris@14
|
216 */
|
Chris@14
|
217 public function __call($name, $arguments)
|
Chris@14
|
218 {
|
Chris@14
|
219 if (count($arguments) === 1 && in_array(str_replace('_', ' ', $name), $this->strategies)) {
|
Chris@14
|
220 return $this->locate($name, $arguments[0]);
|
Chris@14
|
221 }
|
Chris@14
|
222
|
Chris@14
|
223 // fallback to executing WebDriver commands
|
Chris@14
|
224 return parent::__call($name, $arguments);
|
Chris@14
|
225 }
|
Chris@14
|
226
|
Chris@14
|
227 /**
|
Chris@14
|
228 * Get wire protocol URL for an element
|
Chris@14
|
229 *
|
Chris@14
|
230 * @param string $elementId
|
Chris@14
|
231 *
|
Chris@14
|
232 * @return string
|
Chris@14
|
233 */
|
Chris@14
|
234 abstract protected function getElementPath($elementId);
|
Chris@14
|
235 }
|