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 | * Recognized browser names.
|
29 | * @enum {string}
|
30 | */
|
31 | const Browser = {
|
32 | CHROME: 'chrome',
|
33 | EDGE: 'MicrosoftEdge',
|
34 | FIREFOX: 'firefox',
|
35 | INTERNET_EXPLORER: 'internet explorer',
|
36 | SAFARI: 'safari',
|
37 | OPERA: 'opera',
|
38 | }
|
39 |
|
40 | /**
|
41 | * Strategies for waiting for [document readiness] after a navigation
|
42 | * event.
|
43 | *
|
44 | * [document readiness]: https://html.spec.whatwg.org/#current-document-readiness
|
45 | *
|
46 | * @enum {string}
|
47 | */
|
48 | const PageLoadStrategy = {
|
49 | /**
|
50 | * Indicates WebDriver should not wait on the document readiness state after a
|
51 | * navigation event.
|
52 | */
|
53 | NONE: 'none',
|
54 |
|
55 | /**
|
56 | * Indicates WebDriver should wait for the document readiness state to
|
57 | * become "interactive" after navigation.
|
58 | */
|
59 | EAGER: 'eager',
|
60 |
|
61 | /**
|
62 | * Indicates WebDriver should wait for the document readiness state to
|
63 | * be "complete" after navigation. This is the default page loading strategy.
|
64 | */
|
65 | NORMAL: 'normal',
|
66 | }
|
67 |
|
68 | /**
|
69 | * Common platform names. These platforms are not explicitly defined by the
|
70 | * WebDriver spec, however, their use is encouraged for interoperability.
|
71 | *
|
72 | * @enum {string}
|
73 | * @see <https://w3c.github.io/webdriver/webdriver-spec.html>
|
74 | */
|
75 | const Platform = {
|
76 | LINUX: 'linux',
|
77 | MAC: 'mac',
|
78 | WINDOWS: 'windows',
|
79 | }
|
80 |
|
81 | /**
|
82 | * Record object defining the timeouts that apply to certain WebDriver actions.
|
83 | *
|
84 | * @record
|
85 | */
|
86 | function Timeouts() { }
|
87 |
|
88 | /**
|
89 | * Defines when, in milliseconds, to interrupt a script that is being
|
90 | * {@linkplain ./webdriver.IWebDriver#executeScript evaluated}.
|
91 | * @type {number}
|
92 | */
|
93 | Timeouts.prototype.script
|
94 |
|
95 | /**
|
96 | * The timeout, in milliseconds, to apply to navigation events along with the
|
97 | * {@link PageLoadStrategy}.
|
98 | * @type {number}
|
99 | */
|
100 | Timeouts.prototype.pageLoad
|
101 |
|
102 | /**
|
103 | * The maximum amount of time, in milliseconds, to spend attempting to
|
104 | * {@linkplain ./webdriver.IWebDriver#findElement locate} an element on the
|
105 | * current page.
|
106 | * @type {number}
|
107 | */
|
108 | Timeouts.prototype.implicit
|
109 |
|
110 | /**
|
111 | * The possible default actions a WebDriver session can take to respond to
|
112 | * unhandled user prompts (`window.alert()`, `window.confirm()`, and
|
113 | * `window.prompt()`).
|
114 | *
|
115 | * @enum {string}
|
116 | */
|
117 | const UserPromptHandler = {
|
118 | /** All prompts should be silently accepted. */
|
119 | ACCEPT: 'accept',
|
120 | /** All prompts should be silently dismissed. */
|
121 | DISMISS: 'dismiss',
|
122 | /**
|
123 | * All prompts should be automatically accepted, but an error should be
|
124 | * returned to the next (or currently executing) WebDriver command.
|
125 | */
|
126 | ACCEPT_AND_NOTIFY: 'accept and notify',
|
127 | /**
|
128 | * All prompts should be automatically dismissed, but an error should be
|
129 | * returned to the next (or currently executing) WebDriver command.
|
130 | */
|
131 | DISMISS_AND_NOTIFY: 'dismiss and notify',
|
132 | /** All prompts should be left unhandled. */
|
133 | IGNORE: 'ignore',
|
134 | }
|
135 |
|
136 | /**
|
137 | * The standard WebDriver capability keys.
|
138 | *
|
139 | * @enum {string}
|
140 | * @see <https://w3c.github.io/webdriver/webdriver-spec.html#capabilities>
|
141 | */
|
142 | const Capability = {
|
143 | /**
|
144 | * Indicates whether a WebDriver session implicitly trusts otherwise untrusted
|
145 | * and self-signed TLS certificates during navigation.
|
146 | */
|
147 | ACCEPT_INSECURE_TLS_CERTS: 'acceptInsecureCerts',
|
148 |
|
149 | /**
|
150 | * The browser name. Common browser names are defined in the
|
151 | * {@link ./capabilities.Browser Browser} enum.
|
152 | */
|
153 | BROWSER_NAME: 'browserName',
|
154 |
|
155 | /** Identifies the browser version. */
|
156 | BROWSER_VERSION: 'browserVersion',
|
157 |
|
158 | /**
|
159 | * Key for the logging driver logging preferences.
|
160 | * The browser name. Common browser names are defined in the
|
161 | * {@link ./capabilities.Browser Browser} enum.
|
162 | */
|
163 | LOGGING_PREFS: 'goog:loggingPrefs',
|
164 |
|
165 | /**
|
166 | * Defines the session's
|
167 | * {@linkplain ./capabilities.PageLoadStrategy page loading strategy}.
|
168 | */
|
169 | PAGE_LOAD_STRATEGY: 'pageLoadStrategy',
|
170 |
|
171 | /**
|
172 | * Identifies the operating system of the endpoint node. Common values
|
173 | * recognized by the most WebDriver server implementations are predefined in
|
174 | * the {@link ./capabilities.Platform Platform} enum.
|
175 | */
|
176 | PLATFORM_NAME: 'platformName',
|
177 |
|
178 | /**
|
179 | * Describes the proxy configuration to use for a new WebDriver session.
|
180 | */
|
181 | PROXY: 'proxy',
|
182 |
|
183 | /**
|
184 | * Indicates whether the remote end supports all of the window resizing and
|
185 | * positioning commands:
|
186 | *
|
187 | * - {@linkplain ./webdriver.Window#getRect Window.getRect()}
|
188 | * - {@linkplain ./webdriver.Window#setRect Window.setRect()}
|
189 | * - {@linkplain ./webdriver.Window#maximize Window.maximize()}
|
190 | * - {@linkplain ./webdriver.Window#minimize Window.minimize()}
|
191 | * - {@linkplain ./webdriver.Window#fullscreen Window.fullscreen()}
|
192 | */
|
193 | SET_WINDOW_RECT: 'setWindowRect',
|
194 |
|
195 | /**
|
196 | * Describes the {@linkplain ./capabilities.Timeouts timeouts} imposed on
|
197 | * certain session operations.
|
198 | */
|
199 | TIMEOUTS: 'timeouts',
|
200 |
|
201 | /**
|
202 | * Defines how a WebDriver session should
|
203 | * {@linkplain ./capabilities.UserPromptHandler respond} to unhandled user
|
204 | * prompts.
|
205 | */
|
206 | UNHANDLED_PROMPT_BEHAVIOR: 'unhandledPromptBehavior',
|
207 |
|
208 | /**
|
209 | * Defines the current session’s strict file interactability.
|
210 | * Used to upload a file when strict file interactability is on
|
211 | */
|
212 | STRICT_FILE_INTERACTABILITY: 'strictFileInteractability',
|
213 | }
|
214 |
|
215 | /**
|
216 | * Converts a generic hash object to a map.
|
217 | * @param {!Object<string, ?>} hash The hash object.
|
218 | * @return {!Map<string, ?>} The converted map.
|
219 | */
|
220 | function toMap(hash) {
|
221 | let m = new Map()
|
222 | for (let key in hash) {
|
223 | if (Object.prototype.hasOwnProperty.call(hash, key)) {
|
224 | m.set(key, hash[key])
|
225 | }
|
226 | }
|
227 | return m
|
228 | }
|
229 |
|
230 | /**
|
231 | * Describes a set of capabilities for a WebDriver session.
|
232 | */
|
233 | class Capabilities {
|
234 | /**
|
235 | * @param {(Capabilities|Map<string, ?>|Object)=} other Another set of
|
236 | * capabilities to initialize this instance from.
|
237 | */
|
238 | constructor(other = undefined) {
|
239 | if (other instanceof Capabilities) {
|
240 | other = other.map_
|
241 | } else if (other && !(other instanceof Map)) {
|
242 | other = toMap(other)
|
243 | }
|
244 | /** @private @const {!Map<string, ?>} */
|
245 | this.map_ = new Map(other)
|
246 | }
|
247 |
|
248 | /**
|
249 | * @return {!Capabilities} A basic set of capabilities for Chrome.
|
250 | */
|
251 | static chrome() {
|
252 | return new Capabilities().setBrowserName(Browser.CHROME)
|
253 | }
|
254 |
|
255 | /**
|
256 | * @return {!Capabilities} A basic set of capabilities for Microsoft Edge.
|
257 | */
|
258 | static edge() {
|
259 | return new Capabilities().setBrowserName(Browser.EDGE)
|
260 | }
|
261 |
|
262 | /**
|
263 | * @return {!Capabilities} A basic set of capabilities for Firefox.
|
264 | */
|
265 | static firefox() {
|
266 | return new Capabilities()
|
267 | .setBrowserName(Browser.FIREFOX)
|
268 | .set('moz:debuggerAddress', true)
|
269 | }
|
270 |
|
271 | /**
|
272 | * @return {!Capabilities} A basic set of capabilities for Internet Explorer.
|
273 | */
|
274 | static ie() {
|
275 | return new Capabilities().setBrowserName(Browser.INTERNET_EXPLORER)
|
276 | }
|
277 |
|
278 | /**
|
279 | * @return {!Capabilities} A basic set of capabilities for Safari.
|
280 | */
|
281 | static safari() {
|
282 | return new Capabilities().setBrowserName(Browser.SAFARI)
|
283 | }
|
284 |
|
285 | /**
|
286 | * @return {!Capabilities} A basic set of capabilities for Opera
|
287 | */
|
288 | static opera() {
|
289 | return new Capabilities().setBrowserName(Browser.OPERA)
|
290 | }
|
291 |
|
292 | /**
|
293 | * @return {!Object<string, ?>} The JSON representation of this instance.
|
294 | * Note, the returned object may contain nested promised values.
|
295 | * @suppress {checkTypes} Suppress [] access on a struct (state inherited from
|
296 | * Map).
|
297 | */
|
298 | [Symbols.serialize]() {
|
299 | return serialize(this)
|
300 | }
|
301 |
|
302 | /**
|
303 | * @param {string} key the parameter key to get.
|
304 | * @return {T} the stored parameter value.
|
305 | * @template T
|
306 | */
|
307 | get(key) {
|
308 | return this.map_.get(key)
|
309 | }
|
310 |
|
311 | /**
|
312 | * @param {string} key the key to test.
|
313 | * @return {boolean} whether this capability set has the specified key.
|
314 | */
|
315 | has(key) {
|
316 | return this.map_.has(key)
|
317 | }
|
318 |
|
319 | /**
|
320 | * @return {!Iterator<string>} an iterator of the keys set.
|
321 | */
|
322 | keys() {
|
323 | return this.map_.keys()
|
324 | }
|
325 |
|
326 | /** @return {number} The number of capabilities set. */
|
327 | get size() {
|
328 | return this.map_.size
|
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 | let otherMap
|
340 | if (other instanceof Capabilities) {
|
341 | otherMap = other.map_
|
342 | } else if (other instanceof Map) {
|
343 | otherMap = other
|
344 | } else {
|
345 | otherMap = toMap(other)
|
346 | }
|
347 | otherMap.forEach((value, key) => {
|
348 | this.set(key, value)
|
349 | })
|
350 | return this
|
351 | } else {
|
352 | throw new TypeError('no capabilities provided for merge')
|
353 | }
|
354 | }
|
355 |
|
356 | /**
|
357 | * Deletes an entry from this set of capabilities.
|
358 | *
|
359 | * @param {string} key the capability key to delete.
|
360 | */
|
361 | delete(key) {
|
362 | this.map_.delete(key)
|
363 | }
|
364 |
|
365 | /**
|
366 | * @param {string} key The capability key.
|
367 | * @param {*} value The capability value.
|
368 | * @return {!Capabilities} A self reference.
|
369 | * @throws {TypeError} If the `key` is not a string.
|
370 | */
|
371 | set(key, value) {
|
372 | if (typeof key !== 'string') {
|
373 | throw new TypeError('Capability keys must be strings: ' + typeof key)
|
374 | }
|
375 | this.map_.set(key, value)
|
376 | return this
|
377 | }
|
378 |
|
379 | /**
|
380 | * Sets whether a WebDriver session should implicitly accept self-signed, or
|
381 | * other untrusted TLS certificates on navigation.
|
382 | *
|
383 | * @param {boolean} accept whether to accept insecure certs.
|
384 | * @return {!Capabilities} a self reference.
|
385 | */
|
386 | setAcceptInsecureCerts(accept) {
|
387 | return this.set(Capability.ACCEPT_INSECURE_TLS_CERTS, accept)
|
388 | }
|
389 |
|
390 | /**
|
391 | * @return {boolean} whether the session is configured to accept insecure
|
392 | * TLS certificates.
|
393 | */
|
394 | getAcceptInsecureCerts() {
|
395 | return this.get(Capability.ACCEPT_INSECURE_TLS_CERTS)
|
396 | }
|
397 |
|
398 | /**
|
399 | * Sets the name of the target browser.
|
400 | *
|
401 | * @param {(Browser|string)} name the browser name.
|
402 | * @return {!Capabilities} a self reference.
|
403 | */
|
404 | setBrowserName(name) {
|
405 | return this.set(Capability.BROWSER_NAME, name)
|
406 | }
|
407 |
|
408 | /**
|
409 | * @return {(string|undefined)} the configured browser name, or undefined if
|
410 | * not set.
|
411 | */
|
412 | getBrowserName() {
|
413 | return this.get(Capability.BROWSER_NAME)
|
414 | }
|
415 |
|
416 | /**
|
417 | * Sets the desired version of the target browser.
|
418 | *
|
419 | * @param {string} version the desired version.
|
420 | * @return {!Capabilities} a self reference.
|
421 | */
|
422 | setBrowserVersion(version) {
|
423 | return this.set(Capability.BROWSER_VERSION, version)
|
424 | }
|
425 |
|
426 | /**
|
427 | * @return {(string|undefined)} the configured browser version, or undefined
|
428 | * if not set.
|
429 | */
|
430 | getBrowserVersion() {
|
431 | return this.get(Capability.BROWSER_VERSION)
|
432 | }
|
433 |
|
434 | /**
|
435 | * Sets the desired page loading strategy for a new WebDriver session.
|
436 | *
|
437 | * @param {PageLoadStrategy} strategy the desired strategy.
|
438 | * @return {!Capabilities} a self reference.
|
439 | */
|
440 | setPageLoadStrategy(strategy) {
|
441 | return this.set(Capability.PAGE_LOAD_STRATEGY, strategy)
|
442 | }
|
443 |
|
444 | /**
|
445 | * Returns the configured page load strategy.
|
446 | *
|
447 | * @return {(string|undefined)} the page load strategy.
|
448 | */
|
449 | getPageLoadStrategy() {
|
450 | return this.get(Capability.PAGE_LOAD_STRATEGY)
|
451 | }
|
452 |
|
453 | /**
|
454 | * Sets the target platform.
|
455 | *
|
456 | * @param {(Platform|string)} platform the target platform.
|
457 | * @return {!Capabilities} a self reference.
|
458 | */
|
459 | setPlatform(platform) {
|
460 | return this.set(Capability.PLATFORM_NAME, platform)
|
461 | }
|
462 |
|
463 | /**
|
464 | * @return {(string|undefined)} the configured platform or undefined if not
|
465 | * set.
|
466 | */
|
467 | getPlatform() {
|
468 | return this.get(Capability.PLATFORM_NAME)
|
469 | }
|
470 |
|
471 | /**
|
472 | * Sets the logging preferences. Preferences may be specified as a
|
473 | * {@link ./logging.Preferences} instance, or as a map of log-type to
|
474 | * log-level.
|
475 | * @param {!(./logging.Preferences|Object<string>)} prefs The logging
|
476 | * preferences.
|
477 | * @return {!Capabilities} A self reference.
|
478 | */
|
479 | setLoggingPrefs(prefs) {
|
480 | return this.set(Capability.LOGGING_PREFS, prefs)
|
481 | }
|
482 |
|
483 | /**
|
484 | * Sets the proxy configuration for this instance.
|
485 | * @param {proxy.Config} proxy The desired proxy configuration.
|
486 | * @return {!Capabilities} A self reference.
|
487 | */
|
488 | setProxy(proxy) {
|
489 | return this.set(Capability.PROXY, proxy)
|
490 | }
|
491 |
|
492 | /**
|
493 | * @return {(proxy.Config|undefined)} the configured proxy settings, or
|
494 | * undefined if not set.
|
495 | */
|
496 | getProxy() {
|
497 | return this.get(Capability.PROXY)
|
498 | }
|
499 |
|
500 | /**
|
501 | * Sets the default action to take with an unexpected alert before returning
|
502 | * an error. If unspecified, WebDriver will default to
|
503 | * {@link UserPromptHandler.DISMISS_AND_NOTIFY}.
|
504 | *
|
505 | * @param {?UserPromptHandler} behavior The way WebDriver should respond to
|
506 | * unhandled user prompts.
|
507 | * @return {!Capabilities} A self reference.
|
508 | */
|
509 | setAlertBehavior(behavior) {
|
510 | return this.set(Capability.UNHANDLED_PROMPT_BEHAVIOR, behavior)
|
511 | }
|
512 |
|
513 | /**
|
514 | * @return {(UserPromptHandler|undefined)} the behavior pattern for responding
|
515 | * to unhandled user prompts, or undefined if not set.
|
516 | */
|
517 | getAlertBehavior() {
|
518 | return this.get(Capability.UNHANDLED_PROMPT_BEHAVIOR)
|
519 | }
|
520 |
|
521 | /**
|
522 | * Sets the boolean flag configuration for this instance.
|
523 | */
|
524 | setStrictFileInteractability(strictFileInteractability) {
|
525 | return this.set(
|
526 | Capability.STRICT_FILE_INTERACTABILITY,
|
527 | strictFileInteractability
|
528 | )
|
529 | }
|
530 | }
|
531 |
|
532 | /**
|
533 | * Serializes a capabilities object. This is defined as a standalone function
|
534 | * so it may be type checked (where Capabilities[Symbols.serialize] has type
|
535 | * checking disabled since it is defined with [] access on a struct).
|
536 | *
|
537 | * @param {!Capabilities} caps The capabilities to serialize.
|
538 | * @return {!Object<string, ?>} The JSON representation of this instance.
|
539 | * Note, the returned object may contain nested promised values.
|
540 | */
|
541 | function serialize(caps) {
|
542 | let ret = {}
|
543 | for (let key of caps.keys()) {
|
544 | let cap = caps.get(key)
|
545 | if (cap !== undefined && cap !== null) {
|
546 | ret[key] = cap
|
547 | }
|
548 | }
|
549 | return ret
|
550 | }
|
551 |
|
552 | // PUBLIC API
|
553 |
|
554 | module.exports = {
|
555 | Browser,
|
556 | Capabilities,
|
557 | Capability,
|
558 | PageLoadStrategy,
|
559 | Platform,
|
560 | Timeouts,
|
561 | UserPromptHandler,
|
562 | }
|