UrgentcareCLI 0.1.1 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/UrgentCare/CLI.rb +1 -2
- data/lib/UrgentCare/Scraper.rb +65 -0
- data/lib/UrgentCare/version.rb +2 -2
- data/lib/UrgentCare.rb +1 -0
- metadata +3 -313
- data/.gitignore +0 -11
- data/.rspec +0 -3
- data/.travis.yml +0 -5
- data/CODE_OF_CONDUCT.md +0 -74
- data/Gemfile +0 -12
- data/Gemfile.lock +0 -84
- data/LICENSE.txt +0 -21
- data/Notes +0 -41
- data/README.md +0 -41
- data/Rakefile +0 -8
- data/UrgentCare.gemspec +0 -39
- data/background.jpg +0 -0
- data/data.txt +0 -4
- data/lib/Urgentcare/Scraper.rb +0 -78
- data/node_modules/.bin/rimraf +0 -1
- data/node_modules/.package-lock.json +0 -250
- data/node_modules/balanced-match/.github/FUNDING.yml +0 -2
- data/node_modules/balanced-match/LICENSE.md +0 -21
- data/node_modules/balanced-match/README.md +0 -97
- data/node_modules/balanced-match/index.js +0 -62
- data/node_modules/balanced-match/package.json +0 -48
- data/node_modules/brace-expansion/LICENSE +0 -21
- data/node_modules/brace-expansion/README.md +0 -129
- data/node_modules/brace-expansion/index.js +0 -201
- data/node_modules/brace-expansion/package.json +0 -47
- data/node_modules/concat-map/.travis.yml +0 -4
- data/node_modules/concat-map/LICENSE +0 -18
- data/node_modules/concat-map/README.markdown +0 -62
- data/node_modules/concat-map/example/map.js +0 -6
- data/node_modules/concat-map/index.js +0 -13
- data/node_modules/concat-map/package.json +0 -43
- data/node_modules/concat-map/test/map.js +0 -39
- data/node_modules/core-util-is/LICENSE +0 -19
- data/node_modules/core-util-is/README.md +0 -3
- data/node_modules/core-util-is/float.patch +0 -604
- data/node_modules/core-util-is/lib/util.js +0 -107
- data/node_modules/core-util-is/package.json +0 -32
- data/node_modules/core-util-is/test.js +0 -68
- data/node_modules/fs.realpath/LICENSE +0 -43
- data/node_modules/fs.realpath/README.md +0 -33
- data/node_modules/fs.realpath/index.js +0 -66
- data/node_modules/fs.realpath/old.js +0 -303
- data/node_modules/fs.realpath/package.json +0 -26
- data/node_modules/glob/LICENSE +0 -21
- data/node_modules/glob/README.md +0 -375
- data/node_modules/glob/changelog.md +0 -67
- data/node_modules/glob/common.js +0 -234
- data/node_modules/glob/glob.js +0 -788
- data/node_modules/glob/package.json +0 -51
- data/node_modules/glob/sync.js +0 -484
- data/node_modules/immediate/LICENSE.txt +0 -20
- data/node_modules/immediate/README.md +0 -93
- data/node_modules/immediate/dist/immediate.js +0 -75
- data/node_modules/immediate/dist/immediate.min.js +0 -1
- data/node_modules/immediate/lib/browser.js +0 -69
- data/node_modules/immediate/lib/index.js +0 -73
- data/node_modules/immediate/package.json +0 -42
- data/node_modules/inflight/LICENSE +0 -15
- data/node_modules/inflight/README.md +0 -37
- data/node_modules/inflight/inflight.js +0 -54
- data/node_modules/inflight/package.json +0 -29
- data/node_modules/inherits/LICENSE +0 -16
- data/node_modules/inherits/README.md +0 -42
- data/node_modules/inherits/inherits.js +0 -9
- data/node_modules/inherits/inherits_browser.js +0 -27
- data/node_modules/inherits/package.json +0 -29
- data/node_modules/isarray/.npmignore +0 -1
- data/node_modules/isarray/.travis.yml +0 -4
- data/node_modules/isarray/Makefile +0 -6
- data/node_modules/isarray/README.md +0 -60
- data/node_modules/isarray/component.json +0 -19
- data/node_modules/isarray/index.js +0 -5
- data/node_modules/isarray/package.json +0 -45
- data/node_modules/isarray/test.js +0 -20
- data/node_modules/jszip/.codeclimate.yml +0 -16
- data/node_modules/jszip/.editorconfig +0 -8
- data/node_modules/jszip/.jshintignore +0 -1
- data/node_modules/jszip/.jshintrc +0 -21
- data/node_modules/jszip/.travis.yml +0 -17
- data/node_modules/jszip/CHANGES.md +0 -163
- data/node_modules/jszip/LICENSE.markdown +0 -651
- data/node_modules/jszip/README.markdown +0 -35
- data/node_modules/jszip/dist/jszip.js +0 -30
- data/node_modules/jszip/dist/jszip.min.js +0 -13
- data/node_modules/jszip/index.d.ts +0 -270
- data/node_modules/jszip/lib/base64.js +0 -106
- data/node_modules/jszip/lib/compressedObject.js +0 -74
- data/node_modules/jszip/lib/compressions.js +0 -14
- data/node_modules/jszip/lib/crc32.js +0 -77
- data/node_modules/jszip/lib/defaults.js +0 -11
- data/node_modules/jszip/lib/external.js +0 -19
- data/node_modules/jszip/lib/flate.js +0 -85
- data/node_modules/jszip/lib/generate/ZipFileWorker.js +0 -540
- data/node_modules/jszip/lib/generate/index.js +0 -57
- data/node_modules/jszip/lib/index.js +0 -52
- data/node_modules/jszip/lib/license_header.js +0 -11
- data/node_modules/jszip/lib/load.js +0 -81
- data/node_modules/jszip/lib/nodejs/NodejsStreamInputAdapter.js +0 -74
- data/node_modules/jszip/lib/nodejs/NodejsStreamOutputAdapter.js +0 -42
- data/node_modules/jszip/lib/nodejsUtils.js +0 -57
- data/node_modules/jszip/lib/object.js +0 -389
- data/node_modules/jszip/lib/readable-stream-browser.js +0 -9
- data/node_modules/jszip/lib/reader/ArrayReader.js +0 -57
- data/node_modules/jszip/lib/reader/DataReader.js +0 -116
- data/node_modules/jszip/lib/reader/NodeBufferReader.js +0 -19
- data/node_modules/jszip/lib/reader/StringReader.js +0 -38
- data/node_modules/jszip/lib/reader/Uint8ArrayReader.js +0 -22
- data/node_modules/jszip/lib/reader/readerFor.js +0 -28
- data/node_modules/jszip/lib/signature.js +0 -7
- data/node_modules/jszip/lib/stream/ConvertWorker.js +0 -26
- data/node_modules/jszip/lib/stream/Crc32Probe.js +0 -24
- data/node_modules/jszip/lib/stream/DataLengthProbe.js +0 -29
- data/node_modules/jszip/lib/stream/DataWorker.js +0 -116
- data/node_modules/jszip/lib/stream/GenericWorker.js +0 -263
- data/node_modules/jszip/lib/stream/StreamHelper.js +0 -212
- data/node_modules/jszip/lib/support.js +0 -38
- data/node_modules/jszip/lib/utf8.js +0 -275
- data/node_modules/jszip/lib/utils.js +0 -476
- data/node_modules/jszip/lib/zipEntries.js +0 -262
- data/node_modules/jszip/lib/zipEntry.js +0 -294
- data/node_modules/jszip/lib/zipObject.js +0 -133
- data/node_modules/jszip/package.json +0 -63
- data/node_modules/jszip/vendor/FileSaver.js +0 -247
- data/node_modules/lie/README.md +0 -62
- data/node_modules/lie/dist/lie.js +0 -350
- data/node_modules/lie/dist/lie.min.js +0 -1
- data/node_modules/lie/dist/lie.polyfill.js +0 -358
- data/node_modules/lie/dist/lie.polyfill.min.js +0 -1
- data/node_modules/lie/lib/browser.js +0 -273
- data/node_modules/lie/lib/index.js +0 -298
- data/node_modules/lie/license.md +0 -7
- data/node_modules/lie/lie.d.ts +0 -244
- data/node_modules/lie/package.json +0 -69
- data/node_modules/lie/polyfill.js +0 -4
- data/node_modules/minimatch/LICENSE +0 -15
- data/node_modules/minimatch/README.md +0 -209
- data/node_modules/minimatch/minimatch.js +0 -923
- data/node_modules/minimatch/package.json +0 -30
- data/node_modules/once/LICENSE +0 -15
- data/node_modules/once/README.md +0 -79
- data/node_modules/once/once.js +0 -42
- data/node_modules/once/package.json +0 -33
- data/node_modules/pako/CHANGELOG.md +0 -164
- data/node_modules/pako/LICENSE +0 -21
- data/node_modules/pako/README.md +0 -191
- data/node_modules/pako/dist/pako.js +0 -6818
- data/node_modules/pako/dist/pako.min.js +0 -1
- data/node_modules/pako/dist/pako_deflate.js +0 -3997
- data/node_modules/pako/dist/pako_deflate.min.js +0 -1
- data/node_modules/pako/dist/pako_inflate.js +0 -3300
- data/node_modules/pako/dist/pako_inflate.min.js +0 -1
- data/node_modules/pako/index.js +0 -14
- data/node_modules/pako/lib/deflate.js +0 -400
- data/node_modules/pako/lib/inflate.js +0 -423
- data/node_modules/pako/lib/utils/common.js +0 -105
- data/node_modules/pako/lib/utils/strings.js +0 -187
- data/node_modules/pako/lib/zlib/README +0 -59
- data/node_modules/pako/lib/zlib/adler32.js +0 -51
- data/node_modules/pako/lib/zlib/constants.js +0 -68
- data/node_modules/pako/lib/zlib/crc32.js +0 -59
- data/node_modules/pako/lib/zlib/deflate.js +0 -1874
- data/node_modules/pako/lib/zlib/gzheader.js +0 -58
- data/node_modules/pako/lib/zlib/inffast.js +0 -345
- data/node_modules/pako/lib/zlib/inflate.js +0 -1556
- data/node_modules/pako/lib/zlib/inftrees.js +0 -343
- data/node_modules/pako/lib/zlib/messages.js +0 -32
- data/node_modules/pako/lib/zlib/trees.js +0 -1222
- data/node_modules/pako/lib/zlib/zstream.js +0 -47
- data/node_modules/pako/package.json +0 -44
- data/node_modules/path-is-absolute/index.js +0 -20
- data/node_modules/path-is-absolute/license +0 -21
- data/node_modules/path-is-absolute/package.json +0 -43
- data/node_modules/path-is-absolute/readme.md +0 -59
- data/node_modules/process-nextick-args/index.js +0 -45
- data/node_modules/process-nextick-args/license.md +0 -19
- data/node_modules/process-nextick-args/package.json +0 -25
- data/node_modules/process-nextick-args/readme.md +0 -18
- data/node_modules/readable-stream/.travis.yml +0 -34
- data/node_modules/readable-stream/CONTRIBUTING.md +0 -38
- data/node_modules/readable-stream/GOVERNANCE.md +0 -136
- data/node_modules/readable-stream/LICENSE +0 -47
- data/node_modules/readable-stream/README.md +0 -58
- data/node_modules/readable-stream/doc/wg-meetings/2015-01-30.md +0 -60
- data/node_modules/readable-stream/duplex-browser.js +0 -1
- data/node_modules/readable-stream/duplex.js +0 -1
- data/node_modules/readable-stream/lib/_stream_duplex.js +0 -131
- data/node_modules/readable-stream/lib/_stream_passthrough.js +0 -47
- data/node_modules/readable-stream/lib/_stream_readable.js +0 -1019
- data/node_modules/readable-stream/lib/_stream_transform.js +0 -214
- data/node_modules/readable-stream/lib/_stream_writable.js +0 -687
- data/node_modules/readable-stream/lib/internal/streams/BufferList.js +0 -79
- data/node_modules/readable-stream/lib/internal/streams/destroy.js +0 -74
- data/node_modules/readable-stream/lib/internal/streams/stream-browser.js +0 -1
- data/node_modules/readable-stream/lib/internal/streams/stream.js +0 -1
- data/node_modules/readable-stream/package.json +0 -52
- data/node_modules/readable-stream/passthrough.js +0 -1
- data/node_modules/readable-stream/readable-browser.js +0 -7
- data/node_modules/readable-stream/readable.js +0 -19
- data/node_modules/readable-stream/transform.js +0 -1
- data/node_modules/readable-stream/writable-browser.js +0 -1
- data/node_modules/readable-stream/writable.js +0 -8
- data/node_modules/rimraf/LICENSE +0 -15
- data/node_modules/rimraf/README.md +0 -101
- data/node_modules/rimraf/bin.js +0 -50
- data/node_modules/rimraf/package.json +0 -29
- data/node_modules/rimraf/rimraf.js +0 -372
- data/node_modules/safe-buffer/LICENSE +0 -21
- data/node_modules/safe-buffer/README.md +0 -584
- data/node_modules/safe-buffer/index.d.ts +0 -187
- data/node_modules/safe-buffer/index.js +0 -62
- data/node_modules/safe-buffer/package.json +0 -37
- data/node_modules/selenium-webdriver/CHANGES.md +0 -1114
- data/node_modules/selenium-webdriver/LICENSE +0 -202
- data/node_modules/selenium-webdriver/NOTICE +0 -2
- data/node_modules/selenium-webdriver/README.md +0 -229
- data/node_modules/selenium-webdriver/chrome.js +0 -295
- data/node_modules/selenium-webdriver/chromium.js +0 -829
- data/node_modules/selenium-webdriver/devtools/CDPConnection.js +0 -35
- data/node_modules/selenium-webdriver/edge.js +0 -224
- data/node_modules/selenium-webdriver/example/chrome_android.js +0 -45
- data/node_modules/selenium-webdriver/example/chrome_mobile_emulation.js +0 -46
- data/node_modules/selenium-webdriver/example/firefox_channels.js +0 -84
- data/node_modules/selenium-webdriver/example/google_search.js +0 -50
- data/node_modules/selenium-webdriver/example/google_search_test.js +0 -70
- data/node_modules/selenium-webdriver/example/headless.js +0 -63
- data/node_modules/selenium-webdriver/example/logging.js +0 -64
- data/node_modules/selenium-webdriver/firefox.js +0 -789
- data/node_modules/selenium-webdriver/http/index.js +0 -324
- data/node_modules/selenium-webdriver/http/util.js +0 -172
- data/node_modules/selenium-webdriver/ie.js +0 -503
- data/node_modules/selenium-webdriver/index.js +0 -825
- data/node_modules/selenium-webdriver/io/exec.js +0 -162
- data/node_modules/selenium-webdriver/io/index.js +0 -348
- data/node_modules/selenium-webdriver/io/zip.js +0 -223
- data/node_modules/selenium-webdriver/lib/atoms/find-elements.js +0 -123
- data/node_modules/selenium-webdriver/lib/atoms/get-attribute.js +0 -101
- data/node_modules/selenium-webdriver/lib/atoms/is-displayed.js +0 -101
- data/node_modules/selenium-webdriver/lib/atoms/mutation-listener.js +0 -55
- data/node_modules/selenium-webdriver/lib/by.js +0 -415
- data/node_modules/selenium-webdriver/lib/capabilities.js +0 -553
- data/node_modules/selenium-webdriver/lib/command.js +0 -206
- data/node_modules/selenium-webdriver/lib/error.js +0 -605
- data/node_modules/selenium-webdriver/lib/http.js +0 -704
- data/node_modules/selenium-webdriver/lib/input.js +0 -946
- data/node_modules/selenium-webdriver/lib/logging.js +0 -661
- data/node_modules/selenium-webdriver/lib/promise.js +0 -285
- data/node_modules/selenium-webdriver/lib/proxy.js +0 -212
- data/node_modules/selenium-webdriver/lib/session.js +0 -77
- data/node_modules/selenium-webdriver/lib/symbols.js +0 -37
- data/node_modules/selenium-webdriver/lib/until.js +0 -429
- data/node_modules/selenium-webdriver/lib/webdriver.js +0 -2919
- data/node_modules/selenium-webdriver/net/index.js +0 -107
- data/node_modules/selenium-webdriver/net/portprober.js +0 -75
- data/node_modules/selenium-webdriver/opera.js +0 -406
- data/node_modules/selenium-webdriver/package.json +0 -54
- data/node_modules/selenium-webdriver/proxy.js +0 -32
- data/node_modules/selenium-webdriver/remote/index.js +0 -624
- data/node_modules/selenium-webdriver/safari.js +0 -168
- data/node_modules/selenium-webdriver/testing/index.js +0 -504
- data/node_modules/set-immediate-shim/index.js +0 -7
- data/node_modules/set-immediate-shim/package.json +0 -34
- data/node_modules/set-immediate-shim/readme.md +0 -31
- data/node_modules/string_decoder/.travis.yml +0 -50
- data/node_modules/string_decoder/LICENSE +0 -48
- data/node_modules/string_decoder/README.md +0 -47
- data/node_modules/string_decoder/lib/string_decoder.js +0 -296
- data/node_modules/string_decoder/package.json +0 -31
- data/node_modules/tmp/CHANGELOG.md +0 -288
- data/node_modules/tmp/LICENSE +0 -21
- data/node_modules/tmp/README.md +0 -365
- data/node_modules/tmp/lib/tmp.js +0 -780
- data/node_modules/tmp/node_modules/.bin/rimraf +0 -1
- data/node_modules/tmp/node_modules/rimraf/CHANGELOG.md +0 -65
- data/node_modules/tmp/node_modules/rimraf/LICENSE +0 -15
- data/node_modules/tmp/node_modules/rimraf/README.md +0 -101
- data/node_modules/tmp/node_modules/rimraf/bin.js +0 -68
- data/node_modules/tmp/node_modules/rimraf/package.json +0 -32
- data/node_modules/tmp/node_modules/rimraf/rimraf.js +0 -360
- data/node_modules/tmp/package.json +0 -58
- data/node_modules/util-deprecate/History.md +0 -16
- data/node_modules/util-deprecate/LICENSE +0 -24
- data/node_modules/util-deprecate/README.md +0 -53
- data/node_modules/util-deprecate/browser.js +0 -67
- data/node_modules/util-deprecate/node.js +0 -6
- data/node_modules/util-deprecate/package.json +0 -27
- data/node_modules/wrappy/LICENSE +0 -15
- data/node_modules/wrappy/README.md +0 -36
- data/node_modules/wrappy/package.json +0 -29
- data/node_modules/wrappy/wrappy.js +0 -33
- data/node_modules/ws/LICENSE +0 -21
- data/node_modules/ws/README.md +0 -496
- data/node_modules/ws/browser.js +0 -8
- data/node_modules/ws/index.js +0 -10
- data/node_modules/ws/lib/buffer-util.js +0 -129
- data/node_modules/ws/lib/constants.js +0 -10
- data/node_modules/ws/lib/event-target.js +0 -184
- data/node_modules/ws/lib/extension.js +0 -223
- data/node_modules/ws/lib/limiter.js +0 -55
- data/node_modules/ws/lib/permessage-deflate.js +0 -517
- data/node_modules/ws/lib/receiver.js +0 -507
- data/node_modules/ws/lib/sender.js +0 -405
- data/node_modules/ws/lib/stream.js +0 -165
- data/node_modules/ws/lib/validation.js +0 -104
- data/node_modules/ws/lib/websocket-server.js +0 -418
- data/node_modules/ws/lib/websocket.js +0 -942
- data/node_modules/ws/package.json +0 -56
- data/package-lock.json +0 -458
- data/package.json +0 -5
- data/selenium.log +0 -1
- data/spec.md +0 -6
- data/test.data +0 -2110
@@ -1,946 +0,0 @@
|
|
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
|
-
'use strict'
|
19
|
-
|
20
|
-
/**
|
21
|
-
* @fileoverview Defines types related to user input with the WebDriver API.
|
22
|
-
*/
|
23
|
-
|
24
|
-
const promise = require('./promise')
|
25
|
-
const { Command, Name } = require('./command')
|
26
|
-
const {
|
27
|
-
InvalidArgumentError,
|
28
|
-
UnknownCommandError,
|
29
|
-
UnsupportedOperationError,
|
30
|
-
} = require('./error')
|
31
|
-
|
32
|
-
/**
|
33
|
-
* Enumeration of the buttons used in the advanced interactions API.
|
34
|
-
* @enum {number}
|
35
|
-
*/
|
36
|
-
const Button = {
|
37
|
-
LEFT: 0,
|
38
|
-
MIDDLE: 1,
|
39
|
-
RIGHT: 2,
|
40
|
-
}
|
41
|
-
|
42
|
-
/**
|
43
|
-
* Representations of pressable keys that aren't text. These are stored in
|
44
|
-
* the Unicode PUA (Private Use Area) code points, 0xE000-0xF8FF. Refer to
|
45
|
-
* http://www.google.com.au/search?&q=unicode+pua&btnK=Search
|
46
|
-
*
|
47
|
-
* @enum {string}
|
48
|
-
* @see <https://www.w3.org/TR/webdriver/#keyboard-actions>
|
49
|
-
*/
|
50
|
-
const Key = {
|
51
|
-
NULL: '\uE000',
|
52
|
-
CANCEL: '\uE001', // ^break
|
53
|
-
HELP: '\uE002',
|
54
|
-
BACK_SPACE: '\uE003',
|
55
|
-
TAB: '\uE004',
|
56
|
-
CLEAR: '\uE005',
|
57
|
-
RETURN: '\uE006',
|
58
|
-
ENTER: '\uE007',
|
59
|
-
SHIFT: '\uE008',
|
60
|
-
CONTROL: '\uE009',
|
61
|
-
ALT: '\uE00A',
|
62
|
-
PAUSE: '\uE00B',
|
63
|
-
ESCAPE: '\uE00C',
|
64
|
-
SPACE: '\uE00D',
|
65
|
-
PAGE_UP: '\uE00E',
|
66
|
-
PAGE_DOWN: '\uE00F',
|
67
|
-
END: '\uE010',
|
68
|
-
HOME: '\uE011',
|
69
|
-
ARROW_LEFT: '\uE012',
|
70
|
-
LEFT: '\uE012',
|
71
|
-
ARROW_UP: '\uE013',
|
72
|
-
UP: '\uE013',
|
73
|
-
ARROW_RIGHT: '\uE014',
|
74
|
-
RIGHT: '\uE014',
|
75
|
-
ARROW_DOWN: '\uE015',
|
76
|
-
DOWN: '\uE015',
|
77
|
-
INSERT: '\uE016',
|
78
|
-
DELETE: '\uE017',
|
79
|
-
SEMICOLON: '\uE018',
|
80
|
-
EQUALS: '\uE019',
|
81
|
-
|
82
|
-
NUMPAD0: '\uE01A', // number pad keys
|
83
|
-
NUMPAD1: '\uE01B',
|
84
|
-
NUMPAD2: '\uE01C',
|
85
|
-
NUMPAD3: '\uE01D',
|
86
|
-
NUMPAD4: '\uE01E',
|
87
|
-
NUMPAD5: '\uE01F',
|
88
|
-
NUMPAD6: '\uE020',
|
89
|
-
NUMPAD7: '\uE021',
|
90
|
-
NUMPAD8: '\uE022',
|
91
|
-
NUMPAD9: '\uE023',
|
92
|
-
MULTIPLY: '\uE024',
|
93
|
-
ADD: '\uE025',
|
94
|
-
SEPARATOR: '\uE026',
|
95
|
-
SUBTRACT: '\uE027',
|
96
|
-
DECIMAL: '\uE028',
|
97
|
-
DIVIDE: '\uE029',
|
98
|
-
|
99
|
-
F1: '\uE031', // function keys
|
100
|
-
F2: '\uE032',
|
101
|
-
F3: '\uE033',
|
102
|
-
F4: '\uE034',
|
103
|
-
F5: '\uE035',
|
104
|
-
F6: '\uE036',
|
105
|
-
F7: '\uE037',
|
106
|
-
F8: '\uE038',
|
107
|
-
F9: '\uE039',
|
108
|
-
F10: '\uE03A',
|
109
|
-
F11: '\uE03B',
|
110
|
-
F12: '\uE03C',
|
111
|
-
|
112
|
-
COMMAND: '\uE03D', // Apple command key
|
113
|
-
META: '\uE03D', // alias for Windows key
|
114
|
-
|
115
|
-
/**
|
116
|
-
* Japanese modifier key for switching between full- and half-width
|
117
|
-
* characters.
|
118
|
-
* @see <https://en.wikipedia.org/wiki/Language_input_keys>
|
119
|
-
*/
|
120
|
-
ZENKAKU_HANKAKU: '\uE040',
|
121
|
-
}
|
122
|
-
|
123
|
-
/**
|
124
|
-
* Simulate pressing many keys at once in a "chord". Takes a sequence of
|
125
|
-
* {@linkplain Key keys} or strings, appends each of the values to a string,
|
126
|
-
* adds the chord termination key ({@link Key.NULL}) and returns the resulting
|
127
|
-
* string.
|
128
|
-
*
|
129
|
-
* Note: when the low-level webdriver key handlers see Keys.NULL, active
|
130
|
-
* modifier keys (CTRL/ALT/SHIFT/etc) release via a keyup event.
|
131
|
-
*
|
132
|
-
* @param {...string} keys The key sequence to concatenate.
|
133
|
-
* @return {string} The null-terminated key sequence.
|
134
|
-
*/
|
135
|
-
Key.chord = function (...keys) {
|
136
|
-
return keys.join('') + Key.NULL
|
137
|
-
}
|
138
|
-
|
139
|
-
/**
|
140
|
-
* Used with {@link ./webelement.WebElement#sendKeys WebElement#sendKeys} on
|
141
|
-
* file input elements (`<input type="file">`) to detect when the entered key
|
142
|
-
* sequence defines the path to a file.
|
143
|
-
*
|
144
|
-
* By default, {@linkplain ./webelement.WebElement WebElement's} will enter all
|
145
|
-
* key sequences exactly as entered. You may set a
|
146
|
-
* {@linkplain ./webdriver.WebDriver#setFileDetector file detector} on the
|
147
|
-
* parent WebDriver instance to define custom behavior for handling file
|
148
|
-
* elements. Of particular note is the
|
149
|
-
* {@link selenium-webdriver/remote.FileDetector}, which should be used when
|
150
|
-
* running against a remote
|
151
|
-
* [Selenium Server](https://selenium.dev/downloads/).
|
152
|
-
*/
|
153
|
-
class FileDetector {
|
154
|
-
/**
|
155
|
-
* Handles the file specified by the given path, preparing it for use with
|
156
|
-
* the current browser. If the path does not refer to a valid file, it will
|
157
|
-
* be returned unchanged, otherwise a path suitable for use with the current
|
158
|
-
* browser will be returned.
|
159
|
-
*
|
160
|
-
* This default implementation is a no-op. Subtypes may override this function
|
161
|
-
* for custom tailored file handling.
|
162
|
-
*
|
163
|
-
* @param {!./webdriver.WebDriver} driver The driver for the current browser.
|
164
|
-
* @param {string} path The path to process.
|
165
|
-
* @return {!Promise<string>} A promise for the processed file path.
|
166
|
-
* @package
|
167
|
-
*/
|
168
|
-
handleFile(driver, path) { // eslint-disable-line
|
169
|
-
return Promise.resolve(path)
|
170
|
-
}
|
171
|
-
}
|
172
|
-
|
173
|
-
/**
|
174
|
-
* Generic description of a single action to send to the remote end.
|
175
|
-
*
|
176
|
-
* @record
|
177
|
-
* @package
|
178
|
-
*/
|
179
|
-
class Action {
|
180
|
-
constructor() {
|
181
|
-
/** @type {!Action.Type} */
|
182
|
-
this.type
|
183
|
-
/** @type {(number|undefined)} */
|
184
|
-
this.duration
|
185
|
-
/** @type {(string|undefined)} */
|
186
|
-
this.value
|
187
|
-
/** @type {(Button|undefined)} */
|
188
|
-
this.button
|
189
|
-
/** @type {(number|undefined)} */
|
190
|
-
this.x
|
191
|
-
/** @type {(number|undefined)} */
|
192
|
-
this.y
|
193
|
-
}
|
194
|
-
}
|
195
|
-
|
196
|
-
/**
|
197
|
-
* @enum {string}
|
198
|
-
* @package
|
199
|
-
* @see <https://w3c.github.io/webdriver/webdriver-spec.html#terminology-0>
|
200
|
-
*/
|
201
|
-
Action.Type = {
|
202
|
-
KEY_DOWN: 'keyDown',
|
203
|
-
KEY_UP: 'keyUp',
|
204
|
-
PAUSE: 'pause',
|
205
|
-
POINTER_DOWN: 'pointerDown',
|
206
|
-
POINTER_UP: 'pointerUp',
|
207
|
-
POINTER_MOVE: 'pointerMove',
|
208
|
-
POINTER_CANCEL: 'pointerCancel',
|
209
|
-
}
|
210
|
-
|
211
|
-
/**
|
212
|
-
* Represents a user input device.
|
213
|
-
*
|
214
|
-
* @abstract
|
215
|
-
*/
|
216
|
-
class Device {
|
217
|
-
/**
|
218
|
-
* @param {Device.Type} type the input type.
|
219
|
-
* @param {string} id a unique ID for this device.
|
220
|
-
*/
|
221
|
-
constructor(type, id) {
|
222
|
-
/** @private @const */ this.type_ = type
|
223
|
-
/** @private @const */ this.id_ = id
|
224
|
-
}
|
225
|
-
|
226
|
-
/** @return {!Object} the JSON encoding for this device. */
|
227
|
-
toJSON() {
|
228
|
-
return { type: this.type_, id: this.id_ }
|
229
|
-
}
|
230
|
-
}
|
231
|
-
|
232
|
-
/**
|
233
|
-
* Device types supported by the WebDriver protocol.
|
234
|
-
*
|
235
|
-
* @enum {string}
|
236
|
-
* @see <https://w3c.github.io/webdriver/webdriver-spec.html#input-source-state>
|
237
|
-
*/
|
238
|
-
Device.Type = {
|
239
|
-
KEY: 'key',
|
240
|
-
NONE: 'none',
|
241
|
-
POINTER: 'pointer',
|
242
|
-
}
|
243
|
-
|
244
|
-
/**
|
245
|
-
* @param {(string|Key|number)} key
|
246
|
-
* @return {string}
|
247
|
-
* @throws {!(InvalidArgumentError|RangeError)}
|
248
|
-
*/
|
249
|
-
function checkCodePoint(key) {
|
250
|
-
if (typeof key === 'number') {
|
251
|
-
return String.fromCodePoint(key)
|
252
|
-
}
|
253
|
-
|
254
|
-
if (typeof key !== 'string') {
|
255
|
-
throw new InvalidArgumentError(`key is not a string: ${key}`)
|
256
|
-
}
|
257
|
-
|
258
|
-
key = key.normalize()
|
259
|
-
if (Array.from(key).length != 1) {
|
260
|
-
throw new InvalidArgumentError(
|
261
|
-
`key input is not a single code point: ${key}`
|
262
|
-
)
|
263
|
-
}
|
264
|
-
return key
|
265
|
-
}
|
266
|
-
|
267
|
-
/**
|
268
|
-
* Keyboard input device.
|
269
|
-
*
|
270
|
-
* @final
|
271
|
-
* @see <https://www.w3.org/TR/webdriver/#dfn-key-input-source>
|
272
|
-
*/
|
273
|
-
class Keyboard extends Device {
|
274
|
-
/** @param {string} id the device ID. */
|
275
|
-
constructor(id) {
|
276
|
-
super(Device.Type.KEY, id)
|
277
|
-
}
|
278
|
-
|
279
|
-
/**
|
280
|
-
* Generates a key down action.
|
281
|
-
*
|
282
|
-
* @param {(Key|string|number)} key the key to press. This key may be
|
283
|
-
* specified as a {@link Key} value, a specific unicode code point,
|
284
|
-
* or a string containing a single unicode code point.
|
285
|
-
* @return {!Action} a new key down action.
|
286
|
-
* @package
|
287
|
-
*/
|
288
|
-
keyDown(key) {
|
289
|
-
return { type: Action.Type.KEY_DOWN, value: checkCodePoint(key) }
|
290
|
-
}
|
291
|
-
|
292
|
-
/**
|
293
|
-
* Generates a key up action.
|
294
|
-
*
|
295
|
-
* @param {(Key|string|number)} key the key to press. This key may be
|
296
|
-
* specified as a {@link Key} value, a specific unicode code point,
|
297
|
-
* or a string containing a single unicode code point.
|
298
|
-
* @return {!Action} a new key up action.
|
299
|
-
* @package
|
300
|
-
*/
|
301
|
-
keyUp(key) {
|
302
|
-
return { type: Action.Type.KEY_UP, value: checkCodePoint(key) }
|
303
|
-
}
|
304
|
-
}
|
305
|
-
|
306
|
-
/**
|
307
|
-
* Defines the reference point from which to compute offsets for
|
308
|
-
* {@linkplain ./input.Pointer#move pointer move} actions.
|
309
|
-
*
|
310
|
-
* @enum {string}
|
311
|
-
*/
|
312
|
-
const Origin = {
|
313
|
-
/** Compute offsets relative to the pointer's current position. */
|
314
|
-
POINTER: 'pointer',
|
315
|
-
/** Compute offsets relative to the viewport. */
|
316
|
-
VIEWPORT: 'viewport',
|
317
|
-
}
|
318
|
-
|
319
|
-
/**
|
320
|
-
* Pointer input device.
|
321
|
-
*
|
322
|
-
* @final
|
323
|
-
* @see <https://www.w3.org/TR/webdriver/#dfn-pointer-input-source>
|
324
|
-
*/
|
325
|
-
class Pointer extends Device {
|
326
|
-
/**
|
327
|
-
* @param {string} id the device ID.
|
328
|
-
* @param {Pointer.Type} type the pointer type.
|
329
|
-
*/
|
330
|
-
constructor(id, type) {
|
331
|
-
super(Device.Type.POINTER, id)
|
332
|
-
/** @private @const */ this.pointerType_ = type
|
333
|
-
}
|
334
|
-
|
335
|
-
/** @override */
|
336
|
-
toJSON() {
|
337
|
-
return Object.assign(
|
338
|
-
{ parameters: { pointerType: this.pointerType_ } },
|
339
|
-
super.toJSON()
|
340
|
-
)
|
341
|
-
}
|
342
|
-
|
343
|
-
/**
|
344
|
-
* @return {!Action} An action that cancels this pointer's current input.
|
345
|
-
* @package
|
346
|
-
*/
|
347
|
-
cancel() {
|
348
|
-
return { type: Action.Type.POINTER_CANCEL }
|
349
|
-
}
|
350
|
-
|
351
|
-
/**
|
352
|
-
* @param {!Button=} button The button to press.
|
353
|
-
* @return {!Action} An action to press the specified button with this device.
|
354
|
-
* @package
|
355
|
-
*/
|
356
|
-
press(button = Button.LEFT) {
|
357
|
-
return { type: Action.Type.POINTER_DOWN, button }
|
358
|
-
}
|
359
|
-
|
360
|
-
/**
|
361
|
-
* @param {!Button=} button The button to release.
|
362
|
-
* @return {!Action} An action to release the specified button with this
|
363
|
-
* device.
|
364
|
-
* @package
|
365
|
-
*/
|
366
|
-
release(button = Button.LEFT) {
|
367
|
-
return { type: Action.Type.POINTER_UP, button }
|
368
|
-
}
|
369
|
-
|
370
|
-
/**
|
371
|
-
* Creates an action for moving the pointer `x` and `y` pixels from the
|
372
|
-
* specified `origin`. The `origin` may be defined as the pointer's
|
373
|
-
* {@linkplain Origin.POINTER current position}, the
|
374
|
-
* {@linkplain Origin.VIEWPORT viewport}, or the center of a specific
|
375
|
-
* {@linkplain ./webdriver.WebElement WebElement}.
|
376
|
-
*
|
377
|
-
* @param {{
|
378
|
-
* x: (number|undefined),
|
379
|
-
* y: (number|undefined),
|
380
|
-
* duration: (number|undefined),
|
381
|
-
* origin: (!Origin|!./webdriver.WebElement|undefined),
|
382
|
-
* }=} options the move options.
|
383
|
-
* @return {!Action} The new action.
|
384
|
-
* @package
|
385
|
-
*/
|
386
|
-
move({ x = 0, y = 0, duration = 100, origin = Origin.VIEWPORT }) {
|
387
|
-
return { type: Action.Type.POINTER_MOVE, origin, duration, x, y }
|
388
|
-
}
|
389
|
-
}
|
390
|
-
|
391
|
-
/**
|
392
|
-
* The supported types of pointers.
|
393
|
-
* @enum {string}
|
394
|
-
*/
|
395
|
-
Pointer.Type = {
|
396
|
-
MOUSE: 'mouse',
|
397
|
-
PEN: 'pen',
|
398
|
-
TOUCH: 'touch',
|
399
|
-
}
|
400
|
-
|
401
|
-
/**
|
402
|
-
* User facing API for generating complex user gestures. This class should not
|
403
|
-
* be instantiated directly. Instead, users should create new instances by
|
404
|
-
* calling {@link ./webdriver.WebDriver#actions WebDriver.actions()}.
|
405
|
-
*
|
406
|
-
* ### Action Ticks
|
407
|
-
*
|
408
|
-
* Action sequences are divided into a series of "ticks". At each tick, the
|
409
|
-
* WebDriver remote end will perform a single action for each device included
|
410
|
-
* in the action sequence. At tick 0, the driver will perform the first action
|
411
|
-
* defined for each device, at tick 1 the second action for each device, and
|
412
|
-
* so on until all actions have been executed. If an individual device does
|
413
|
-
* not have an action defined at a particular tick, it will automatically
|
414
|
-
* pause.
|
415
|
-
*
|
416
|
-
* By default, action sequences will be synchronized so only one device has a
|
417
|
-
* define action in each tick. Consider the following code sample:
|
418
|
-
*
|
419
|
-
* const actions = driver.actions();
|
420
|
-
*
|
421
|
-
* await actions
|
422
|
-
* .keyDown(SHIFT)
|
423
|
-
* .move({origin: el})
|
424
|
-
* .press()
|
425
|
-
* .release()
|
426
|
-
* .keyUp(SHIFT)
|
427
|
-
* .perform();
|
428
|
-
*
|
429
|
-
* This sample produces the following sequence of ticks:
|
430
|
-
*
|
431
|
-
* | Device | Tick 1 | Tick 2 | Tick 3 | Tick 4 | Tick 5 |
|
432
|
-
* | -------- | -------------- | ------------------ | ------- | --------- | ------------ |
|
433
|
-
* | Keyboard | keyDown(SHIFT) | pause() | pause() | pause() | keyUp(SHIFT) |
|
434
|
-
* | Mouse | pause() | move({origin: el}) | press() | release() | pause() |
|
435
|
-
*
|
436
|
-
* If you'd like the remote end to execute actions with multiple devices
|
437
|
-
* simultaneously, you may pass `{async: true}` when creating the actions
|
438
|
-
* builder. With synchronization disabled (`{async: true}`), the ticks from our
|
439
|
-
* previous example become:
|
440
|
-
*
|
441
|
-
* | Device | Tick 1 | Tick 2 | Tick 3 |
|
442
|
-
* | -------- | ------------------ | ------------ | --------- |
|
443
|
-
* | Keyboard | keyDown(SHIFT) | keyUp(SHIFT) | |
|
444
|
-
* | Mouse | move({origin: el}) | press() | release() |
|
445
|
-
*
|
446
|
-
* When synchronization is disabled, it is your responsibility to insert
|
447
|
-
* {@linkplain #pause() pauses} for each device, as needed:
|
448
|
-
*
|
449
|
-
* const actions = driver.actions({async: true});
|
450
|
-
* const kb = actions.keyboard();
|
451
|
-
* const mouse = actions.mouse();
|
452
|
-
*
|
453
|
-
* actions.keyDown(SHIFT).pause(kb).pause(kb).key(SHIFT);
|
454
|
-
* actions.pause(mouse).move({origin: el}).press().release();
|
455
|
-
* actions.perform();
|
456
|
-
*
|
457
|
-
* With pauses insert for individual devices, we're back to:
|
458
|
-
*
|
459
|
-
* | Device | Tick 1 | Tick 2 | Tick 3 | Tick 4 |
|
460
|
-
* | -------- | -------------- | ------------------ | ------- | ------------ |
|
461
|
-
* | Keyboard | keyDown(SHIFT) | pause() | pause() | keyUp(SHIFT) |
|
462
|
-
* | Mouse | pause() | move({origin: el}) | press() | release() |
|
463
|
-
*
|
464
|
-
* #### Tick Durations
|
465
|
-
*
|
466
|
-
* The length of each action tick is however long it takes the remote end to
|
467
|
-
* execute the actions for every device in that tick. Most actions are
|
468
|
-
* "instantaneous", however, {@linkplain #pause pause} and
|
469
|
-
* {@linkplain #move pointer move} actions allow you to specify a duration for
|
470
|
-
* how long that action should take. The remote end will always wait for all
|
471
|
-
* actions within a tick to finish before starting the next tick, so a device
|
472
|
-
* may implicitly pause while waiting for other devices to finish.
|
473
|
-
*
|
474
|
-
* | Device | Tick 1 | Tick 2 |
|
475
|
-
* | --------- | --------------------- | ------- |
|
476
|
-
* | Pointer 1 | move({duration: 200}) | press() |
|
477
|
-
* | Pointer 2 | move({duration: 300}) | press() |
|
478
|
-
*
|
479
|
-
* In table above, the move for Pointer 1 should only take 200 ms, but the
|
480
|
-
* remote end will wait for the move for Pointer 2 to finish
|
481
|
-
* (an additional 100 ms) before proceeding to Tick 2.
|
482
|
-
*
|
483
|
-
* This implicit waiting also applies to pauses. In the table below, even though
|
484
|
-
* the keyboard only defines a pause of 100 ms, the remote end will wait an
|
485
|
-
* additional 200 ms for the mouse move to finish before moving to Tick 2.
|
486
|
-
*
|
487
|
-
* | Device | Tick 1 | Tick 2 |
|
488
|
-
* | -------- | --------------------- | -------------- |
|
489
|
-
* | Keyboard | pause(100) | keyDown(SHIFT) |
|
490
|
-
* | Mouse | move({duration: 300}) | |
|
491
|
-
*
|
492
|
-
* [client rect]: https://developer.mozilla.org/en-US/docs/Web/API/Element/getClientRects
|
493
|
-
* [bounding client rect]: https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect
|
494
|
-
*
|
495
|
-
* @final
|
496
|
-
* @see <https://www.w3.org/TR/webdriver/#actions>
|
497
|
-
*/
|
498
|
-
class Actions {
|
499
|
-
/**
|
500
|
-
* @param {!Executor} executor The object to execute the configured
|
501
|
-
* actions with.
|
502
|
-
* @param {{async: (boolean|undefined)}} options Options for this action
|
503
|
-
* sequence (see class description for details).
|
504
|
-
*/
|
505
|
-
constructor(executor, { async = false } = {}) {
|
506
|
-
|
507
|
-
/** @private @const */
|
508
|
-
this.executor_ = executor
|
509
|
-
|
510
|
-
/** @private @const */
|
511
|
-
this.sync_ = !async
|
512
|
-
|
513
|
-
/** @private @const */
|
514
|
-
this.keyboard_ = new Keyboard('default keyboard')
|
515
|
-
|
516
|
-
/** @private @const */
|
517
|
-
this.mouse_ = new Pointer('default mouse', Pointer.Type.MOUSE)
|
518
|
-
|
519
|
-
/** @private @const {!Map<!Device, !Array<!Action>>} */
|
520
|
-
this.sequences_ = new Map([
|
521
|
-
[this.keyboard_, []],
|
522
|
-
[this.mouse_, []],
|
523
|
-
])
|
524
|
-
}
|
525
|
-
|
526
|
-
/** @return {!Keyboard} the keyboard device handle. */
|
527
|
-
keyboard() {
|
528
|
-
return this.keyboard_
|
529
|
-
}
|
530
|
-
|
531
|
-
/** @return {!Pointer} the mouse pointer device handle. */
|
532
|
-
mouse() {
|
533
|
-
return this.mouse_
|
534
|
-
}
|
535
|
-
|
536
|
-
/**
|
537
|
-
* @param {!Device} device
|
538
|
-
* @return {!Array<!Action>}
|
539
|
-
* @private
|
540
|
-
*/
|
541
|
-
sequence_(device) {
|
542
|
-
let sequence = this.sequences_.get(device)
|
543
|
-
if (!sequence) {
|
544
|
-
sequence = []
|
545
|
-
this.sequences_.set(device, sequence)
|
546
|
-
}
|
547
|
-
return sequence
|
548
|
-
}
|
549
|
-
|
550
|
-
/**
|
551
|
-
* Appends `actions` to the end of the current sequence for the given
|
552
|
-
* `device`. If device synchronization is enabled, after inserting the
|
553
|
-
* actions, pauses will be inserted for all other devices to ensure all action
|
554
|
-
* sequences are the same length.
|
555
|
-
*
|
556
|
-
* @param {!Device} device the device to update.
|
557
|
-
* @param {...!Action} actions the actions to insert.
|
558
|
-
* @return {!Actions} a self reference.
|
559
|
-
*/
|
560
|
-
insert(device, ...actions) {
|
561
|
-
this.sequence_(device).push(...actions)
|
562
|
-
return this.sync_ ? this.synchronize() : this
|
563
|
-
}
|
564
|
-
|
565
|
-
/**
|
566
|
-
* Ensures the action sequence for every device referenced in this action
|
567
|
-
* sequence is the same length. For devices whose sequence is too short,
|
568
|
-
* this will insert {@linkplain #pause pauses} so that every device has an
|
569
|
-
* explicit action defined at each tick.
|
570
|
-
*
|
571
|
-
* @param {...!Device} devices The specific devices to synchronize.
|
572
|
-
* If unspecified, the action sequences for every device will be
|
573
|
-
* synchronized.
|
574
|
-
* @return {!Actions} a self reference.
|
575
|
-
*/
|
576
|
-
synchronize(...devices) {
|
577
|
-
let sequences
|
578
|
-
let max = 0
|
579
|
-
if (devices.length === 0) {
|
580
|
-
for (const s of this.sequences_.values()) {
|
581
|
-
max = Math.max(max, s.length)
|
582
|
-
}
|
583
|
-
sequences = this.sequences_.values()
|
584
|
-
} else {
|
585
|
-
sequences = []
|
586
|
-
for (const device of devices) {
|
587
|
-
const seq = this.sequence_(device)
|
588
|
-
max = Math.max(max, seq.length)
|
589
|
-
sequences.push(seq)
|
590
|
-
}
|
591
|
-
}
|
592
|
-
|
593
|
-
const pause = { type: Action.Type.PAUSE, duration: 0 }
|
594
|
-
for (const seq of sequences) {
|
595
|
-
while (seq.length < max) {
|
596
|
-
seq.push(pause)
|
597
|
-
}
|
598
|
-
}
|
599
|
-
|
600
|
-
return this
|
601
|
-
}
|
602
|
-
|
603
|
-
/**
|
604
|
-
* Inserts a pause action for the specified devices, ensuring each device is
|
605
|
-
* idle for a tick. The length of the pause (in milliseconds) may be specified
|
606
|
-
* as the first parameter to this method (defaults to 0). Otherwise, you may
|
607
|
-
* just specify the individual devices that should pause.
|
608
|
-
*
|
609
|
-
* If no devices are specified, a pause action will be created (using the same
|
610
|
-
* duration) for every device.
|
611
|
-
*
|
612
|
-
* When device synchronization is enabled (the default for new {@link Actions}
|
613
|
-
* objects), there is no need to specify devices as pausing one automatically
|
614
|
-
* pauses the others for the same duration. In other words, the following are
|
615
|
-
* all equivalent:
|
616
|
-
*
|
617
|
-
* let a1 = driver.actions();
|
618
|
-
* a1.pause(100).perform();
|
619
|
-
*
|
620
|
-
* let a2 = driver.actions();
|
621
|
-
* a2.pause(100, a2.keyboard()).perform();
|
622
|
-
* // Synchronization ensures a2.mouse() is automatically paused too.
|
623
|
-
*
|
624
|
-
* let a3 = driver.actions();
|
625
|
-
* a3.pause(100, a3.keyboard(), a3.mouse()).perform();
|
626
|
-
*
|
627
|
-
* When device synchronization is _disabled_, you can cause individual devices
|
628
|
-
* to pause during a tick. For example, to hold the SHIFT key down while
|
629
|
-
* moving the mouse:
|
630
|
-
*
|
631
|
-
* let actions = driver.actions({async: true});
|
632
|
-
*
|
633
|
-
* actions.keyDown(Key.SHIFT);
|
634
|
-
* actions.pause(actions.mouse()) // Pause for shift down
|
635
|
-
* .press(Button.LEFT)
|
636
|
-
* .move({x: 10, y: 10})
|
637
|
-
* .release(Button.LEFT);
|
638
|
-
* actions
|
639
|
-
* .pause(
|
640
|
-
* actions.keyboard(), // Pause for press left
|
641
|
-
* actions.keyboard(), // Pause for move
|
642
|
-
* actions.keyboard()) // Pause for release left
|
643
|
-
* .keyUp(Key.SHIFT);
|
644
|
-
* await actions.perform();
|
645
|
-
*
|
646
|
-
* @param {(number|!Device)=} duration The length of the pause to insert, in
|
647
|
-
* milliseconds. Alternatively, the duration may be omitted (yielding a
|
648
|
-
* default 0 ms pause), and the first device to pause may be specified.
|
649
|
-
* @param {...!Device} devices The devices to insert the pause for. If no
|
650
|
-
* devices are specified, the pause will be inserted for _all_ devices.
|
651
|
-
* @return {!Actions} a self reference.
|
652
|
-
*/
|
653
|
-
pause(duration, ...devices) {
|
654
|
-
if (duration instanceof Device) {
|
655
|
-
devices.push(duration)
|
656
|
-
duration = 0
|
657
|
-
} else if (!duration) {
|
658
|
-
duration = 0
|
659
|
-
}
|
660
|
-
|
661
|
-
const action = { type: Action.Type.PAUSE, duration }
|
662
|
-
|
663
|
-
// NB: need a properly typed variable for type checking.
|
664
|
-
/** @type {!Iterable<!Device>} */
|
665
|
-
const iterable = devices.length === 0 ? this.sequences_.keys() : devices
|
666
|
-
for (const device of iterable) {
|
667
|
-
this.sequence_(device).push(action)
|
668
|
-
}
|
669
|
-
return this.sync_ ? this.synchronize() : this
|
670
|
-
}
|
671
|
-
|
672
|
-
/**
|
673
|
-
* Inserts an action to press a single key.
|
674
|
-
*
|
675
|
-
* @param {(Key|string|number)} key the key to press. This key may be
|
676
|
-
* specified as a {@link Key} value, a specific unicode code point,
|
677
|
-
* or a string containing a single unicode code point.
|
678
|
-
* @return {!Actions} a self reference.
|
679
|
-
*/
|
680
|
-
keyDown(key) {
|
681
|
-
return this.insert(this.keyboard_, this.keyboard_.keyDown(key))
|
682
|
-
}
|
683
|
-
|
684
|
-
/**
|
685
|
-
* Inserts an action to release a single key.
|
686
|
-
*
|
687
|
-
* @param {(Key|string|number)} key the key to release. This key may be
|
688
|
-
* specified as a {@link Key} value, a specific unicode code point,
|
689
|
-
* or a string containing a single unicode code point.
|
690
|
-
* @return {!Actions} a self reference.
|
691
|
-
*/
|
692
|
-
keyUp(key) {
|
693
|
-
return this.insert(this.keyboard_, this.keyboard_.keyUp(key))
|
694
|
-
}
|
695
|
-
|
696
|
-
/**
|
697
|
-
* Inserts a sequence of actions to type the provided key sequence.
|
698
|
-
* For each key, this will record a pair of {@linkplain #keyDown keyDown}
|
699
|
-
* and {@linkplain #keyUp keyUp} actions. An implication of this pairing
|
700
|
-
* is that modifier keys (e.g. {@link ./input.Key.SHIFT Key.SHIFT}) will
|
701
|
-
* always be immediately released. In other words, `sendKeys(Key.SHIFT, 'a')`
|
702
|
-
* is the same as typing `sendKeys('a')`, _not_ `sendKeys('A')`.
|
703
|
-
*
|
704
|
-
* @param {...(Key|string|number)} keys the keys to type.
|
705
|
-
* @return {!Actions} a self reference.
|
706
|
-
*/
|
707
|
-
sendKeys(...keys) {
|
708
|
-
const actions = []
|
709
|
-
for (const key of keys) {
|
710
|
-
if (typeof key === 'string') {
|
711
|
-
for (const symbol of key) {
|
712
|
-
actions.push(
|
713
|
-
this.keyboard_.keyDown(symbol),
|
714
|
-
this.keyboard_.keyUp(symbol)
|
715
|
-
)
|
716
|
-
}
|
717
|
-
} else {
|
718
|
-
actions.push(this.keyboard_.keyDown(key), this.keyboard_.keyUp(key))
|
719
|
-
}
|
720
|
-
}
|
721
|
-
return this.insert(this.keyboard_, ...actions)
|
722
|
-
}
|
723
|
-
|
724
|
-
/**
|
725
|
-
* Inserts an action to press a mouse button at the mouse's current location.
|
726
|
-
*
|
727
|
-
* @param {!Button=} button The button to press; defaults to `LEFT`.
|
728
|
-
* @return {!Actions} a self reference.
|
729
|
-
*/
|
730
|
-
press(button = Button.LEFT) {
|
731
|
-
return this.insert(this.mouse_, this.mouse_.press(button))
|
732
|
-
}
|
733
|
-
|
734
|
-
/**
|
735
|
-
* Inserts an action to release a mouse button at the mouse's current
|
736
|
-
* location.
|
737
|
-
*
|
738
|
-
* @param {!Button=} button The button to release; defaults to `LEFT`.
|
739
|
-
* @return {!Actions} a self reference.
|
740
|
-
*/
|
741
|
-
release(button = Button.LEFT) {
|
742
|
-
return this.insert(this.mouse_, this.mouse_.release(button))
|
743
|
-
}
|
744
|
-
|
745
|
-
/**
|
746
|
-
* Inserts an action for moving the mouse `x` and `y` pixels relative to the
|
747
|
-
* specified `origin`. The `origin` may be defined as the mouse's
|
748
|
-
* {@linkplain ./input.Origin.POINTER current position}, the
|
749
|
-
* {@linkplain ./input.Origin.VIEWPORT viewport}, or the center of a specific
|
750
|
-
* {@linkplain ./webdriver.WebElement WebElement}.
|
751
|
-
*
|
752
|
-
* You may adjust how long the remote end should take, in milliseconds, to
|
753
|
-
* perform the move using the `duration` parameter (defaults to 100 ms).
|
754
|
-
* The number of incremental move events generated over this duration is an
|
755
|
-
* implementation detail for the remote end.
|
756
|
-
*
|
757
|
-
* @param {{
|
758
|
-
* x: (number|undefined),
|
759
|
-
* y: (number|undefined),
|
760
|
-
* duration: (number|undefined),
|
761
|
-
* origin: (!Origin|!./webdriver.WebElement|undefined),
|
762
|
-
* }=} options The move options. Defaults to moving the mouse to the top-left
|
763
|
-
* corner of the viewport over 100ms.
|
764
|
-
* @return {!Actions} a self reference.
|
765
|
-
*/
|
766
|
-
move({ x = 0, y = 0, duration = 100, origin = Origin.VIEWPORT } = {}) {
|
767
|
-
return this.insert(
|
768
|
-
this.mouse_,
|
769
|
-
this.mouse_.move({ x, y, duration, origin })
|
770
|
-
)
|
771
|
-
}
|
772
|
-
|
773
|
-
/**
|
774
|
-
* Short-hand for performing a simple left-click (down/up) with the mouse.
|
775
|
-
*
|
776
|
-
* @param {./webdriver.WebElement=} element If specified, the mouse will
|
777
|
-
* first be moved to the center of the element before performing the
|
778
|
-
* click.
|
779
|
-
* @return {!Actions} a self reference.
|
780
|
-
*/
|
781
|
-
click(element) {
|
782
|
-
if (element) {
|
783
|
-
this.move({ origin: element })
|
784
|
-
}
|
785
|
-
return this.press().release()
|
786
|
-
}
|
787
|
-
|
788
|
-
/**
|
789
|
-
* Short-hand for performing a simple right-click (down/up) with the mouse.
|
790
|
-
*
|
791
|
-
* @param {./webdriver.WebElement=} element If specified, the mouse will
|
792
|
-
* first be moved to the center of the element before performing the
|
793
|
-
* click.
|
794
|
-
* @return {!Actions} a self reference.
|
795
|
-
*/
|
796
|
-
contextClick(element) {
|
797
|
-
if (element) {
|
798
|
-
this.move({ origin: element })
|
799
|
-
}
|
800
|
-
return this.press(Button.RIGHT).release(Button.RIGHT)
|
801
|
-
}
|
802
|
-
|
803
|
-
/**
|
804
|
-
* Short-hand for performing a double left-click with the mouse.
|
805
|
-
*
|
806
|
-
* @param {./webdriver.WebElement=} element If specified, the mouse will
|
807
|
-
* first be moved to the center of the element before performing the
|
808
|
-
* click.
|
809
|
-
* @return {!Actions} a self reference.
|
810
|
-
*/
|
811
|
-
doubleClick(element) {
|
812
|
-
return this.click(element).press().release()
|
813
|
-
}
|
814
|
-
|
815
|
-
/**
|
816
|
-
* Configures a drag-and-drop action consisting of the following steps:
|
817
|
-
*
|
818
|
-
* 1. Move to the center of the `from` element (element to be dragged).
|
819
|
-
* 2. Press the left mouse button.
|
820
|
-
* 3. If the `to` target is a {@linkplain ./webdriver.WebElement WebElement},
|
821
|
-
* move the mouse to its center. Otherwise, move the mouse by the
|
822
|
-
* specified offset.
|
823
|
-
* 4. Release the left mouse button.
|
824
|
-
*
|
825
|
-
* @param {!./webdriver.WebElement} from The element to press the left mouse
|
826
|
-
* button on to start the drag.
|
827
|
-
* @param {(!./webdriver.WebElement|{x: number, y: number})} to Either another
|
828
|
-
* element to drag to (will drag to the center of the element), or an
|
829
|
-
* object specifying the offset to drag by, in pixels.
|
830
|
-
* @return {!Actions} a self reference.
|
831
|
-
*/
|
832
|
-
dragAndDrop(from, to) {
|
833
|
-
// Do not require up top to avoid a cycle that breaks static analysis.
|
834
|
-
const { WebElement } = require('./webdriver')
|
835
|
-
if (
|
836
|
-
!(to instanceof WebElement) &&
|
837
|
-
(!to || typeof to.x !== 'number' || typeof to.y !== 'number')
|
838
|
-
) {
|
839
|
-
throw new InvalidArgumentError(
|
840
|
-
'Invalid drag target; must specify a WebElement or {x, y} offset'
|
841
|
-
)
|
842
|
-
}
|
843
|
-
|
844
|
-
this.move({ origin: from }).press()
|
845
|
-
if (to instanceof WebElement) {
|
846
|
-
this.move({ origin: to })
|
847
|
-
} else {
|
848
|
-
this.move({ x: to.x, y: to.y, origin: Origin.POINTER })
|
849
|
-
}
|
850
|
-
return this.release()
|
851
|
-
}
|
852
|
-
|
853
|
-
/**
|
854
|
-
* Releases all keys, pointers, and clears internal state.
|
855
|
-
*
|
856
|
-
* @return {!Promise<void>} a promise that will resolve when finished
|
857
|
-
* clearing all action state.
|
858
|
-
*/
|
859
|
-
clear() {
|
860
|
-
for (const s of this.sequences_.values()) {
|
861
|
-
s.length = 0
|
862
|
-
}
|
863
|
-
return this.executor_.execute(new Command(Name.CLEAR_ACTIONS))
|
864
|
-
}
|
865
|
-
|
866
|
-
/**
|
867
|
-
* Performs the configured action sequence.
|
868
|
-
*
|
869
|
-
* @return {!Promise<void>} a promise that will resolve when all actions have
|
870
|
-
* been completed.
|
871
|
-
*/
|
872
|
-
async perform() {
|
873
|
-
const _actions = []
|
874
|
-
this.sequences_.forEach((actions, device) => {
|
875
|
-
if (!isIdle(actions)) {
|
876
|
-
actions = actions.concat() // Defensive copy.
|
877
|
-
_actions.push(Object.assign({ actions }, device.toJSON()))
|
878
|
-
}
|
879
|
-
})
|
880
|
-
|
881
|
-
if (_actions.length === 0) {
|
882
|
-
return Promise.resolve()
|
883
|
-
}
|
884
|
-
|
885
|
-
try {
|
886
|
-
await this.executor_.execute(
|
887
|
-
new Command(Name.ACTIONS).setParameter('actions', _actions)
|
888
|
-
)
|
889
|
-
} catch (ex) {
|
890
|
-
throw ex
|
891
|
-
}
|
892
|
-
}
|
893
|
-
}
|
894
|
-
|
895
|
-
/**
|
896
|
-
* @param {!Array<!Action>} actions
|
897
|
-
* @return {boolean}
|
898
|
-
*/
|
899
|
-
function isIdle(actions) {
|
900
|
-
return (
|
901
|
-
actions.length === 0 ||
|
902
|
-
actions.every((a) => a.type === Action.Type.PAUSE && !a.duration)
|
903
|
-
)
|
904
|
-
}
|
905
|
-
|
906
|
-
/**
|
907
|
-
* Script used to compute the offset from the center of a DOM element's first
|
908
|
-
* client rect from the top-left corner of the element's bounding client rect.
|
909
|
-
* The element's center point is computed using the algorithm defined here:
|
910
|
-
* <https://w3c.github.io/webdriver/webdriver-spec.html#dfn-center-point>.
|
911
|
-
*
|
912
|
-
* __This is only exported for use in internal unit tests. DO NOT USE.__
|
913
|
-
*
|
914
|
-
* @package
|
915
|
-
*/
|
916
|
-
const INTERNAL_COMPUTE_OFFSET_SCRIPT = `
|
917
|
-
function computeOffset(el) {
|
918
|
-
var rect = el.getClientRects()[0];
|
919
|
-
var left = Math.max(0, Math.min(rect.x, rect.x + rect.width));
|
920
|
-
var right =
|
921
|
-
Math.min(window.innerWidth, Math.max(rect.x, rect.x + rect.width));
|
922
|
-
var top = Math.max(0, Math.min(rect.y, rect.y + rect.height));
|
923
|
-
var bot =
|
924
|
-
Math.min(window.innerHeight, Math.max(rect.y, rect.y + rect.height));
|
925
|
-
var x = Math.floor(0.5 * (left + right));
|
926
|
-
var y = Math.floor(0.5 * (top + bot));
|
927
|
-
|
928
|
-
var bbox = el.getBoundingClientRect();
|
929
|
-
return [x - bbox.left, y - bbox.top];
|
930
|
-
}
|
931
|
-
return computeOffset(arguments[0]);`
|
932
|
-
|
933
|
-
// PUBLIC API
|
934
|
-
|
935
|
-
module.exports = {
|
936
|
-
Action, // For documentation only.
|
937
|
-
Actions,
|
938
|
-
Button,
|
939
|
-
Device,
|
940
|
-
Key,
|
941
|
-
Keyboard,
|
942
|
-
FileDetector,
|
943
|
-
Origin,
|
944
|
-
Pointer,
|
945
|
-
INTERNAL_COMPUTE_OFFSET_SCRIPT,
|
946
|
-
}
|