UrgentcareCLI 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (308) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +60 -25
  4. data/Notes +1 -1
  5. data/README.md +5 -5
  6. data/Rakefile +2 -0
  7. data/UrgentCare.gemspec +3 -3
  8. data/background.jpg +0 -0
  9. data/lib/UrgentCare.rb +3 -0
  10. data/lib/UrgentCare/CLI.rb +6 -2
  11. data/lib/UrgentCare/version.rb +1 -1
  12. data/lib/Urgentcare/Scraper.rb +65 -23
  13. data/node_modules/.bin/rimraf +1 -0
  14. data/node_modules/.package-lock.json +250 -0
  15. data/node_modules/balanced-match/.github/FUNDING.yml +2 -0
  16. data/node_modules/balanced-match/LICENSE.md +21 -0
  17. data/node_modules/balanced-match/README.md +97 -0
  18. data/node_modules/balanced-match/index.js +62 -0
  19. data/node_modules/balanced-match/package.json +48 -0
  20. data/node_modules/brace-expansion/LICENSE +21 -0
  21. data/node_modules/brace-expansion/README.md +129 -0
  22. data/node_modules/brace-expansion/index.js +201 -0
  23. data/node_modules/brace-expansion/package.json +47 -0
  24. data/node_modules/concat-map/.travis.yml +4 -0
  25. data/node_modules/concat-map/LICENSE +18 -0
  26. data/node_modules/concat-map/README.markdown +62 -0
  27. data/node_modules/concat-map/example/map.js +6 -0
  28. data/node_modules/concat-map/index.js +13 -0
  29. data/node_modules/concat-map/package.json +43 -0
  30. data/node_modules/concat-map/test/map.js +39 -0
  31. data/node_modules/core-util-is/LICENSE +19 -0
  32. data/node_modules/core-util-is/README.md +3 -0
  33. data/node_modules/core-util-is/float.patch +604 -0
  34. data/node_modules/core-util-is/lib/util.js +107 -0
  35. data/node_modules/core-util-is/package.json +32 -0
  36. data/node_modules/core-util-is/test.js +68 -0
  37. data/node_modules/fs.realpath/LICENSE +43 -0
  38. data/node_modules/fs.realpath/README.md +33 -0
  39. data/node_modules/fs.realpath/index.js +66 -0
  40. data/node_modules/fs.realpath/old.js +303 -0
  41. data/node_modules/fs.realpath/package.json +26 -0
  42. data/node_modules/glob/LICENSE +21 -0
  43. data/node_modules/glob/README.md +375 -0
  44. data/node_modules/glob/changelog.md +67 -0
  45. data/node_modules/glob/common.js +234 -0
  46. data/node_modules/glob/glob.js +788 -0
  47. data/node_modules/glob/package.json +51 -0
  48. data/node_modules/glob/sync.js +484 -0
  49. data/node_modules/immediate/LICENSE.txt +20 -0
  50. data/node_modules/immediate/README.md +93 -0
  51. data/node_modules/immediate/dist/immediate.js +75 -0
  52. data/node_modules/immediate/dist/immediate.min.js +1 -0
  53. data/node_modules/immediate/lib/browser.js +69 -0
  54. data/node_modules/immediate/lib/index.js +73 -0
  55. data/node_modules/immediate/package.json +42 -0
  56. data/node_modules/inflight/LICENSE +15 -0
  57. data/node_modules/inflight/README.md +37 -0
  58. data/node_modules/inflight/inflight.js +54 -0
  59. data/node_modules/inflight/package.json +29 -0
  60. data/node_modules/inherits/LICENSE +16 -0
  61. data/node_modules/inherits/README.md +42 -0
  62. data/node_modules/inherits/inherits.js +9 -0
  63. data/node_modules/inherits/inherits_browser.js +27 -0
  64. data/node_modules/inherits/package.json +29 -0
  65. data/node_modules/isarray/.npmignore +1 -0
  66. data/node_modules/isarray/.travis.yml +4 -0
  67. data/node_modules/isarray/Makefile +6 -0
  68. data/node_modules/isarray/README.md +60 -0
  69. data/node_modules/isarray/component.json +19 -0
  70. data/node_modules/isarray/index.js +5 -0
  71. data/node_modules/isarray/package.json +45 -0
  72. data/node_modules/isarray/test.js +20 -0
  73. data/node_modules/jszip/.codeclimate.yml +16 -0
  74. data/node_modules/jszip/.editorconfig +8 -0
  75. data/node_modules/jszip/.jshintignore +1 -0
  76. data/node_modules/jszip/.jshintrc +21 -0
  77. data/node_modules/jszip/.travis.yml +17 -0
  78. data/node_modules/jszip/CHANGES.md +163 -0
  79. data/node_modules/jszip/LICENSE.markdown +651 -0
  80. data/node_modules/jszip/README.markdown +35 -0
  81. data/node_modules/jszip/dist/jszip.js +30 -0
  82. data/node_modules/jszip/dist/jszip.min.js +13 -0
  83. data/node_modules/jszip/index.d.ts +270 -0
  84. data/node_modules/jszip/lib/base64.js +106 -0
  85. data/node_modules/jszip/lib/compressedObject.js +74 -0
  86. data/node_modules/jszip/lib/compressions.js +14 -0
  87. data/node_modules/jszip/lib/crc32.js +77 -0
  88. data/node_modules/jszip/lib/defaults.js +11 -0
  89. data/node_modules/jszip/lib/external.js +19 -0
  90. data/node_modules/jszip/lib/flate.js +85 -0
  91. data/node_modules/jszip/lib/generate/ZipFileWorker.js +540 -0
  92. data/node_modules/jszip/lib/generate/index.js +57 -0
  93. data/node_modules/jszip/lib/index.js +52 -0
  94. data/node_modules/jszip/lib/license_header.js +11 -0
  95. data/node_modules/jszip/lib/load.js +81 -0
  96. data/node_modules/jszip/lib/nodejs/NodejsStreamInputAdapter.js +74 -0
  97. data/node_modules/jszip/lib/nodejs/NodejsStreamOutputAdapter.js +42 -0
  98. data/node_modules/jszip/lib/nodejsUtils.js +57 -0
  99. data/node_modules/jszip/lib/object.js +389 -0
  100. data/node_modules/jszip/lib/readable-stream-browser.js +9 -0
  101. data/node_modules/jszip/lib/reader/ArrayReader.js +57 -0
  102. data/node_modules/jszip/lib/reader/DataReader.js +116 -0
  103. data/node_modules/jszip/lib/reader/NodeBufferReader.js +19 -0
  104. data/node_modules/jszip/lib/reader/StringReader.js +38 -0
  105. data/node_modules/jszip/lib/reader/Uint8ArrayReader.js +22 -0
  106. data/node_modules/jszip/lib/reader/readerFor.js +28 -0
  107. data/node_modules/jszip/lib/signature.js +7 -0
  108. data/node_modules/jszip/lib/stream/ConvertWorker.js +26 -0
  109. data/node_modules/jszip/lib/stream/Crc32Probe.js +24 -0
  110. data/node_modules/jszip/lib/stream/DataLengthProbe.js +29 -0
  111. data/node_modules/jszip/lib/stream/DataWorker.js +116 -0
  112. data/node_modules/jszip/lib/stream/GenericWorker.js +263 -0
  113. data/node_modules/jszip/lib/stream/StreamHelper.js +212 -0
  114. data/node_modules/jszip/lib/support.js +38 -0
  115. data/node_modules/jszip/lib/utf8.js +275 -0
  116. data/node_modules/jszip/lib/utils.js +476 -0
  117. data/node_modules/jszip/lib/zipEntries.js +262 -0
  118. data/node_modules/jszip/lib/zipEntry.js +294 -0
  119. data/node_modules/jszip/lib/zipObject.js +133 -0
  120. data/node_modules/jszip/package.json +63 -0
  121. data/node_modules/jszip/vendor/FileSaver.js +247 -0
  122. data/node_modules/lie/README.md +62 -0
  123. data/node_modules/lie/dist/lie.js +350 -0
  124. data/node_modules/lie/dist/lie.min.js +1 -0
  125. data/node_modules/lie/dist/lie.polyfill.js +358 -0
  126. data/node_modules/lie/dist/lie.polyfill.min.js +1 -0
  127. data/node_modules/lie/lib/browser.js +273 -0
  128. data/node_modules/lie/lib/index.js +298 -0
  129. data/node_modules/lie/license.md +7 -0
  130. data/node_modules/lie/lie.d.ts +244 -0
  131. data/node_modules/lie/package.json +69 -0
  132. data/node_modules/lie/polyfill.js +4 -0
  133. data/node_modules/minimatch/LICENSE +15 -0
  134. data/node_modules/minimatch/README.md +209 -0
  135. data/node_modules/minimatch/minimatch.js +923 -0
  136. data/node_modules/minimatch/package.json +30 -0
  137. data/node_modules/once/LICENSE +15 -0
  138. data/node_modules/once/README.md +79 -0
  139. data/node_modules/once/once.js +42 -0
  140. data/node_modules/once/package.json +33 -0
  141. data/node_modules/pako/CHANGELOG.md +164 -0
  142. data/node_modules/pako/LICENSE +21 -0
  143. data/node_modules/pako/README.md +191 -0
  144. data/node_modules/pako/dist/pako.js +6818 -0
  145. data/node_modules/pako/dist/pako.min.js +1 -0
  146. data/node_modules/pako/dist/pako_deflate.js +3997 -0
  147. data/node_modules/pako/dist/pako_deflate.min.js +1 -0
  148. data/node_modules/pako/dist/pako_inflate.js +3300 -0
  149. data/node_modules/pako/dist/pako_inflate.min.js +1 -0
  150. data/node_modules/pako/index.js +14 -0
  151. data/node_modules/pako/lib/deflate.js +400 -0
  152. data/node_modules/pako/lib/inflate.js +423 -0
  153. data/node_modules/pako/lib/utils/common.js +105 -0
  154. data/node_modules/pako/lib/utils/strings.js +187 -0
  155. data/node_modules/pako/lib/zlib/README +59 -0
  156. data/node_modules/pako/lib/zlib/adler32.js +51 -0
  157. data/node_modules/pako/lib/zlib/constants.js +68 -0
  158. data/node_modules/pako/lib/zlib/crc32.js +59 -0
  159. data/node_modules/pako/lib/zlib/deflate.js +1874 -0
  160. data/node_modules/pako/lib/zlib/gzheader.js +58 -0
  161. data/node_modules/pako/lib/zlib/inffast.js +345 -0
  162. data/node_modules/pako/lib/zlib/inflate.js +1556 -0
  163. data/node_modules/pako/lib/zlib/inftrees.js +343 -0
  164. data/node_modules/pako/lib/zlib/messages.js +32 -0
  165. data/node_modules/pako/lib/zlib/trees.js +1222 -0
  166. data/node_modules/pako/lib/zlib/zstream.js +47 -0
  167. data/node_modules/pako/package.json +44 -0
  168. data/node_modules/path-is-absolute/index.js +20 -0
  169. data/node_modules/path-is-absolute/license +21 -0
  170. data/node_modules/path-is-absolute/package.json +43 -0
  171. data/node_modules/path-is-absolute/readme.md +59 -0
  172. data/node_modules/process-nextick-args/index.js +45 -0
  173. data/node_modules/process-nextick-args/license.md +19 -0
  174. data/node_modules/process-nextick-args/package.json +25 -0
  175. data/node_modules/process-nextick-args/readme.md +18 -0
  176. data/node_modules/readable-stream/.travis.yml +34 -0
  177. data/node_modules/readable-stream/CONTRIBUTING.md +38 -0
  178. data/node_modules/readable-stream/GOVERNANCE.md +136 -0
  179. data/node_modules/readable-stream/LICENSE +47 -0
  180. data/node_modules/readable-stream/README.md +58 -0
  181. data/node_modules/readable-stream/doc/wg-meetings/2015-01-30.md +60 -0
  182. data/node_modules/readable-stream/duplex-browser.js +1 -0
  183. data/node_modules/readable-stream/duplex.js +1 -0
  184. data/node_modules/readable-stream/lib/_stream_duplex.js +131 -0
  185. data/node_modules/readable-stream/lib/_stream_passthrough.js +47 -0
  186. data/node_modules/readable-stream/lib/_stream_readable.js +1019 -0
  187. data/node_modules/readable-stream/lib/_stream_transform.js +214 -0
  188. data/node_modules/readable-stream/lib/_stream_writable.js +687 -0
  189. data/node_modules/readable-stream/lib/internal/streams/BufferList.js +79 -0
  190. data/node_modules/readable-stream/lib/internal/streams/destroy.js +74 -0
  191. data/node_modules/readable-stream/lib/internal/streams/stream-browser.js +1 -0
  192. data/node_modules/readable-stream/lib/internal/streams/stream.js +1 -0
  193. data/node_modules/readable-stream/package.json +52 -0
  194. data/node_modules/readable-stream/passthrough.js +1 -0
  195. data/node_modules/readable-stream/readable-browser.js +7 -0
  196. data/node_modules/readable-stream/readable.js +19 -0
  197. data/node_modules/readable-stream/transform.js +1 -0
  198. data/node_modules/readable-stream/writable-browser.js +1 -0
  199. data/node_modules/readable-stream/writable.js +8 -0
  200. data/node_modules/rimraf/LICENSE +15 -0
  201. data/node_modules/rimraf/README.md +101 -0
  202. data/node_modules/rimraf/bin.js +50 -0
  203. data/node_modules/rimraf/package.json +29 -0
  204. data/node_modules/rimraf/rimraf.js +372 -0
  205. data/node_modules/safe-buffer/LICENSE +21 -0
  206. data/node_modules/safe-buffer/README.md +584 -0
  207. data/node_modules/safe-buffer/index.d.ts +187 -0
  208. data/node_modules/safe-buffer/index.js +62 -0
  209. data/node_modules/safe-buffer/package.json +37 -0
  210. data/node_modules/selenium-webdriver/CHANGES.md +1114 -0
  211. data/node_modules/selenium-webdriver/LICENSE +202 -0
  212. data/node_modules/selenium-webdriver/NOTICE +2 -0
  213. data/node_modules/selenium-webdriver/README.md +229 -0
  214. data/node_modules/selenium-webdriver/chrome.js +295 -0
  215. data/node_modules/selenium-webdriver/chromium.js +829 -0
  216. data/node_modules/selenium-webdriver/devtools/CDPConnection.js +35 -0
  217. data/node_modules/selenium-webdriver/edge.js +224 -0
  218. data/node_modules/selenium-webdriver/example/chrome_android.js +45 -0
  219. data/node_modules/selenium-webdriver/example/chrome_mobile_emulation.js +46 -0
  220. data/node_modules/selenium-webdriver/example/firefox_channels.js +84 -0
  221. data/node_modules/selenium-webdriver/example/google_search.js +50 -0
  222. data/node_modules/selenium-webdriver/example/google_search_test.js +70 -0
  223. data/node_modules/selenium-webdriver/example/headless.js +63 -0
  224. data/node_modules/selenium-webdriver/example/logging.js +64 -0
  225. data/node_modules/selenium-webdriver/firefox.js +789 -0
  226. data/node_modules/selenium-webdriver/http/index.js +324 -0
  227. data/node_modules/selenium-webdriver/http/util.js +172 -0
  228. data/node_modules/selenium-webdriver/ie.js +503 -0
  229. data/node_modules/selenium-webdriver/index.js +825 -0
  230. data/node_modules/selenium-webdriver/io/exec.js +162 -0
  231. data/node_modules/selenium-webdriver/io/index.js +348 -0
  232. data/node_modules/selenium-webdriver/io/zip.js +223 -0
  233. data/node_modules/selenium-webdriver/lib/atoms/find-elements.js +123 -0
  234. data/node_modules/selenium-webdriver/lib/atoms/get-attribute.js +101 -0
  235. data/node_modules/selenium-webdriver/lib/atoms/is-displayed.js +101 -0
  236. data/node_modules/selenium-webdriver/lib/atoms/mutation-listener.js +55 -0
  237. data/node_modules/selenium-webdriver/lib/by.js +415 -0
  238. data/node_modules/selenium-webdriver/lib/capabilities.js +553 -0
  239. data/node_modules/selenium-webdriver/lib/command.js +206 -0
  240. data/node_modules/selenium-webdriver/lib/error.js +605 -0
  241. data/node_modules/selenium-webdriver/lib/http.js +704 -0
  242. data/node_modules/selenium-webdriver/lib/input.js +946 -0
  243. data/node_modules/selenium-webdriver/lib/logging.js +661 -0
  244. data/node_modules/selenium-webdriver/lib/promise.js +285 -0
  245. data/node_modules/selenium-webdriver/lib/proxy.js +212 -0
  246. data/node_modules/selenium-webdriver/lib/session.js +77 -0
  247. data/node_modules/selenium-webdriver/lib/symbols.js +37 -0
  248. data/node_modules/selenium-webdriver/lib/until.js +429 -0
  249. data/node_modules/selenium-webdriver/lib/webdriver.js +2919 -0
  250. data/node_modules/selenium-webdriver/net/index.js +107 -0
  251. data/node_modules/selenium-webdriver/net/portprober.js +75 -0
  252. data/node_modules/selenium-webdriver/opera.js +406 -0
  253. data/node_modules/selenium-webdriver/package.json +54 -0
  254. data/node_modules/selenium-webdriver/proxy.js +32 -0
  255. data/node_modules/selenium-webdriver/remote/index.js +624 -0
  256. data/node_modules/selenium-webdriver/safari.js +168 -0
  257. data/node_modules/selenium-webdriver/testing/index.js +504 -0
  258. data/node_modules/set-immediate-shim/index.js +7 -0
  259. data/node_modules/set-immediate-shim/package.json +34 -0
  260. data/node_modules/set-immediate-shim/readme.md +31 -0
  261. data/node_modules/string_decoder/.travis.yml +50 -0
  262. data/node_modules/string_decoder/LICENSE +48 -0
  263. data/node_modules/string_decoder/README.md +47 -0
  264. data/node_modules/string_decoder/lib/string_decoder.js +296 -0
  265. data/node_modules/string_decoder/package.json +31 -0
  266. data/node_modules/tmp/CHANGELOG.md +288 -0
  267. data/node_modules/tmp/LICENSE +21 -0
  268. data/node_modules/tmp/README.md +365 -0
  269. data/node_modules/tmp/lib/tmp.js +780 -0
  270. data/node_modules/tmp/node_modules/.bin/rimraf +1 -0
  271. data/node_modules/tmp/node_modules/rimraf/CHANGELOG.md +65 -0
  272. data/node_modules/tmp/node_modules/rimraf/LICENSE +15 -0
  273. data/node_modules/tmp/node_modules/rimraf/README.md +101 -0
  274. data/node_modules/tmp/node_modules/rimraf/bin.js +68 -0
  275. data/node_modules/tmp/node_modules/rimraf/package.json +32 -0
  276. data/node_modules/tmp/node_modules/rimraf/rimraf.js +360 -0
  277. data/node_modules/tmp/package.json +58 -0
  278. data/node_modules/util-deprecate/History.md +16 -0
  279. data/node_modules/util-deprecate/LICENSE +24 -0
  280. data/node_modules/util-deprecate/README.md +53 -0
  281. data/node_modules/util-deprecate/browser.js +67 -0
  282. data/node_modules/util-deprecate/node.js +6 -0
  283. data/node_modules/util-deprecate/package.json +27 -0
  284. data/node_modules/wrappy/LICENSE +15 -0
  285. data/node_modules/wrappy/README.md +36 -0
  286. data/node_modules/wrappy/package.json +29 -0
  287. data/node_modules/wrappy/wrappy.js +33 -0
  288. data/node_modules/ws/LICENSE +21 -0
  289. data/node_modules/ws/README.md +496 -0
  290. data/node_modules/ws/browser.js +8 -0
  291. data/node_modules/ws/index.js +10 -0
  292. data/node_modules/ws/lib/buffer-util.js +129 -0
  293. data/node_modules/ws/lib/constants.js +10 -0
  294. data/node_modules/ws/lib/event-target.js +184 -0
  295. data/node_modules/ws/lib/extension.js +223 -0
  296. data/node_modules/ws/lib/limiter.js +55 -0
  297. data/node_modules/ws/lib/permessage-deflate.js +517 -0
  298. data/node_modules/ws/lib/receiver.js +507 -0
  299. data/node_modules/ws/lib/sender.js +405 -0
  300. data/node_modules/ws/lib/stream.js +165 -0
  301. data/node_modules/ws/lib/validation.js +104 -0
  302. data/node_modules/ws/lib/websocket-server.js +418 -0
  303. data/node_modules/ws/lib/websocket.js +942 -0
  304. data/node_modules/ws/package.json +56 -0
  305. data/package-lock.json +458 -0
  306. data/package.json +5 -0
  307. data/selenium.log +1 -0
  308. metadata +314 -19
@@ -0,0 +1,946 @@
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
+ }