1 | // Licensed to the Software Freedom Conservancy (SFC) under one
|
2 | // or more contributor license agreements. See the NOTICE file
|
3 | // distributed with this work for additional information
|
4 | // regarding copyright ownership. The SFC licenses this file
|
5 | // to you under the Apache License, Version 2.0 (the
|
6 | // "License"); you may not use this file except in compliance
|
7 | // with the License. You may obtain a copy of the License at
|
8 | //
|
9 | // http://www.apache.org/licenses/LICENSE-2.0
|
10 | //
|
11 | // Unless required by applicable law or agreed to in writing,
|
12 | // software distributed under the License is distributed on an
|
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
14 | // KIND, either express or implied. See the License for the
|
15 | // specific language governing permissions and limitations
|
16 | // under the License.
|
17 |
|
18 | ;
|
19 |
|
20 | /**
|
21 | * @fileoverview Defines types related to describing the capabilities of a
|
22 | * WebDriver session.
|
23 | */
|
24 |
|
25 | const Symbols = require('./symbols');
|
26 |
|
27 |
|
28 | /**
|
29 | * Recognized browser names.
|
30 | * @enum {string}
|
31 | */
|
32 | const Browser = {
|
33 | ANDROID: 'android',
|
34 | CHROME: 'chrome',
|
35 | EDGE: 'MicrosoftEdge',
|
36 | FIREFOX: 'firefox',
|
37 | IE: 'internet explorer',
|
38 | INTERNET_EXPLORER: 'internet explorer',
|
39 | IPAD: 'iPad',
|
40 | IPHONE: 'iPhone',
|
41 | OPERA: 'opera',
|
42 | PHANTOM_JS: 'phantomjs',
|
43 | SAFARI: 'safari',
|
44 | HTMLUNIT: 'htmlunit'
|
45 | };
|
46 |
|
47 |
|
48 | /**
|
49 | * Common Capability keys.
|
50 | * @enum {string}
|
51 | */
|
52 | const Capability = {
|
53 |
|
54 | /**
|
55 | * Indicates whether a driver should accept all SSL certs by default. This
|
56 | * capability only applies when requesting a new session. To query whether
|
57 | * a driver can handle insecure SSL certs, see {@link #SECURE_SSL}.
|
58 | */
|
59 | ACCEPT_SSL_CERTS: 'acceptSslCerts',
|
60 |
|
61 |
|
62 | /**
|
63 | * The browser name. Common browser names are defined in the {@link Browser}
|
64 | * enum.
|
65 | */
|
66 | BROWSER_NAME: 'browserName',
|
67 |
|
68 | /**
|
69 | * Defines how elements should be scrolled into the viewport for interaction.
|
70 | * This capability will be set to zero (0) if elements are aligned with the
|
71 | * top of the viewport, or one (1) if aligned with the bottom. The default
|
72 | * behavior is to align with the top of the viewport.
|
73 | */
|
74 | ELEMENT_SCROLL_BEHAVIOR: 'elementScrollBehavior',
|
75 |
|
76 | /**
|
77 | * Whether the driver is capable of handling modal alerts (e.g. alert,
|
78 | * confirm, prompt). To define how a driver <i>should</i> handle alerts,
|
79 | * use {@link #UNEXPECTED_ALERT_BEHAVIOR}.
|
80 | */
|
81 | HANDLES_ALERTS: 'handlesAlerts',
|
82 |
|
83 | /**
|
84 | * Key for the logging driver logging preferences.
|
85 | */
|
86 | LOGGING_PREFS: 'loggingPrefs',
|
87 |
|
88 | /**
|
89 | * Whether this session generates native events when simulating user input.
|
90 | */
|
91 | NATIVE_EVENTS: 'nativeEvents',
|
92 |
|
93 | /**
|
94 | * Describes the platform the browser is running on. Will be one of
|
95 | * ANDROID, IOS, LINUX, MAC, UNIX, or WINDOWS. When <i>requesting</i> a
|
96 | * session, ANY may be used to indicate no platform preference (this is
|
97 | * semantically equivalent to omitting the platform capability).
|
98 | */
|
99 | PLATFORM: 'platform',
|
100 |
|
101 | /**
|
102 | * Describes the proxy configuration to use for a new WebDriver session.
|
103 | */
|
104 | PROXY: 'proxy',
|
105 |
|
106 | /** Whether the driver supports changing the brower's orientation. */
|
107 | ROTATABLE: 'rotatable',
|
108 |
|
109 | /**
|
110 | * Whether a driver is only capable of handling secure SSL certs. To request
|
111 | * that a driver accept insecure SSL certs by default, use
|
112 | * {@link #ACCEPT_SSL_CERTS}.
|
113 | */
|
114 | SECURE_SSL: 'secureSsl',
|
115 |
|
116 | /** Whether the driver supports manipulating the app cache. */
|
117 | SUPPORTS_APPLICATION_CACHE: 'applicationCacheEnabled',
|
118 |
|
119 | /** Whether the driver supports locating elements with CSS selectors. */
|
120 | SUPPORTS_CSS_SELECTORS: 'cssSelectorsEnabled',
|
121 |
|
122 | /** Whether the browser supports JavaScript. */
|
123 | SUPPORTS_JAVASCRIPT: 'javascriptEnabled',
|
124 |
|
125 | /** Whether the driver supports controlling the browser's location info. */
|
126 | SUPPORTS_LOCATION_CONTEXT: 'locationContextEnabled',
|
127 |
|
128 | /** Whether the driver supports taking screenshots. */
|
129 | TAKES_SCREENSHOT: 'takesScreenshot',
|
130 |
|
131 | /**
|
132 | * Defines how the driver should handle unexpected alerts. The value should
|
133 | * be one of "accept", "dismiss", or "ignore.
|
134 | */
|
135 | UNEXPECTED_ALERT_BEHAVIOR: 'unexpectedAlertBehavior',
|
136 |
|
137 | /** Defines the browser version. */
|
138 | VERSION: 'version'
|
139 | };
|
140 |
|
141 |
|
142 | /**
|
143 | * Describes how a proxy should be configured for a WebDriver session.
|
144 | * @record
|
145 | */
|
146 | function ProxyConfig() {}
|
147 |
|
148 | /**
|
149 | * The proxy type. Must be one of {"manual", "pac", "system"}.
|
150 | * @type {string}
|
151 | */
|
152 | ProxyConfig.prototype.proxyType;
|
153 |
|
154 | /**
|
155 | * URL for the PAC file to use. Only used if {@link #proxyType} is "pac".
|
156 | * @type {(string|undefined)}
|
157 | */
|
158 | ProxyConfig.prototype.proxyAutoconfigUrl;
|
159 |
|
160 | /**
|
161 | * The proxy host for FTP requests. Only used if {@link #proxyType} is "manual".
|
162 | * @type {(string|undefined)}
|
163 | */
|
164 | ProxyConfig.prototype.ftpProxy;
|
165 |
|
166 | /**
|
167 | * The proxy host for HTTP requests. Only used if {@link #proxyType} is
|
168 | * "manual".
|
169 | * @type {(string|undefined)}
|
170 | */
|
171 | ProxyConfig.prototype.httpProxy;
|
172 |
|
173 | /**
|
174 | * The proxy host for HTTPS requests. Only used if {@link #proxyType} is
|
175 | * "manual".
|
176 | * @type {(string|undefined)}
|
177 | */
|
178 | ProxyConfig.prototype.sslProxy;
|
179 |
|
180 | /**
|
181 | * A comma delimited list of hosts which should bypass all proxies. Only used if
|
182 | * {@link #proxyType} is "manual".
|
183 | * @type {(string|undefined)}
|
184 | */
|
185 | ProxyConfig.prototype.noProxy;
|
186 |
|
187 |
|
188 | /**
|
189 | * Converts a generic hash object to a map.
|
190 | * @param {!Object<string, ?>} hash The hash object.
|
191 | * @return {!Map<string, ?>} The converted map.
|
192 | */
|
193 | function toMap(hash) {
|
194 | let m = new Map;
|
195 | for (let key in hash) {
|
196 | if (hash.hasOwnProperty(key)) {
|
197 | m.set(key, hash[key]);
|
198 | }
|
199 | }
|
200 | return m;
|
201 | }
|
202 |
|
203 |
|
204 | /**
|
205 | * Describes a set of capabilities for a WebDriver session.
|
206 | */
|
207 | class Capabilities extends Map {
|
208 | /**
|
209 | * @param {(Capabilities|Map<string, ?>|Object)=} opt_other Another set of
|
210 | * capabilities to initialize this instance from.
|
211 | */
|
212 | constructor(opt_other) {
|
213 | if (opt_other && !(opt_other instanceof Map)) {
|
214 | opt_other = toMap(opt_other);
|
215 | }
|
216 | super(opt_other);
|
217 | }
|
218 |
|
219 | /**
|
220 | * @return {!Capabilities} A basic set of capabilities for Android.
|
221 | */
|
222 | static android() {
|
223 | return new Capabilities()
|
224 | .set(Capability.BROWSER_NAME, Browser.ANDROID)
|
225 | .set(Capability.PLATFORM, 'ANDROID');
|
226 | }
|
227 |
|
228 | /**
|
229 | * @return {!Capabilities} A basic set of capabilities for Chrome.
|
230 | */
|
231 | static chrome() {
|
232 | return new Capabilities().set(Capability.BROWSER_NAME, Browser.CHROME);
|
233 | }
|
234 |
|
235 | /**
|
236 | * @return {!Capabilities} A basic set of capabilities for Microsoft Edge.
|
237 | */
|
238 | static edge() {
|
239 | return new Capabilities()
|
240 | .set(Capability.BROWSER_NAME, Browser.EDGE)
|
241 | .set(Capability.PLATFORM, 'WINDOWS');
|
242 | }
|
243 |
|
244 | /**
|
245 | * @return {!Capabilities} A basic set of capabilities for Firefox.
|
246 | */
|
247 | static firefox() {
|
248 | return new Capabilities().set(Capability.BROWSER_NAME, Browser.FIREFOX);
|
249 | }
|
250 |
|
251 | /**
|
252 | * @return {!Capabilities} A basic set of capabilities for Internet Explorer.
|
253 | */
|
254 | static ie() {
|
255 | return new Capabilities().
|
256 | set(Capability.BROWSER_NAME, Browser.INTERNET_EXPLORER).
|
257 | set(Capability.PLATFORM, 'WINDOWS');
|
258 | }
|
259 |
|
260 | /**
|
261 | * @return {!Capabilities} A basic set of capabilities for iPad.
|
262 | */
|
263 | static ipad() {
|
264 | return new Capabilities().
|
265 | set(Capability.BROWSER_NAME, Browser.IPAD).
|
266 | set(Capability.PLATFORM, 'MAC');
|
267 | }
|
268 |
|
269 | /**
|
270 | * @return {!Capabilities} A basic set of capabilities for iPhone.
|
271 | */
|
272 | static iphone() {
|
273 | return new Capabilities().
|
274 | set(Capability.BROWSER_NAME, Browser.IPHONE).
|
275 | set(Capability.PLATFORM, 'MAC');
|
276 | }
|
277 |
|
278 | /**
|
279 | * @return {!Capabilities} A basic set of capabilities for Opera.
|
280 | */
|
281 | static opera() {
|
282 | return new Capabilities().
|
283 | set(Capability.BROWSER_NAME, Browser.OPERA);
|
284 | }
|
285 |
|
286 | /**
|
287 | * @return {!Capabilities} A basic set of capabilities for PhantomJS.
|
288 | */
|
289 | static phantomjs() {
|
290 | return new Capabilities().
|
291 | set(Capability.BROWSER_NAME, Browser.PHANTOM_JS);
|
292 | }
|
293 |
|
294 | /**
|
295 | * @return {!Capabilities} A basic set of capabilities for Safari.
|
296 | */
|
297 | static safari() {
|
298 | return new Capabilities().
|
299 | set(Capability.BROWSER_NAME, Browser.SAFARI).
|
300 | set(Capability.PLATFORM, 'MAC');
|
301 | }
|
302 |
|
303 | /**
|
304 | * @return {!Capabilities} A basic set of capabilities for HTMLUnit.
|
305 | */
|
306 | static htmlunit() {
|
307 | return new Capabilities().
|
308 | set(Capability.BROWSER_NAME, Browser.HTMLUNIT);
|
309 | }
|
310 |
|
311 | /**
|
312 | * @return {!Capabilities} A basic set of capabilities for HTMLUnit
|
313 | * with enabled Javascript.
|
314 | */
|
315 | static htmlunitwithjs() {
|
316 | return new Capabilities().
|
317 | set(Capability.BROWSER_NAME, Browser.HTMLUNIT).
|
318 | set(Capability.SUPPORTS_JAVASCRIPT, true);
|
319 | }
|
320 |
|
321 | /**
|
322 | * @return {!Object<string, ?>} The JSON representation of this instance.
|
323 | * Note, the returned object may contain nested promised values.
|
324 | * @suppress {checkTypes} Suppress [] access on a struct (state inherited from
|
325 | * Map).
|
326 | */
|
327 | [Symbols.serialize]() {
|
328 | return serialize(this);
|
329 | }
|
330 |
|
331 | /**
|
332 | * Merges another set of capabilities into this instance.
|
333 | * @param {!(Capabilities|Map<String, ?>|Object<string, ?>)} other The other
|
334 | * set of capabilities to merge.
|
335 | * @return {!Capabilities} A self reference.
|
336 | */
|
337 | merge(other) {
|
338 | if (!other) {
|
339 | throw new TypeError('no capabilities provided for merge');
|
340 | }
|
341 |
|
342 | if (!(other instanceof Map)) {
|
343 | other = toMap(other);
|
344 | }
|
345 |
|
346 | for (let key of other.keys()) {
|
347 | this.set(key, other.get(key));
|
348 | }
|
349 |
|
350 | return this;
|
351 | }
|
352 |
|
353 | /**
|
354 | * @param {string} key The capability key.
|
355 | * @param {*} value The capability value.
|
356 | * @return {!Capabilities} A self reference.
|
357 | * @throws {TypeError} If the `key` is not a string.
|
358 | * @override
|
359 | */
|
360 | set(key, value) {
|
361 | if (typeof key !== 'string') {
|
362 | throw new TypeError('Capability keys must be strings: ' + typeof key);
|
363 | }
|
364 | super.set(key, value);
|
365 | return this;
|
366 | }
|
367 |
|
368 | /**
|
369 | * Sets the logging preferences. Preferences may be specified as a
|
370 | * {@link ./logging.Preferences} instance, or a as a map of log-type to
|
371 | * log-level.
|
372 | * @param {!(./logging.Preferences|Object<string>)} prefs The logging
|
373 | * preferences.
|
374 | * @return {!Capabilities} A self reference.
|
375 | */
|
376 | setLoggingPrefs(prefs) {
|
377 | return this.set(Capability.LOGGING_PREFS, prefs);
|
378 | }
|
379 |
|
380 | /**
|
381 | * Sets the proxy configuration for this instance.
|
382 | * @param {ProxyConfig} proxy The desired proxy configuration.
|
383 | * @return {!Capabilities} A self reference.
|
384 | */
|
385 | setProxy(proxy) {
|
386 | return this.set(Capability.PROXY, proxy);
|
387 | }
|
388 |
|
389 | /**
|
390 | * Sets whether native events should be used.
|
391 | * @param {boolean} enabled Whether to enable native events.
|
392 | * @return {!Capabilities} A self reference.
|
393 | */
|
394 | setEnableNativeEvents(enabled) {
|
395 | return this.set(Capability.NATIVE_EVENTS, enabled);
|
396 | }
|
397 |
|
398 | /**
|
399 | * Sets how elements should be scrolled into view for interaction.
|
400 | * @param {number} behavior The desired scroll behavior: either 0 to align
|
401 | * with the top of the viewport or 1 to align with the bottom.
|
402 | * @return {!Capabilities} A self reference.
|
403 | */
|
404 | setScrollBehavior(behavior) {
|
405 | return this.set(Capability.ELEMENT_SCROLL_BEHAVIOR, behavior);
|
406 | }
|
407 |
|
408 | /**
|
409 | * Sets the default action to take with an unexpected alert before returning
|
410 | * an error.
|
411 | * @param {string} behavior The desired behavior; should be "accept",
|
412 | * "dismiss", or "ignore". Defaults to "dismiss".
|
413 | * @return {!Capabilities} A self reference.
|
414 | */
|
415 | setAlertBehavior(behavior) {
|
416 | return this.set(Capability.UNEXPECTED_ALERT_BEHAVIOR, behavior);
|
417 | }
|
418 | }
|
419 |
|
420 |
|
421 | /**
|
422 | * Serializes a capabilities object. This is defined as a standalone function
|
423 | * so it may be type checked (where Capabilities[Symbols.serialize] has type
|
424 | * checking disabled since it is defined with [] access on a struct).
|
425 | *
|
426 | * @param {!Capabilities} caps The capabilities to serialize.
|
427 | * @return {!Object<string, ?>} The JSON representation of this instance.
|
428 | * Note, the returned object may contain nested promised values.
|
429 | */
|
430 | function serialize(caps) {
|
431 | let ret = {};
|
432 | for (let key of caps.keys()) {
|
433 | let cap = caps.get(key);
|
434 | if (cap !== undefined && cap !== null) {
|
435 | ret[key] = cap;
|
436 | }
|
437 | }
|
438 | return ret;
|
439 | }
|
440 |
|
441 |
|
442 | // PUBLIC API
|
443 |
|
444 |
|
445 | module.exports = {
|
446 | Browser: Browser,
|
447 | Capabilities: Capabilities,
|
448 | Capability: Capability,
|
449 | ProxyConfig: ProxyConfig
|
450 | };
|