selenium-webdriver 2.48.2 → 2.53.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (534) hide show
  1. package/CHANGES.md +116 -0
  2. package/NOTICE +1 -1
  3. package/README.md +59 -9
  4. package/builder.js +375 -358
  5. package/chrome.js +549 -586
  6. package/edge.js +378 -0
  7. package/error.js +9 -6
  8. package/example/google_search.js +1 -1
  9. package/example/google_search_generator.js +2 -4
  10. package/example/logging.js +6 -2
  11. package/example/sample.js +21 -0
  12. package/executors.js +11 -27
  13. package/firefox/binary.js +149 -98
  14. package/firefox/extension.js +15 -19
  15. package/firefox/index.js +256 -163
  16. package/firefox/profile.js +223 -243
  17. package/http/index.js +487 -81
  18. package/http/util.js +40 -36
  19. package/ie.js +288 -309
  20. package/index.js +34 -125
  21. package/io/exec.js +58 -39
  22. package/io/index.js +72 -60
  23. package/lib/README +4 -0
  24. package/lib/actions.js +596 -0
  25. package/lib/by.js +277 -0
  26. package/lib/capabilities.js +450 -0
  27. package/lib/{webdriver/command.js → command.js} +91 -72
  28. package/lib/{webdriver/button.js → devmode.js} +13 -8
  29. package/lib/error.js +690 -0
  30. package/lib/events.js +212 -0
  31. package/lib/firefox/amd64/libnoblur64.so +0 -0
  32. package/lib/firefox/i386/libnoblur.so +0 -0
  33. package/lib/firefox/webdriver.json +5 -1
  34. package/lib/firefox/webdriver.xpi +0 -0
  35. package/lib/{webdriver/key.js → input.js} +84 -2
  36. package/lib/logging.js +670 -0
  37. package/lib/{webdriver/promise.js → promise.js} +817 -644
  38. package/lib/safari/client.js +266 -214
  39. package/lib/session.js +80 -0
  40. package/lib/{webdriver/serializable.js → symbols.js} +16 -19
  41. package/lib/test/build.js +4 -4
  42. package/lib/test/data/click_tests/html5_submit_buttons.html +2 -1
  43. package/lib/test/data/click_tests/overlapping_elements.html +15 -4
  44. package/lib/test/data/click_tests/partially_overlapping_elements.html +124 -0
  45. package/lib/test/data/click_tests/wrapped_overlapping_elements.html +13 -0
  46. package/lib/test/data/hidden_partially.html +45 -0
  47. package/lib/test/data/readOnlyPage.html +1 -1
  48. package/lib/test/data/selectPage.html +18 -2
  49. package/lib/test/fileserver.js +3 -4
  50. package/lib/test/index.js +7 -3
  51. package/lib/test/resources.js +1 -1
  52. package/lib/until.js +376 -0
  53. package/lib/webdriver.js +2440 -0
  54. package/net/index.js +4 -0
  55. package/net/portprober.js +16 -12
  56. package/opera.js +295 -314
  57. package/package.json +6 -5
  58. package/phantomjs.js +144 -147
  59. package/proxy.js +10 -6
  60. package/remote/index.js +289 -238
  61. package/safari.js +326 -311
  62. package/test/chrome/options_test.js +11 -9
  63. package/test/element_finding_test.js +51 -13
  64. package/test/execute_script_test.js +17 -3
  65. package/test/firefox/firefox_test.js +0 -32
  66. package/test/http/http_test.js +671 -61
  67. package/test/http/util_test.js +25 -23
  68. package/test/io_test.js +67 -1
  69. package/test/lib/by_test.js +139 -0
  70. package/test/lib/capabilities_test.js +111 -0
  71. package/test/lib/error_test.js +325 -0
  72. package/test/lib/events_test.js +177 -0
  73. package/test/lib/logging_test.js +272 -0
  74. package/test/{promise_aplus_test.js → lib/promise_aplus_test.js} +4 -13
  75. package/test/lib/promise_error_test.js +808 -0
  76. package/test/lib/promise_flow_test.js +2282 -0
  77. package/test/lib/promise_generator_test.js +308 -0
  78. package/test/lib/promise_test.js +996 -0
  79. package/test/lib/testutil.js +90 -0
  80. package/test/lib/until_test.js +400 -0
  81. package/test/lib/webdriver_test.js +2157 -0
  82. package/test/page_loading_test.js +7 -9
  83. package/test/remote_test.js +50 -3
  84. package/test/session_test.js +53 -0
  85. package/test/stale_element_test.js +2 -2
  86. package/test/testing/assert_test.js +374 -0
  87. package/test/testing/index_test.js +9 -11
  88. package/testing/assert.js +334 -17
  89. package/testing/index.js +12 -2
  90. package/_base.js +0 -200
  91. package/docs/Changes.html +0 -356
  92. package/docs/class_bot_Error.html +0 -15
  93. package/docs/class_webdriver_ActionSequence.html +0 -115
  94. package/docs/class_webdriver_Alert.html +0 -24
  95. package/docs/class_webdriver_AlertPromise.html +0 -92
  96. package/docs/class_webdriver_Capabilities.html +0 -60
  97. package/docs/class_webdriver_Command.html +0 -15
  98. package/docs/class_webdriver_EventEmitter.html +0 -35
  99. package/docs/class_webdriver_FileDetector.html +0 -21
  100. package/docs/class_webdriver_Locator.html +0 -12
  101. package/docs/class_webdriver_Serializable.html +0 -9
  102. package/docs/class_webdriver_Session.html +0 -13
  103. package/docs/class_webdriver_TouchSequence.html +0 -49
  104. package/docs/class_webdriver_UnhandledAlertError.html +0 -18
  105. package/docs/class_webdriver_WebDriver.html +0 -313
  106. package/docs/class_webdriver_WebDriver_Logs.html +0 -15
  107. package/docs/class_webdriver_WebDriver_Navigation.html +0 -16
  108. package/docs/class_webdriver_WebDriver_Options.html +0 -41
  109. package/docs/class_webdriver_WebDriver_TargetLocator.html +0 -38
  110. package/docs/class_webdriver_WebDriver_Timeouts.html +0 -29
  111. package/docs/class_webdriver_WebDriver_Window.html +0 -27
  112. package/docs/class_webdriver_WebElement.html +0 -223
  113. package/docs/class_webdriver_WebElementPromise.html +0 -274
  114. package/docs/class_webdriver_http_Executor.html +0 -22
  115. package/docs/class_webdriver_http_Request.html +0 -12
  116. package/docs/class_webdriver_http_Response.html +0 -13
  117. package/docs/class_webdriver_logging_Entry.html +0 -15
  118. package/docs/class_webdriver_logging_Level.html +0 -55
  119. package/docs/class_webdriver_logging_LogRecord.html +0 -45
  120. package/docs/class_webdriver_logging_Logger.html +0 -119
  121. package/docs/class_webdriver_logging_Preferences.html +0 -8
  122. package/docs/class_webdriver_promise_CancellationError.html +0 -17
  123. package/docs/class_webdriver_promise_ControlFlow.html +0 -153
  124. package/docs/class_webdriver_promise_Deferred.html +0 -84
  125. package/docs/class_webdriver_promise_MultipleUnhandledRejectionError.html +0 -14
  126. package/docs/class_webdriver_promise_Promise.html +0 -75
  127. package/docs/class_webdriver_stacktrace_Frame.html +0 -20
  128. package/docs/class_webdriver_stacktrace_Snapshot.html +0 -6
  129. package/docs/class_webdriver_testing_Assertion.html +0 -99
  130. package/docs/class_webdriver_testing_Assertion_DelegatingMatcher_.html +0 -13
  131. package/docs/class_webdriver_testing_ContainsMatcher.html +0 -11
  132. package/docs/class_webdriver_testing_NegatedAssertion.html +0 -97
  133. package/docs/class_webdriver_until_Condition.html +0 -7
  134. package/docs/dossier.css +0 -1
  135. package/docs/dossier.js +0 -86
  136. package/docs/enum_bot_ErrorCode.html +0 -3
  137. package/docs/enum_bot_Error_State.html +0 -2
  138. package/docs/enum_webdriver_Browser.html +0 -2
  139. package/docs/enum_webdriver_Button.html +0 -2
  140. package/docs/enum_webdriver_Capability.html +0 -33
  141. package/docs/enum_webdriver_CommandName.html +0 -3
  142. package/docs/enum_webdriver_Key.html +0 -12
  143. package/docs/enum_webdriver_logging_Type.html +0 -6
  144. package/docs/enum_webdriver_promise_ControlFlow_EventType.html +0 -9
  145. package/docs/index.html +0 -125
  146. package/docs/interface_webdriver_CommandExecutor.html +0 -9
  147. package/docs/interface_webdriver_http_Client.html +0 -10
  148. package/docs/interface_webdriver_promise_Thenable.html +0 -77
  149. package/docs/module_selenium-webdriver.html +0 -23
  150. package/docs/module_selenium-webdriver__base.html +0 -23
  151. package/docs/module_selenium-webdriver__base_class_Context.html +0 -5
  152. package/docs/module_selenium-webdriver_builder.html +0 -2
  153. package/docs/module_selenium-webdriver_builder_class_Builder.html +0 -138
  154. package/docs/module_selenium-webdriver_chrome.html +0 -90
  155. package/docs/module_selenium-webdriver_chrome_class_Driver.html +0 -280
  156. package/docs/module_selenium-webdriver_chrome_class_Options.html +0 -127
  157. package/docs/module_selenium-webdriver_chrome_class_ServiceBuilder.html +0 -46
  158. package/docs/module_selenium-webdriver_class_ActionSequence.html +0 -115
  159. package/docs/module_selenium-webdriver_class_Builder.html +0 -138
  160. package/docs/module_selenium-webdriver_class_Capabilities.html +0 -60
  161. package/docs/module_selenium-webdriver_class_Command.html +0 -15
  162. package/docs/module_selenium-webdriver_class_EventEmitter.html +0 -35
  163. package/docs/module_selenium-webdriver_class_FileDetector.html +0 -21
  164. package/docs/module_selenium-webdriver_class_Serializable.html +0 -9
  165. package/docs/module_selenium-webdriver_class_Session.html +0 -13
  166. package/docs/module_selenium-webdriver_class_WebDriver.html +0 -313
  167. package/docs/module_selenium-webdriver_class_WebElement.html +0 -223
  168. package/docs/module_selenium-webdriver_class_WebElementPromise.html +0 -274
  169. package/docs/module_selenium-webdriver_enum_Browser.html +0 -2
  170. package/docs/module_selenium-webdriver_enum_Button.html +0 -2
  171. package/docs/module_selenium-webdriver_enum_Capability.html +0 -33
  172. package/docs/module_selenium-webdriver_enum_CommandName.html +0 -3
  173. package/docs/module_selenium-webdriver_enum_Key.html +0 -12
  174. package/docs/module_selenium-webdriver_error.html +0 -4
  175. package/docs/module_selenium-webdriver_error_class_Error.html +0 -15
  176. package/docs/module_selenium-webdriver_error_enum_ErrorCode.html +0 -3
  177. package/docs/module_selenium-webdriver_executors.html +0 -10
  178. package/docs/module_selenium-webdriver_executors_class_DeferredExecutor.html +0 -12
  179. package/docs/module_selenium-webdriver_firefox.html +0 -68
  180. package/docs/module_selenium-webdriver_firefox_binary.html +0 -5
  181. package/docs/module_selenium-webdriver_firefox_binary_class_Binary.html +0 -20
  182. package/docs/module_selenium-webdriver_firefox_class_Binary.html +0 -20
  183. package/docs/module_selenium-webdriver_firefox_class_Driver.html +0 -276
  184. package/docs/module_selenium-webdriver_firefox_class_Options.html +0 -19
  185. package/docs/module_selenium-webdriver_firefox_class_Profile.html +0 -50
  186. package/docs/module_selenium-webdriver_firefox_extension.html +0 -8
  187. package/docs/module_selenium-webdriver_firefox_profile.html +0 -13
  188. package/docs/module_selenium-webdriver_firefox_profile_class_Profile.html +0 -50
  189. package/docs/module_selenium-webdriver_http.html +0 -9
  190. package/docs/module_selenium-webdriver_http_class_Executor.html +0 -22
  191. package/docs/module_selenium-webdriver_http_class_HttpClient.html +0 -16
  192. package/docs/module_selenium-webdriver_http_class_Request.html +0 -12
  193. package/docs/module_selenium-webdriver_http_class_Response.html +0 -13
  194. package/docs/module_selenium-webdriver_http_util.html +0 -17
  195. package/docs/module_selenium-webdriver_ie.html +0 -11
  196. package/docs/module_selenium-webdriver_ie_class_Driver.html +0 -274
  197. package/docs/module_selenium-webdriver_ie_class_Options.html +0 -89
  198. package/docs/module_selenium-webdriver_ie_enum_Level.html +0 -1
  199. package/docs/module_selenium-webdriver_io.html +0 -37
  200. package/docs/module_selenium-webdriver_io_exec.html +0 -6
  201. package/docs/module_selenium-webdriver_namespace_By.html +0 -56
  202. package/docs/module_selenium-webdriver_namespace_error.html +0 -4
  203. package/docs/module_selenium-webdriver_namespace_logging.html +0 -18
  204. package/docs/module_selenium-webdriver_namespace_promise.html +0 -163
  205. package/docs/module_selenium-webdriver_namespace_stacktrace.html +0 -17
  206. package/docs/module_selenium-webdriver_namespace_until.html +0 -82
  207. package/docs/module_selenium-webdriver_net.html +0 -7
  208. package/docs/module_selenium-webdriver_net_portprober.html +0 -12
  209. package/docs/module_selenium-webdriver_opera.html +0 -62
  210. package/docs/module_selenium-webdriver_opera_class_Driver.html +0 -276
  211. package/docs/module_selenium-webdriver_opera_class_Options.html +0 -44
  212. package/docs/module_selenium-webdriver_opera_class_ServiceBuilder.html +0 -35
  213. package/docs/module_selenium-webdriver_phantomjs.html +0 -2
  214. package/docs/module_selenium-webdriver_phantomjs_class_Driver.html +0 -299
  215. package/docs/module_selenium-webdriver_proxy.html +0 -28
  216. package/docs/module_selenium-webdriver_remote.html +0 -8
  217. package/docs/module_selenium-webdriver_remote_class_DriverService.html +0 -32
  218. package/docs/module_selenium-webdriver_remote_class_FileDetector.html +0 -22
  219. package/docs/module_selenium-webdriver_remote_class_SeleniumServer.html +0 -41
  220. package/docs/module_selenium-webdriver_safari.html +0 -9
  221. package/docs/module_selenium-webdriver_safari_class_Driver.html +0 -279
  222. package/docs/module_selenium-webdriver_safari_class_Options.html +0 -23
  223. package/docs/module_selenium-webdriver_testing.html +0 -74
  224. package/docs/module_selenium-webdriver_testing_assert.html +0 -9
  225. package/docs/namespace_bot.html +0 -4
  226. package/docs/namespace_bot_json.html +0 -20
  227. package/docs/namespace_bot_response.html +0 -18
  228. package/docs/namespace_bot_userAgent.html +0 -33
  229. package/docs/namespace_webdriver.html +0 -30
  230. package/docs/namespace_webdriver_By.html +0 -56
  231. package/docs/namespace_webdriver_http.html +0 -6
  232. package/docs/namespace_webdriver_logging.html +0 -70
  233. package/docs/namespace_webdriver_promise.html +0 -688
  234. package/docs/namespace_webdriver_stacktrace.html +0 -17
  235. package/docs/namespace_webdriver_testing.html +0 -7
  236. package/docs/namespace_webdriver_testing_assert.html +0 -9
  237. package/docs/namespace_webdriver_testing_asserts.html +0 -18
  238. package/docs/namespace_webdriver_until.html +0 -82
  239. package/docs/source/_base.js.src.html +0 -1
  240. package/docs/source/builder.js.src.html +0 -1
  241. package/docs/source/chrome.js.src.html +0 -1
  242. package/docs/source/error.js.src.html +0 -1
  243. package/docs/source/executors.js.src.html +0 -1
  244. package/docs/source/firefox/binary.js.src.html +0 -1
  245. package/docs/source/firefox/extension.js.src.html +0 -1
  246. package/docs/source/firefox/index.js.src.html +0 -1
  247. package/docs/source/firefox/profile.js.src.html +0 -1
  248. package/docs/source/http/index.js.src.html +0 -1
  249. package/docs/source/http/util.js.src.html +0 -1
  250. package/docs/source/ie.js.src.html +0 -1
  251. package/docs/source/index.js.src.html +0 -1
  252. package/docs/source/io/exec.js.src.html +0 -1
  253. package/docs/source/io/index.js.src.html +0 -1
  254. package/docs/source/lib/atoms/error.js.src.html +0 -1
  255. package/docs/source/lib/atoms/json.js.src.html +0 -1
  256. package/docs/source/lib/atoms/response.js.src.html +0 -1
  257. package/docs/source/lib/atoms/userAgent.js.src.html +0 -1
  258. package/docs/source/lib/goog/array/array.js.src.html +0 -1
  259. package/docs/source/lib/goog/asserts/asserts.js.src.html +0 -1
  260. package/docs/source/lib/goog/async/freelist.js.src.html +0 -1
  261. package/docs/source/lib/goog/async/nexttick.js.src.html +0 -1
  262. package/docs/source/lib/goog/async/run.js.src.html +0 -1
  263. package/docs/source/lib/goog/async/workqueue.js.src.html +0 -1
  264. package/docs/source/lib/goog/base.js.src.html +0 -1
  265. package/docs/source/lib/goog/debug/debug.js.src.html +0 -1
  266. package/docs/source/lib/goog/debug/entrypointregistry.js.src.html +0 -1
  267. package/docs/source/lib/goog/debug/error.js.src.html +0 -1
  268. package/docs/source/lib/goog/debug/logbuffer.js.src.html +0 -1
  269. package/docs/source/lib/goog/debug/logger.js.src.html +0 -1
  270. package/docs/source/lib/goog/debug/logrecord.js.src.html +0 -1
  271. package/docs/source/lib/goog/deps.js.src.html +0 -1
  272. package/docs/source/lib/goog/disposable/disposable.js.src.html +0 -1
  273. package/docs/source/lib/goog/disposable/idisposable.js.src.html +0 -1
  274. package/docs/source/lib/goog/dom/browserfeature.js.src.html +0 -1
  275. package/docs/source/lib/goog/dom/dom.js.src.html +0 -1
  276. package/docs/source/lib/goog/dom/nodetype.js.src.html +0 -1
  277. package/docs/source/lib/goog/dom/safe.js.src.html +0 -1
  278. package/docs/source/lib/goog/dom/tagname.js.src.html +0 -1
  279. package/docs/source/lib/goog/dom/tags.js.src.html +0 -1
  280. package/docs/source/lib/goog/dom/vendor.js.src.html +0 -1
  281. package/docs/source/lib/goog/events/browserevent.js.src.html +0 -1
  282. package/docs/source/lib/goog/events/browserfeature.js.src.html +0 -1
  283. package/docs/source/lib/goog/events/event.js.src.html +0 -1
  284. package/docs/source/lib/goog/events/eventid.js.src.html +0 -1
  285. package/docs/source/lib/goog/events/events.js.src.html +0 -1
  286. package/docs/source/lib/goog/events/eventtarget.js.src.html +0 -1
  287. package/docs/source/lib/goog/events/eventtype.js.src.html +0 -1
  288. package/docs/source/lib/goog/events/keycodes.js.src.html +0 -1
  289. package/docs/source/lib/goog/events/listenable.js.src.html +0 -1
  290. package/docs/source/lib/goog/events/listener.js.src.html +0 -1
  291. package/docs/source/lib/goog/events/listenermap.js.src.html +0 -1
  292. package/docs/source/lib/goog/fs/url.js.src.html +0 -1
  293. package/docs/source/lib/goog/functions/functions.js.src.html +0 -1
  294. package/docs/source/lib/goog/html/safehtml.js.src.html +0 -1
  295. package/docs/source/lib/goog/html/safescript.js.src.html +0 -1
  296. package/docs/source/lib/goog/html/safestyle.js.src.html +0 -1
  297. package/docs/source/lib/goog/html/safestylesheet.js.src.html +0 -1
  298. package/docs/source/lib/goog/html/safeurl.js.src.html +0 -1
  299. package/docs/source/lib/goog/html/trustedresourceurl.js.src.html +0 -1
  300. package/docs/source/lib/goog/html/uncheckedconversions.js.src.html +0 -1
  301. package/docs/source/lib/goog/i18n/bidi.js.src.html +0 -1
  302. package/docs/source/lib/goog/iter/iter.js.src.html +0 -1
  303. package/docs/source/lib/goog/json/json.js.src.html +0 -1
  304. package/docs/source/lib/goog/labs/testing/assertthat.js.src.html +0 -1
  305. package/docs/source/lib/goog/labs/testing/logicmatcher.js.src.html +0 -1
  306. package/docs/source/lib/goog/labs/testing/matcher.js.src.html +0 -1
  307. package/docs/source/lib/goog/labs/testing/numbermatcher.js.src.html +0 -1
  308. package/docs/source/lib/goog/labs/testing/objectmatcher.js.src.html +0 -1
  309. package/docs/source/lib/goog/labs/testing/stringmatcher.js.src.html +0 -1
  310. package/docs/source/lib/goog/labs/useragent/browser.js.src.html +0 -1
  311. package/docs/source/lib/goog/labs/useragent/engine.js.src.html +0 -1
  312. package/docs/source/lib/goog/labs/useragent/platform.js.src.html +0 -1
  313. package/docs/source/lib/goog/labs/useragent/util.js.src.html +0 -1
  314. package/docs/source/lib/goog/log/log.js.src.html +0 -1
  315. package/docs/source/lib/goog/math/box.js.src.html +0 -1
  316. package/docs/source/lib/goog/math/coordinate.js.src.html +0 -1
  317. package/docs/source/lib/goog/math/math.js.src.html +0 -1
  318. package/docs/source/lib/goog/math/rect.js.src.html +0 -1
  319. package/docs/source/lib/goog/math/size.js.src.html +0 -1
  320. package/docs/source/lib/goog/net/wrapperxmlhttpfactory.js.src.html +0 -1
  321. package/docs/source/lib/goog/net/xhrlike.js.src.html +0 -1
  322. package/docs/source/lib/goog/net/xmlhttp.js.src.html +0 -1
  323. package/docs/source/lib/goog/net/xmlhttpfactory.js.src.html +0 -1
  324. package/docs/source/lib/goog/object/object.js.src.html +0 -1
  325. package/docs/source/lib/goog/promise/promise.js.src.html +0 -1
  326. package/docs/source/lib/goog/promise/resolver.js.src.html +0 -1
  327. package/docs/source/lib/goog/promise/thenable.js.src.html +0 -1
  328. package/docs/source/lib/goog/reflect/reflect.js.src.html +0 -1
  329. package/docs/source/lib/goog/string/const.js.src.html +0 -1
  330. package/docs/source/lib/goog/string/string.js.src.html +0 -1
  331. package/docs/source/lib/goog/string/typedstring.js.src.html +0 -1
  332. package/docs/source/lib/goog/structs/collection.js.src.html +0 -1
  333. package/docs/source/lib/goog/structs/map.js.src.html +0 -1
  334. package/docs/source/lib/goog/structs/set.js.src.html +0 -1
  335. package/docs/source/lib/goog/structs/structs.js.src.html +0 -1
  336. package/docs/source/lib/goog/style/style.js.src.html +0 -1
  337. package/docs/source/lib/goog/testing/asserts.js.src.html +0 -1
  338. package/docs/source/lib/goog/testing/events/events.js.src.html +0 -1
  339. package/docs/source/lib/goog/testing/functionmock.js.src.html +0 -1
  340. package/docs/source/lib/goog/testing/jsunit.js.src.html +0 -1
  341. package/docs/source/lib/goog/testing/loosemock.js.src.html +0 -1
  342. package/docs/source/lib/goog/testing/mock.js.src.html +0 -1
  343. package/docs/source/lib/goog/testing/mockclock.js.src.html +0 -1
  344. package/docs/source/lib/goog/testing/mockcontrol.js.src.html +0 -1
  345. package/docs/source/lib/goog/testing/mockinterface.js.src.html +0 -1
  346. package/docs/source/lib/goog/testing/mockmatchers.js.src.html +0 -1
  347. package/docs/source/lib/goog/testing/objectpropertystring.js.src.html +0 -1
  348. package/docs/source/lib/goog/testing/propertyreplacer.js.src.html +0 -1
  349. package/docs/source/lib/goog/testing/recordfunction.js.src.html +0 -1
  350. package/docs/source/lib/goog/testing/stacktrace.js.src.html +0 -1
  351. package/docs/source/lib/goog/testing/strictmock.js.src.html +0 -1
  352. package/docs/source/lib/goog/testing/testcase.js.src.html +0 -1
  353. package/docs/source/lib/goog/testing/testrunner.js.src.html +0 -1
  354. package/docs/source/lib/goog/uri/uri.js.src.html +0 -1
  355. package/docs/source/lib/goog/uri/utils.js.src.html +0 -1
  356. package/docs/source/lib/goog/useragent/product.js.src.html +0 -1
  357. package/docs/source/lib/goog/useragent/product_isversion.js.src.html +0 -1
  358. package/docs/source/lib/goog/useragent/useragent.js.src.html +0 -1
  359. package/docs/source/lib/webdriver/actionsequence.js.src.html +0 -1
  360. package/docs/source/lib/webdriver/button.js.src.html +0 -1
  361. package/docs/source/lib/webdriver/capabilities.js.src.html +0 -1
  362. package/docs/source/lib/webdriver/command.js.src.html +0 -1
  363. package/docs/source/lib/webdriver/events.js.src.html +0 -1
  364. package/docs/source/lib/webdriver/http/http.js.src.html +0 -1
  365. package/docs/source/lib/webdriver/key.js.src.html +0 -1
  366. package/docs/source/lib/webdriver/locators.js.src.html +0 -1
  367. package/docs/source/lib/webdriver/logging.js.src.html +0 -1
  368. package/docs/source/lib/webdriver/promise.js.src.html +0 -1
  369. package/docs/source/lib/webdriver/serializable.js.src.html +0 -1
  370. package/docs/source/lib/webdriver/session.js.src.html +0 -1
  371. package/docs/source/lib/webdriver/stacktrace.js.src.html +0 -1
  372. package/docs/source/lib/webdriver/testing/asserts.js.src.html +0 -1
  373. package/docs/source/lib/webdriver/touchsequence.js.src.html +0 -1
  374. package/docs/source/lib/webdriver/until.js.src.html +0 -1
  375. package/docs/source/lib/webdriver/webdriver.js.src.html +0 -1
  376. package/docs/source/net/index.js.src.html +0 -1
  377. package/docs/source/net/portprober.js.src.html +0 -1
  378. package/docs/source/opera.js.src.html +0 -1
  379. package/docs/source/phantomjs.js.src.html +0 -1
  380. package/docs/source/proxy.js.src.html +0 -1
  381. package/docs/source/remote/index.js.src.html +0 -1
  382. package/docs/source/safari.js.src.html +0 -1
  383. package/docs/source/testing/assert.js.src.html +0 -1
  384. package/docs/source/testing/index.js.src.html +0 -1
  385. package/docs/types.js +0 -1
  386. package/lib/atoms/error.js +0 -202
  387. package/lib/atoms/json.js +0 -80
  388. package/lib/atoms/response.js +0 -110
  389. package/lib/atoms/userAgent.js +0 -257
  390. package/lib/goog/LICENSE +0 -176
  391. package/lib/goog/array/array.js +0 -1654
  392. package/lib/goog/asserts/asserts.js +0 -365
  393. package/lib/goog/async/freelist.js +0 -88
  394. package/lib/goog/async/nexttick.js +0 -241
  395. package/lib/goog/async/run.js +0 -133
  396. package/lib/goog/async/workqueue.js +0 -139
  397. package/lib/goog/base.js +0 -2548
  398. package/lib/goog/debug/debug.js +0 -653
  399. package/lib/goog/debug/entrypointregistry.js +0 -158
  400. package/lib/goog/debug/error.js +0 -63
  401. package/lib/goog/debug/logbuffer.js +0 -148
  402. package/lib/goog/debug/logger.js +0 -873
  403. package/lib/goog/debug/logrecord.js +0 -242
  404. package/lib/goog/deps.js +0 -151
  405. package/lib/goog/disposable/disposable.js +0 -307
  406. package/lib/goog/disposable/idisposable.js +0 -45
  407. package/lib/goog/dom/browserfeature.js +0 -72
  408. package/lib/goog/dom/dom.js +0 -2991
  409. package/lib/goog/dom/nodetype.js +0 -48
  410. package/lib/goog/dom/safe.js +0 -347
  411. package/lib/goog/dom/tagname.js +0 -160
  412. package/lib/goog/dom/tags.js +0 -41
  413. package/lib/goog/dom/vendor.js +0 -96
  414. package/lib/goog/events/browserevent.js +0 -400
  415. package/lib/goog/events/browserfeature.js +0 -85
  416. package/lib/goog/events/event.js +0 -143
  417. package/lib/goog/events/eventid.js +0 -47
  418. package/lib/goog/events/events.js +0 -984
  419. package/lib/goog/events/eventtarget.js +0 -394
  420. package/lib/goog/events/eventtype.js +0 -237
  421. package/lib/goog/events/keycodes.js +0 -427
  422. package/lib/goog/events/listenable.js +0 -335
  423. package/lib/goog/events/listener.js +0 -131
  424. package/lib/goog/events/listenermap.js +0 -308
  425. package/lib/goog/fs/url.js +0 -109
  426. package/lib/goog/functions/functions.js +0 -442
  427. package/lib/goog/html/safehtml.js +0 -757
  428. package/lib/goog/html/safescript.js +0 -234
  429. package/lib/goog/html/safestyle.js +0 -442
  430. package/lib/goog/html/safestylesheet.js +0 -276
  431. package/lib/goog/html/safeurl.js +0 -398
  432. package/lib/goog/html/trustedresourceurl.js +0 -224
  433. package/lib/goog/html/uncheckedconversions.js +0 -232
  434. package/lib/goog/i18n/bidi.js +0 -908
  435. package/lib/goog/iter/iter.js +0 -1302
  436. package/lib/goog/json/json.js +0 -363
  437. package/lib/goog/labs/testing/assertthat.js +0 -58
  438. package/lib/goog/labs/testing/logicmatcher.js +0 -212
  439. package/lib/goog/labs/testing/matcher.js +0 -80
  440. package/lib/goog/labs/testing/numbermatcher.js +0 -346
  441. package/lib/goog/labs/testing/objectmatcher.js +0 -317
  442. package/lib/goog/labs/testing/stringmatcher.js +0 -415
  443. package/lib/goog/labs/useragent/browser.js +0 -341
  444. package/lib/goog/labs/useragent/engine.js +0 -160
  445. package/lib/goog/labs/useragent/platform.js +0 -160
  446. package/lib/goog/labs/useragent/util.js +0 -148
  447. package/lib/goog/log/log.js +0 -197
  448. package/lib/goog/math/box.js +0 -398
  449. package/lib/goog/math/coordinate.js +0 -268
  450. package/lib/goog/math/math.js +0 -451
  451. package/lib/goog/math/rect.js +0 -476
  452. package/lib/goog/math/size.js +0 -227
  453. package/lib/goog/net/wrapperxmlhttpfactory.js +0 -71
  454. package/lib/goog/net/xhrlike.js +0 -124
  455. package/lib/goog/net/xmlhttp.js +0 -246
  456. package/lib/goog/net/xmlhttpfactory.js +0 -67
  457. package/lib/goog/object/object.js +0 -686
  458. package/lib/goog/promise/promise.js +0 -1350
  459. package/lib/goog/promise/resolver.js +0 -48
  460. package/lib/goog/promise/thenable.js +0 -126
  461. package/lib/goog/reflect/reflect.js +0 -77
  462. package/lib/goog/string/const.js +0 -182
  463. package/lib/goog/string/string.js +0 -1599
  464. package/lib/goog/string/typedstring.js +0 -48
  465. package/lib/goog/structs/collection.js +0 -56
  466. package/lib/goog/structs/map.js +0 -457
  467. package/lib/goog/structs/set.js +0 -279
  468. package/lib/goog/structs/structs.js +0 -354
  469. package/lib/goog/style/style.js +0 -2037
  470. package/lib/goog/testing/asserts.js +0 -1278
  471. package/lib/goog/testing/events/events.js +0 -767
  472. package/lib/goog/testing/functionmock.js +0 -175
  473. package/lib/goog/testing/jsunit.js +0 -162
  474. package/lib/goog/testing/loosemock.js +0 -242
  475. package/lib/goog/testing/mock.js +0 -645
  476. package/lib/goog/testing/mockclock.js +0 -606
  477. package/lib/goog/testing/mockcontrol.js +0 -220
  478. package/lib/goog/testing/mockinterface.js +0 -45
  479. package/lib/goog/testing/mockmatchers.js +0 -400
  480. package/lib/goog/testing/objectpropertystring.js +0 -68
  481. package/lib/goog/testing/propertyreplacer.js +0 -262
  482. package/lib/goog/testing/recordfunction.js +0 -215
  483. package/lib/goog/testing/stacktrace.js +0 -594
  484. package/lib/goog/testing/strictmock.js +0 -130
  485. package/lib/goog/testing/testcase.js +0 -1629
  486. package/lib/goog/testing/testrunner.js +0 -440
  487. package/lib/goog/uri/uri.js +0 -1524
  488. package/lib/goog/uri/utils.js +0 -1064
  489. package/lib/goog/useragent/product.js +0 -183
  490. package/lib/goog/useragent/product_isversion.js +0 -144
  491. package/lib/goog/useragent/useragent.js +0 -572
  492. package/lib/webdriver/actionsequence.js +0 -356
  493. package/lib/webdriver/builder.js +0 -207
  494. package/lib/webdriver/capabilities.js +0 -412
  495. package/lib/webdriver/events.js +0 -179
  496. package/lib/webdriver/firefoxdomexecutor.js +0 -175
  497. package/lib/webdriver/http/corsclient.js +0 -133
  498. package/lib/webdriver/http/http.js +0 -525
  499. package/lib/webdriver/http/xhrclient.js +0 -67
  500. package/lib/webdriver/locators.js +0 -257
  501. package/lib/webdriver/logging.js +0 -347
  502. package/lib/webdriver/session.js +0 -74
  503. package/lib/webdriver/stacktrace.js +0 -619
  504. package/lib/webdriver/test/builder_test.js +0 -53
  505. package/lib/webdriver/test/capabilities_test.js +0 -72
  506. package/lib/webdriver/test/events_test.js +0 -203
  507. package/lib/webdriver/test/http/corsclient_test.js +0 -151
  508. package/lib/webdriver/test/http/http_test.js +0 -428
  509. package/lib/webdriver/test/http/xhrclient_test.js +0 -196
  510. package/lib/webdriver/test/locators_test.js +0 -59
  511. package/lib/webdriver/test/logging_test.js +0 -85
  512. package/lib/webdriver/test/promise_error_test.js +0 -892
  513. package/lib/webdriver/test/promise_flow_test.js +0 -2365
  514. package/lib/webdriver/test/promise_generator_test.js +0 -323
  515. package/lib/webdriver/test/promise_test.js +0 -2012
  516. package/lib/webdriver/test/stacktrace_test.js +0 -480
  517. package/lib/webdriver/test/test_bootstrap.js +0 -67
  518. package/lib/webdriver/test/testing/asserts_test.js +0 -117
  519. package/lib/webdriver/test/testing/client_test.js +0 -88
  520. package/lib/webdriver/test/testing/testcase_test.js +0 -229
  521. package/lib/webdriver/test/testutil.js +0 -209
  522. package/lib/webdriver/test/testutil_test.js +0 -104
  523. package/lib/webdriver/test/until_test.js +0 -411
  524. package/lib/webdriver/test/webdriver_generator_test.js +0 -92
  525. package/lib/webdriver/test/webdriver_test.js +0 -2369
  526. package/lib/webdriver/testing/asserts.js +0 -487
  527. package/lib/webdriver/testing/client.js +0 -179
  528. package/lib/webdriver/testing/jsunit.js +0 -363
  529. package/lib/webdriver/testing/testcase.js +0 -168
  530. package/lib/webdriver/testing/window.js +0 -244
  531. package/lib/webdriver/touchsequence.js +0 -248
  532. package/lib/webdriver/until.js +0 -412
  533. package/lib/webdriver/webdriver.js +0 -2511
  534. package/test/_base_test.js +0 -129
@@ -0,0 +1,2440 @@
1
+ // Licensed to the Software Freedom Conservancy (SFC) under one
2
+ // or more contributor license agreements. See the NOTICE file
3
+ // distributed with this work for additional information
4
+ // regarding copyright ownership. The SFC licenses this file
5
+ // to you under the Apache License, Version 2.0 (the
6
+ // "License"); you may not use this file except in compliance
7
+ // with the License. You may obtain a copy of the License at
8
+ //
9
+ // http://www.apache.org/licenses/LICENSE-2.0
10
+ //
11
+ // Unless required by applicable law or agreed to in writing,
12
+ // software distributed under the License is distributed on an
13
+ // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ // KIND, either express or implied. See the License for the
15
+ // specific language governing permissions and limitations
16
+ // under the License.
17
+
18
+ /**
19
+ * @fileoverview The heart of the WebDriver JavaScript API.
20
+ */
21
+
22
+ 'use strict';
23
+
24
+ const actions = require('./actions');
25
+ const by = require('./by');
26
+ const Capabilities = require('./capabilities').Capabilities;
27
+ const command = require('./command');
28
+ const error = require('./error');
29
+ const input = require('./input');
30
+ const logging = require('./logging');
31
+ const Session = require('./session').Session;
32
+ const Symbols = require('./symbols');
33
+ const promise = require('./promise');
34
+
35
+
36
+ /**
37
+ * Defines a condition for use with WebDriver's {@linkplain WebDriver#wait wait
38
+ * command}.
39
+ *
40
+ * @template OUT
41
+ */
42
+ class Condition {
43
+ /**
44
+ * @param {string} message A descriptive error message. Should complete the
45
+ * sentence "Waiting [...]"
46
+ * @param {function(!WebDriver): OUT} fn The condition function to
47
+ * evaluate on each iteration of the wait loop.
48
+ */
49
+ constructor(message, fn) {
50
+ /** @private {string} */
51
+ this.description_ = 'Waiting ' + message;
52
+
53
+ /** @type {function(!WebDriver): OUT} */
54
+ this.fn = fn;
55
+ }
56
+
57
+ /** @return {string} A description of this condition. */
58
+ description() {
59
+ return this.description_;
60
+ }
61
+ }
62
+
63
+
64
+ /**
65
+ * Defines a condition that will result in a {@link WebElement}.
66
+ *
67
+ * @extends {Condition<!(WebElement|promise.Promise<!WebElement>)>}
68
+ */
69
+ class WebElementCondition extends Condition {
70
+ /**
71
+ * @param {string} message A descriptive error message. Should complete the
72
+ * sentence "Waiting [...]"
73
+ * @param {function(!WebDriver): !(WebElement|promise.Promise<!WebElement>)}
74
+ * fn The condition function to evaluate on each iteration of the wait
75
+ * loop.
76
+ */
77
+ constructor(message, fn) {
78
+ super(message, fn);
79
+ }
80
+ }
81
+
82
+
83
+ //////////////////////////////////////////////////////////////////////////////
84
+ //
85
+ // WebDriver
86
+ //
87
+ //////////////////////////////////////////////////////////////////////////////
88
+
89
+
90
+ /**
91
+ * Translates a command to its wire-protocol representation before passing it
92
+ * to the given `executor` for execution.
93
+ * @param {!command.Executor} executor The executor to use.
94
+ * @param {!command.Command} command The command to execute.
95
+ * @return {!promise.Promise} A promise that will resolve with the
96
+ * command response.
97
+ */
98
+ function executeCommand(executor, command) {
99
+ return toWireValue(command.getParameters()).
100
+ then(function(parameters) {
101
+ command.setParameters(parameters);
102
+ return executor.execute(command);
103
+ });
104
+ }
105
+
106
+
107
+ /**
108
+ * Converts an object to its JSON representation in the WebDriver wire protocol.
109
+ * When converting values of type object, the following steps will be taken:
110
+ * <ol>
111
+ * <li>if the object is a WebElement, the return value will be the element's
112
+ * server ID
113
+ * <li>if the object defines a {@link Symbols.serialize} method, this algorithm
114
+ * will be recursively applied to the object's serialized representation
115
+ * <li>if the object provides a "toJSON" function, this algorithm will
116
+ * recursively be applied to the result of that function
117
+ * <li>otherwise, the value of each key will be recursively converted according
118
+ * to the rules above.
119
+ * </ol>
120
+ *
121
+ * @param {*} obj The object to convert.
122
+ * @return {!promise.Promise<?>} A promise that will resolve to the
123
+ * input value's JSON representation.
124
+ */
125
+ function toWireValue(obj) {
126
+ if (promise.isPromise(obj)) {
127
+ return obj.then(toWireValue);
128
+ }
129
+ return promise.fulfilled(convertValue(obj));
130
+ }
131
+
132
+
133
+ function convertValue(value) {
134
+ if (value === void 0 || value === null) {
135
+ return value;
136
+ }
137
+
138
+ if (typeof value === 'boolean'
139
+ || typeof value === 'number'
140
+ || typeof value === 'string') {
141
+ return value;
142
+ }
143
+
144
+ if (Array.isArray(value)) {
145
+ return convertKeys(value);
146
+ }
147
+
148
+ if (typeof value === 'function') {
149
+ return '' + value;
150
+ }
151
+
152
+ if (typeof value[Symbols.serialize] === 'function') {
153
+ return toWireValue(value[Symbols.serialize]());
154
+ } else if (typeof value.toJSON === 'function') {
155
+ return toWireValue(value.toJSON());
156
+ }
157
+ return convertKeys(value);
158
+ }
159
+
160
+
161
+ function convertKeys(obj) {
162
+ const isArray = Array.isArray(obj);
163
+ const numKeys = isArray ? obj.length : Object.keys(obj).length;
164
+ const ret = isArray ? new Array(numKeys) : {};
165
+ if (!numKeys) {
166
+ return promise.fulfilled(ret);
167
+ }
168
+
169
+ let numResolved = 0;
170
+
171
+ function forEachKey(obj, fn) {
172
+ if (Array.isArray(obj)) {
173
+ for (let i = 0, n = obj.length; i < n; i++) {
174
+ fn(obj[i], i);
175
+ }
176
+ } else {
177
+ for (let key in obj) {
178
+ fn(obj[key], key);
179
+ }
180
+ }
181
+ }
182
+
183
+ return new promise.Promise(function(done, reject) {
184
+ forEachKey(obj, function(value, key) {
185
+ if (promise.isPromise(value)) {
186
+ value.then(toWireValue).then(setValue, reject);
187
+ } else {
188
+ value = convertValue(value);
189
+ if (promise.isPromise(value)) {
190
+ value.then(toWireValue).then(setValue, reject);
191
+ } else {
192
+ setValue(value);
193
+ }
194
+ }
195
+
196
+ function setValue(value) {
197
+ ret[key] = value;
198
+ maybeFulfill();
199
+ }
200
+ });
201
+
202
+ function maybeFulfill() {
203
+ if (++numResolved === numKeys) {
204
+ done(ret);
205
+ }
206
+ }
207
+ });
208
+ }
209
+
210
+
211
+ /**
212
+ * Converts a value from its JSON representation according to the WebDriver wire
213
+ * protocol. Any JSON object that defines a WebElement ID will be decoded to a
214
+ * {@link WebElement} object. All other values will be passed through as is.
215
+ *
216
+ * @param {!WebDriver} driver The driver to use as the parent of any unwrapped
217
+ * {@link WebElement} values.
218
+ * @param {*} value The value to convert.
219
+ * @return {*} The converted value.
220
+ */
221
+ function fromWireValue(driver, value) {
222
+ if (Array.isArray(value)) {
223
+ value = value.map(v => fromWireValue(driver, v));
224
+ } else if (WebElement.isId(value)) {
225
+ let id = WebElement.extractId(value);
226
+ value = new WebElement(driver, id);
227
+ } else if (value && typeof value === 'object') {
228
+ let result = {};
229
+ for (let key in value) {
230
+ if (value.hasOwnProperty(key)) {
231
+ result[key] = fromWireValue(driver, value[key]);
232
+ }
233
+ }
234
+ value = result;
235
+ }
236
+ return value;
237
+ }
238
+
239
+
240
+ /**
241
+ * Creates a new WebDriver client, which provides control over a browser.
242
+ *
243
+ * Every command.Command returns a {@link promise.Promise} that
244
+ * represents the result of that command. Callbacks may be registered on this
245
+ * object to manipulate the command result or catch an expected error. Any
246
+ * commands scheduled with a callback are considered sub-commands and will
247
+ * execute before the next command in the current frame. For example:
248
+ *
249
+ * var message = [];
250
+ * driver.call(message.push, message, 'a').then(function() {
251
+ * driver.call(message.push, message, 'b');
252
+ * });
253
+ * driver.call(message.push, message, 'c');
254
+ * driver.call(function() {
255
+ * alert('message is abc? ' + (message.join('') == 'abc'));
256
+ * });
257
+ *
258
+ */
259
+ class WebDriver {
260
+ /**
261
+ * @param {!(Session|promise.Promise<!Session>)} session Either a
262
+ * known session or a promise that will be resolved to a session.
263
+ * @param {!command.Executor} executor The executor to use when sending
264
+ * commands to the browser.
265
+ * @param {promise.ControlFlow=} opt_flow The flow to
266
+ * schedule commands through. Defaults to the active flow object.
267
+ */
268
+ constructor(session, executor, opt_flow) {
269
+ /** @private {!promise.Promise<!Session>} */
270
+ this.session_ = promise.fulfilled(session);;
271
+
272
+ /** @private {!command.Executor} */
273
+ this.executor_ = executor;
274
+
275
+ /** @private {!promise.ControlFlow} */
276
+ this.flow_ = opt_flow || promise.controlFlow();
277
+
278
+ /** @private {input.FileDetector} */
279
+ this.fileDetector_ = null;
280
+ }
281
+
282
+ /**
283
+ * Creates a new WebDriver client for an existing session.
284
+ * @param {!command.Executor} executor Command executor to use when querying
285
+ * for session details.
286
+ * @param {string} sessionId ID of the session to attach to.
287
+ * @param {promise.ControlFlow=} opt_flow The control flow all
288
+ * driver commands should execute under. Defaults to the
289
+ * {@link promise.controlFlow() currently active} control flow.
290
+ * @return {!WebDriver} A new client for the specified session.
291
+ */
292
+ static attachToSession(executor, sessionId, opt_flow) {
293
+ let flow = opt_flow || promise.controlFlow();
294
+ let cmd = new command.Command(command.Name.DESCRIBE_SESSION)
295
+ .setParameter('sessionId', sessionId);
296
+ let session = flow.execute(
297
+ () => executeCommand(executor, cmd),
298
+ 'WebDriver.attachToSession()');
299
+
300
+ session = session.catch(err => {
301
+ // The DESCRIBE_SESSION command is not supported by the W3C spec, so if
302
+ // we get back an unknown command, just return a session with unknown
303
+ // capabilities.
304
+ if (err instanceof error.UnknownCommandError) {
305
+ return new Session(sessionId, new Capabilities);
306
+ }
307
+ throw err;
308
+ });
309
+
310
+ return new WebDriver(session, executor, flow);
311
+ }
312
+
313
+ /**
314
+ * Creates a new WebDriver session.
315
+ * @param {!command.Executor} executor The executor to create the new session
316
+ * with.
317
+ * @param {!./capabilities.Capabilities} desiredCapabilities The desired
318
+ * capabilities for the new session.
319
+ * @param {promise.ControlFlow=} opt_flow The control flow all driver
320
+ * commands should execute under, including the initial session creation.
321
+ * Defaults to the {@link promise.controlFlow() currently active}
322
+ * control flow.
323
+ * @return {!WebDriver} The driver for the newly created session.
324
+ */
325
+ static createSession(executor, desiredCapabilities, opt_flow) {
326
+ let flow = opt_flow || promise.controlFlow();
327
+ let cmd = new command.Command(command.Name.NEW_SESSION)
328
+ .setParameter('desiredCapabilities', desiredCapabilities) ;
329
+ let session = flow.execute(
330
+ () => executeCommand(executor, cmd),
331
+ 'WebDriver.createSession()');
332
+ return new WebDriver(session, executor, flow);
333
+ }
334
+
335
+ /**
336
+ * @return {!promise.ControlFlow} The control flow used by this
337
+ * instance.
338
+ */
339
+ controlFlow() {
340
+ return this.flow_;
341
+ }
342
+
343
+ /**
344
+ * Schedules a {@link command.Command} to be executed by this driver's
345
+ * {@link command.Executor}.
346
+ *
347
+ * @param {!command.Command} command The command to schedule.
348
+ * @param {string} description A description of the command for debugging.
349
+ * @return {!promise.Promise<T>} A promise that will be resolved
350
+ * with the command result.
351
+ * @template T
352
+ */
353
+ schedule(command, description) {
354
+ var self = this;
355
+
356
+ checkHasNotQuit();
357
+ command.setParameter('sessionId', this.session_);
358
+
359
+ // If any of the command parameters are rejected promises, those
360
+ // rejections may be reported as unhandled before the control flow
361
+ // attempts to execute the command. To ensure parameters errors
362
+ // propagate through the command itself, we resolve all of the
363
+ // command parameters now, but suppress any errors until the ControlFlow
364
+ // actually executes the command. This addresses scenarios like catching
365
+ // an element not found error in:
366
+ //
367
+ // driver.findElement(By.id('foo')).click().catch(function(e) {
368
+ // if (e instanceof NoSuchElementError) {
369
+ // // Do something.
370
+ // }
371
+ // });
372
+ var prepCommand = toWireValue(command.getParameters());
373
+ prepCommand.catch(function() {});
374
+
375
+ var flow = this.flow_;
376
+ var executor = this.executor_;
377
+ return flow.execute(function() {
378
+ // A call to WebDriver.quit() may have been scheduled in the same event
379
+ // loop as this |command|, which would prevent us from detecting that the
380
+ // driver has quit above. Therefore, we need to make another quick check.
381
+ // We still check above so we can fail as early as possible.
382
+ checkHasNotQuit();
383
+
384
+ // Retrieve resolved command parameters; any previously suppressed errors
385
+ // will now propagate up through the control flow as part of the command
386
+ // execution.
387
+ return prepCommand.then(function(parameters) {
388
+ command.setParameters(parameters);
389
+ return executor.execute(command);
390
+ }).then(value => fromWireValue(self, value));
391
+ }, description);
392
+
393
+ function checkHasNotQuit() {
394
+ if (!self.session_) {
395
+ throw new error.NoSuchSessionError(
396
+ 'This driver instance does not have a valid session ID ' +
397
+ '(did you call WebDriver.quit()?) and may no longer be ' +
398
+ 'used.');
399
+ }
400
+ }
401
+ }
402
+
403
+ /**
404
+ * Sets the {@linkplain input.FileDetector file detector} that should be
405
+ * used with this instance.
406
+ * @param {input.FileDetector} detector The detector to use or {@code null}.
407
+ */
408
+ setFileDetector(detector) {
409
+ this.fileDetector_ = detector;
410
+ }
411
+
412
+ /**
413
+ * @return {!command.Executor} The command executor used by this instance.
414
+ */
415
+ getExecutor() {
416
+ return this.executor_;
417
+ }
418
+
419
+ /**
420
+ * @return {!promise.Promise<!Session>} A promise for this client's
421
+ * session.
422
+ */
423
+ getSession() {
424
+ return this.session_;
425
+ }
426
+
427
+ /**
428
+ * @return {!promise.Promise<!Capabilities>} A promise
429
+ * that will resolve with the this instance's capabilities.
430
+ */
431
+ getCapabilities() {
432
+ return this.session_.then(session => session.getCapabilities());
433
+ }
434
+
435
+ /**
436
+ * Schedules a command to quit the current session. After calling quit, this
437
+ * instance will be invalidated and may no longer be used to issue commands
438
+ * against the browser.
439
+ * @return {!promise.Promise<void>} A promise that will be resolved
440
+ * when the command has completed.
441
+ */
442
+ quit() {
443
+ var result = this.schedule(
444
+ new command.Command(command.Name.QUIT),
445
+ 'WebDriver.quit()');
446
+ // Delete our session ID when the quit command finishes; this will allow us
447
+ // to throw an error when attemnpting to use a driver post-quit.
448
+ return result.finally(() => delete this.session_);
449
+ }
450
+
451
+ /**
452
+ * Creates a new action sequence using this driver. The sequence will not be
453
+ * scheduled for execution until {@link actions.ActionSequence#perform} is
454
+ * called. Example:
455
+ *
456
+ * driver.actions().
457
+ * mouseDown(element1).
458
+ * mouseMove(element2).
459
+ * mouseUp().
460
+ * perform();
461
+ *
462
+ * @return {!actions.ActionSequence} A new action sequence for this instance.
463
+ */
464
+ actions() {
465
+ return new actions.ActionSequence(this);
466
+ }
467
+
468
+ /**
469
+ * Creates a new touch sequence using this driver. The sequence will not be
470
+ * scheduled for execution until {@link actions.TouchSequence#perform} is
471
+ * called. Example:
472
+ *
473
+ * driver.touchActions().
474
+ * tap(element1).
475
+ * doubleTap(element2).
476
+ * perform();
477
+ *
478
+ * @return {!actions.TouchSequence} A new touch sequence for this instance.
479
+ */
480
+ touchActions() {
481
+ return new actions.TouchSequence(this);
482
+ }
483
+
484
+ /**
485
+ * Schedules a command to execute JavaScript in the context of the currently
486
+ * selected frame or window. The script fragment will be executed as the body
487
+ * of an anonymous function. If the script is provided as a function object,
488
+ * that function will be converted to a string for injection into the target
489
+ * window.
490
+ *
491
+ * Any arguments provided in addition to the script will be included as script
492
+ * arguments and may be referenced using the {@code arguments} object.
493
+ * Arguments may be a boolean, number, string, or {@linkplain WebElement}.
494
+ * Arrays and objects may also be used as script arguments as long as each item
495
+ * adheres to the types previously mentioned.
496
+ *
497
+ * The script may refer to any variables accessible from the current window.
498
+ * Furthermore, the script will execute in the window's context, thus
499
+ * {@code document} may be used to refer to the current document. Any local
500
+ * variables will not be available once the script has finished executing,
501
+ * though global variables will persist.
502
+ *
503
+ * If the script has a return value (i.e. if the script contains a return
504
+ * statement), then the following steps will be taken for resolving this
505
+ * functions return value:
506
+ *
507
+ * - For a HTML element, the value will resolve to a {@linkplain WebElement}
508
+ * - Null and undefined return values will resolve to null</li>
509
+ * - Booleans, numbers, and strings will resolve as is</li>
510
+ * - Functions will resolve to their string representation</li>
511
+ * - For arrays and objects, each member item will be converted according to
512
+ * the rules above
513
+ *
514
+ * @param {!(string|Function)} script The script to execute.
515
+ * @param {...*} var_args The arguments to pass to the script.
516
+ * @return {!promise.Promise<T>} A promise that will resolve to the
517
+ * scripts return value.
518
+ * @template T
519
+ */
520
+ executeScript(script, var_args) {
521
+ if (typeof script === 'function') {
522
+ script = 'return (' + script + ').apply(null, arguments);';
523
+ }
524
+ let args =
525
+ arguments.length > 1 ? Array.prototype.slice.call(arguments, 1) : [];
526
+ return this.schedule(
527
+ new command.Command(command.Name.EXECUTE_SCRIPT).
528
+ setParameter('script', script).
529
+ setParameter('args', args),
530
+ 'WebDriver.executeScript()');
531
+ }
532
+
533
+ /**
534
+ * Schedules a command to execute asynchronous JavaScript in the context of the
535
+ * currently selected frame or window. The script fragment will be executed as
536
+ * the body of an anonymous function. If the script is provided as a function
537
+ * object, that function will be converted to a string for injection into the
538
+ * target window.
539
+ *
540
+ * Any arguments provided in addition to the script will be included as script
541
+ * arguments and may be referenced using the {@code arguments} object.
542
+ * Arguments may be a boolean, number, string, or {@code WebElement}.
543
+ * Arrays and objects may also be used as script arguments as long as each item
544
+ * adheres to the types previously mentioned.
545
+ *
546
+ * Unlike executing synchronous JavaScript with {@link #executeScript},
547
+ * scripts executed with this function must explicitly signal they are finished
548
+ * by invoking the provided callback. This callback will always be injected
549
+ * into the executed function as the last argument, and thus may be referenced
550
+ * with {@code arguments[arguments.length - 1]}. The following steps will be
551
+ * taken for resolving this functions return value against the first argument
552
+ * to the script's callback function:
553
+ *
554
+ * - For a HTML element, the value will resolve to a
555
+ * {@link WebElement}
556
+ * - Null and undefined return values will resolve to null
557
+ * - Booleans, numbers, and strings will resolve as is
558
+ * - Functions will resolve to their string representation
559
+ * - For arrays and objects, each member item will be converted according to
560
+ * the rules above
561
+ *
562
+ * __Example #1:__ Performing a sleep that is synchronized with the currently
563
+ * selected window:
564
+ *
565
+ * var start = new Date().getTime();
566
+ * driver.executeAsyncScript(
567
+ * 'window.setTimeout(arguments[arguments.length - 1], 500);').
568
+ * then(function() {
569
+ * console.log(
570
+ * 'Elapsed time: ' + (new Date().getTime() - start) + ' ms');
571
+ * });
572
+ *
573
+ * __Example #2:__ Synchronizing a test with an AJAX application:
574
+ *
575
+ * var button = driver.findElement(By.id('compose-button'));
576
+ * button.click();
577
+ * driver.executeAsyncScript(
578
+ * 'var callback = arguments[arguments.length - 1];' +
579
+ * 'mailClient.getComposeWindowWidget().onload(callback);');
580
+ * driver.switchTo().frame('composeWidget');
581
+ * driver.findElement(By.id('to')).sendKeys('dog@example.com');
582
+ *
583
+ * __Example #3:__ Injecting a XMLHttpRequest and waiting for the result. In
584
+ * this example, the inject script is specified with a function literal. When
585
+ * using this format, the function is converted to a string for injection, so it
586
+ * should not reference any symbols not defined in the scope of the page under
587
+ * test.
588
+ *
589
+ * driver.executeAsyncScript(function() {
590
+ * var callback = arguments[arguments.length - 1];
591
+ * var xhr = new XMLHttpRequest();
592
+ * xhr.open("GET", "/resource/data.json", true);
593
+ * xhr.onreadystatechange = function() {
594
+ * if (xhr.readyState == 4) {
595
+ * callback(xhr.responseText);
596
+ * }
597
+ * };
598
+ * xhr.send('');
599
+ * }).then(function(str) {
600
+ * console.log(JSON.parse(str)['food']);
601
+ * });
602
+ *
603
+ * @param {!(string|Function)} script The script to execute.
604
+ * @param {...*} var_args The arguments to pass to the script.
605
+ * @return {!promise.Promise<T>} A promise that will resolve to the
606
+ * scripts return value.
607
+ * @template T
608
+ */
609
+ executeAsyncScript(script, var_args) {
610
+ if (typeof script === 'function') {
611
+ script = 'return (' + script + ').apply(null, arguments);';
612
+ }
613
+ let args = Array.prototype.slice.call(arguments, 1);
614
+ return this.schedule(
615
+ new command.Command(command.Name.EXECUTE_ASYNC_SCRIPT).
616
+ setParameter('script', script).
617
+ setParameter('args', args),
618
+ 'WebDriver.executeScript()');
619
+ }
620
+
621
+ /**
622
+ * Schedules a command to execute a custom function.
623
+ * @param {function(...): (T|promise.Promise<T>)} fn The function to
624
+ * execute.
625
+ * @param {Object=} opt_scope The object in whose scope to execute the function.
626
+ * @param {...*} var_args Any arguments to pass to the function.
627
+ * @return {!promise.Promise<T>} A promise that will be resolved'
628
+ * with the function's result.
629
+ * @template T
630
+ */
631
+ call(fn, opt_scope, var_args) {
632
+ let args = Array.prototype.slice.call(arguments, 2);
633
+ let flow = this.flow_;
634
+ return flow.execute(function() {
635
+ return promise.fullyResolved(args).then(function(args) {
636
+ if (promise.isGenerator(fn)) {
637
+ args.unshift(fn, opt_scope);
638
+ return promise.consume.apply(null, args);
639
+ }
640
+ return fn.apply(opt_scope, args);
641
+ });
642
+ }, 'WebDriver.call(' + (fn.name || 'function') + ')');
643
+ }
644
+
645
+ /**
646
+ * Schedules a command to wait for a condition to hold. The condition may be
647
+ * specified by a {@link Condition}, as a custom function, or as any
648
+ * promise-like thenable.
649
+ *
650
+ * For a {@link Condition} or function, the wait will repeatedly
651
+ * evaluate the condition until it returns a truthy value. If any errors occur
652
+ * while evaluating the condition, they will be allowed to propagate. In the
653
+ * event a condition returns a {@link promise.Promise promise}, the polling
654
+ * loop will wait for it to be resolved and use the resolved value for whether
655
+ * the condition has been satisified. Note the resolution time for a promise
656
+ * is factored into whether a wait has timed out.
657
+ *
658
+ * Note, if the provided condition is a {@link WebElementCondition}, then
659
+ * the wait will return a {@link WebElementPromise} that will resolve to the
660
+ * element that satisified the condition.
661
+ *
662
+ * _Example:_ waiting up to 10 seconds for an element to be present on the
663
+ * page.
664
+ *
665
+ * var button = driver.wait(until.elementLocated(By.id('foo')), 10000);
666
+ * button.click();
667
+ *
668
+ * This function may also be used to block the command flow on the resolution
669
+ * of any thenable promise object. When given a promise, the command will
670
+ * simply wait for its resolution before completing. A timeout may be provided
671
+ * to fail the command if the promise does not resolve before the timeout
672
+ * expires.
673
+ *
674
+ * _Example:_ Suppose you have a function, `startTestServer`, that returns a
675
+ * promise for when a server is ready for requests. You can block a WebDriver
676
+ * client on this promise with:
677
+ *
678
+ * var started = startTestServer();
679
+ * driver.wait(started, 5 * 1000, 'Server should start within 5 seconds');
680
+ * driver.get(getServerUrl());
681
+ *
682
+ * @param {!(promise.Promise<T>|
683
+ * Condition<T>|
684
+ * function(!WebDriver): T)} condition The condition to
685
+ * wait on, defined as a promise, condition object, or a function to
686
+ * evaluate as a condition.
687
+ * @param {number=} opt_timeout How long to wait for the condition to be true.
688
+ * @param {string=} opt_message An optional message to use if the wait times
689
+ * out.
690
+ * @return {!(promise.Promise<T>|WebElementPromise)} A promise that will be
691
+ * resolved with the first truthy value returned by the condition
692
+ * function, or rejected if the condition times out. If the input
693
+ * input condition is an instance of a {@link WebElementCondition},
694
+ * the returned value will be a {@link WebElementPromise}.
695
+ * @template T
696
+ */
697
+ wait(condition, opt_timeout, opt_message) {
698
+ if (promise.isPromise(condition)) {
699
+ return this.flow_.wait(
700
+ /** @type {!promise.Promise} */(condition),
701
+ opt_timeout, opt_message);
702
+ }
703
+
704
+ var message = opt_message;
705
+ var fn = /** @type {!Function} */(condition);
706
+ if (condition instanceof Condition) {
707
+ message = message || condition.description();
708
+ fn = condition.fn;
709
+ }
710
+
711
+ var driver = this;
712
+ var result = this.flow_.wait(function() {
713
+ if (promise.isGenerator(fn)) {
714
+ return promise.consume(fn, null, [driver]);
715
+ }
716
+ return fn(driver);
717
+ }, opt_timeout, message);
718
+
719
+ if (condition instanceof WebElementCondition) {
720
+ result = new WebElementPromise(this, result.then(function(value) {
721
+ if (!(value instanceof WebElement)) {
722
+ throw TypeError(
723
+ 'WebElementCondition did not resolve to a WebElement: '
724
+ + Object.prototype.toString.call(value));
725
+ }
726
+ return value;
727
+ }));
728
+ }
729
+ return result;
730
+ }
731
+
732
+ /**
733
+ * Schedules a command to make the driver sleep for the given amount of time.
734
+ * @param {number} ms The amount of time, in milliseconds, to sleep.
735
+ * @return {!promise.Promise<void>} A promise that will be resolved
736
+ * when the sleep has finished.
737
+ */
738
+ sleep(ms) {
739
+ return this.flow_.timeout(ms, 'WebDriver.sleep(' + ms + ')');
740
+ }
741
+
742
+ /**
743
+ * Schedules a command to retrieve they current window handle.
744
+ * @return {!promise.Promise<string>} A promise that will be
745
+ * resolved with the current window handle.
746
+ */
747
+ getWindowHandle() {
748
+ return this.schedule(
749
+ new command.Command(command.Name.GET_CURRENT_WINDOW_HANDLE),
750
+ 'WebDriver.getWindowHandle()');
751
+ }
752
+
753
+ /**
754
+ * Schedules a command to retrieve the current list of available window handles.
755
+ * @return {!promise.Promise.<!Array<string>>} A promise that will
756
+ * be resolved with an array of window handles.
757
+ */
758
+ getAllWindowHandles() {
759
+ return this.schedule(
760
+ new command.Command(command.Name.GET_WINDOW_HANDLES),
761
+ 'WebDriver.getAllWindowHandles()');
762
+ }
763
+
764
+ /**
765
+ * Schedules a command to retrieve the current page's source. The page source
766
+ * returned is a representation of the underlying DOM: do not expect it to be
767
+ * formatted or escaped in the same way as the response sent from the web
768
+ * server.
769
+ * @return {!promise.Promise<string>} A promise that will be
770
+ * resolved with the current page source.
771
+ */
772
+ getPageSource() {
773
+ return this.schedule(
774
+ new command.Command(command.Name.GET_PAGE_SOURCE),
775
+ 'WebDriver.getPageSource()');
776
+ }
777
+
778
+ /**
779
+ * Schedules a command to close the current window.
780
+ * @return {!promise.Promise<void>} A promise that will be resolved
781
+ * when this command has completed.
782
+ */
783
+ close() {
784
+ return this.schedule(new command.Command(command.Name.CLOSE),
785
+ 'WebDriver.close()');
786
+ }
787
+
788
+ /**
789
+ * Schedules a command to navigate to the given URL.
790
+ * @param {string} url The fully qualified URL to open.
791
+ * @return {!promise.Promise<void>} A promise that will be resolved
792
+ * when the document has finished loading.
793
+ */
794
+ get(url) {
795
+ return this.navigate().to(url);
796
+ }
797
+
798
+ /**
799
+ * Schedules a command to retrieve the URL of the current page.
800
+ * @return {!promise.Promise<string>} A promise that will be
801
+ * resolved with the current URL.
802
+ */
803
+ getCurrentUrl() {
804
+ return this.schedule(
805
+ new command.Command(command.Name.GET_CURRENT_URL),
806
+ 'WebDriver.getCurrentUrl()');
807
+ }
808
+
809
+ /**
810
+ * Schedules a command to retrieve the current page's title.
811
+ * @return {!promise.Promise<string>} A promise that will be
812
+ * resolved with the current page's title.
813
+ */
814
+ getTitle() {
815
+ return this.schedule(new command.Command(command.Name.GET_TITLE),
816
+ 'WebDriver.getTitle()');
817
+ }
818
+
819
+ /**
820
+ * Schedule a command to find an element on the page. If the element cannot be
821
+ * found, a {@link bot.ErrorCode.NO_SUCH_ELEMENT} result will be returned
822
+ * by the driver. Unlike other commands, this error cannot be suppressed. In
823
+ * other words, scheduling a command to find an element doubles as an assert
824
+ * that the element is present on the page. To test whether an element is
825
+ * present on the page, use {@link #isElementPresent} instead.
826
+ *
827
+ * The search criteria for an element may be defined using one of the
828
+ * factories in the {@link webdriver.By} namespace, or as a short-hand
829
+ * {@link webdriver.By.Hash} object. For example, the following two statements
830
+ * are equivalent:
831
+ *
832
+ * var e1 = driver.findElement(By.id('foo'));
833
+ * var e2 = driver.findElement({id:'foo'});
834
+ *
835
+ * You may also provide a custom locator function, which takes as input this
836
+ * instance and returns a {@link WebElement}, or a promise that will resolve
837
+ * to a WebElement. If the returned promise resolves to an array of
838
+ * WebElements, WebDriver will use the first element. For example, to find the
839
+ * first visible link on a page, you could write:
840
+ *
841
+ * var link = driver.findElement(firstVisibleLink);
842
+ *
843
+ * function firstVisibleLink(driver) {
844
+ * var links = driver.findElements(By.tagName('a'));
845
+ * return promise.filter(links, function(link) {
846
+ * return link.isDisplayed();
847
+ * });
848
+ * }
849
+ *
850
+ * @param {!(by.By|Function)} locator The locator to use.
851
+ * @return {!WebElementPromise} A WebElement that can be used to issue
852
+ * commands against the located element. If the element is not found, the
853
+ * element will be invalidated and all scheduled commands aborted.
854
+ */
855
+ findElement(locator) {
856
+ let id;
857
+ locator = by.checkedLocator(locator);
858
+ if (typeof locator === 'function') {
859
+ id = this.findElementInternal_(locator, this);
860
+ } else {
861
+ let cmd = new command.Command(command.Name.FIND_ELEMENT).
862
+ setParameter('using', locator.using).
863
+ setParameter('value', locator.value);
864
+ id = this.schedule(cmd, 'WebDriver.findElement(' + locator + ')');
865
+ }
866
+ return new WebElementPromise(this, id);
867
+ }
868
+
869
+ /**
870
+ * @param {!Function} locatorFn The locator function to use.
871
+ * @param {!(WebDriver|WebElement)} context The search
872
+ * context.
873
+ * @return {!promise.Promise.<!WebElement>} A
874
+ * promise that will resolve to a list of WebElements.
875
+ * @private
876
+ */
877
+ findElementInternal_(locatorFn, context) {
878
+ return this.call(() => locatorFn(context)).then(function(result) {
879
+ if (Array.isArray(result)) {
880
+ result = result[0];
881
+ }
882
+ if (!(result instanceof WebElement)) {
883
+ throw new TypeError('Custom locator did not return a WebElement');
884
+ }
885
+ return result;
886
+ });
887
+ }
888
+
889
+ /**
890
+ * Schedules a command to test if an element is present on the page.
891
+ *
892
+ * If given a DOM element, this function will check if it belongs to the
893
+ * document the driver is currently focused on. Otherwise, the function will
894
+ * test if at least one element can be found with the given search criteria.
895
+ *
896
+ * @param {!(by.By|Function)} locator The locator to use.
897
+ * @return {!promise.Promise<boolean>} A promise that will resolve
898
+ * with whether the element is present on the page.
899
+ * @deprecated This method will be removed in Selenium 3.0 for consistency
900
+ * with the other Selenium language bindings. This method is equivalent
901
+ * to
902
+ *
903
+ * driver.findElements(locator).then(e => !!e.length);
904
+ */
905
+ isElementPresent(locator) {
906
+ return this.findElements.apply(this, arguments).then(function(result) {
907
+ return !!result.length;
908
+ });
909
+ }
910
+
911
+ /**
912
+ * Schedule a command to search for multiple elements on the page.
913
+ *
914
+ * @param {!(by.By|Function)} locator The locator to use.
915
+ * @return {!promise.Promise.<!Array.<!WebElement>>} A
916
+ * promise that will resolve to an array of WebElements.
917
+ */
918
+ findElements(locator) {
919
+ locator = by.checkedLocator(locator);
920
+ if (typeof locator === 'function') {
921
+ return this.findElementsInternal_(locator, this);
922
+ } else {
923
+ let cmd = new command.Command(command.Name.FIND_ELEMENTS).
924
+ setParameter('using', locator.using).
925
+ setParameter('value', locator.value);
926
+ let res = this.schedule(cmd, 'WebDriver.findElements(' + locator + ')');
927
+ return res.catch(function(e) {
928
+ if (e instanceof error.NoSuchElementError) {
929
+ return [];
930
+ }
931
+ throw e;
932
+ });
933
+ }
934
+ }
935
+
936
+ /**
937
+ * @param {!Function} locatorFn The locator function to use.
938
+ * @param {!(WebDriver|WebElement)} context The search context.
939
+ * @return {!promise.Promise<!Array<!WebElement>>} A promise that
940
+ * will resolve to an array of WebElements.
941
+ * @private
942
+ */
943
+ findElementsInternal_(locatorFn, context) {
944
+ return this.call(() => locatorFn(context)).then(function(result) {
945
+ if (result instanceof WebElement) {
946
+ return [result];
947
+ }
948
+
949
+ if (!Array.isArray(result)) {
950
+ return [];
951
+ }
952
+
953
+ return result.filter(function(item) {
954
+ return item instanceof WebElement;
955
+ });
956
+ });
957
+ }
958
+
959
+ /**
960
+ * Schedule a command to take a screenshot. The driver makes a best effort to
961
+ * return a screenshot of the following, in order of preference:
962
+ *
963
+ * 1. Entire page
964
+ * 2. Current window
965
+ * 3. Visible portion of the current frame
966
+ * 4. The entire display containing the browser
967
+ *
968
+ * @return {!promise.Promise<string>} A promise that will be
969
+ * resolved to the screenshot as a base-64 encoded PNG.
970
+ */
971
+ takeScreenshot() {
972
+ return this.schedule(new command.Command(command.Name.SCREENSHOT),
973
+ 'WebDriver.takeScreenshot()');
974
+ }
975
+
976
+ /**
977
+ * @return {!Options} The options interface for this instance.
978
+ */
979
+ manage() {
980
+ return new Options(this);
981
+ }
982
+
983
+ /**
984
+ * @return {!Navigation} The navigation interface for this instance.
985
+ */
986
+ navigate() {
987
+ return new Navigation(this);
988
+ }
989
+
990
+ /**
991
+ * @return {!TargetLocator} The target locator interface for this
992
+ * instance.
993
+ */
994
+ switchTo() {
995
+ return new TargetLocator(this);
996
+ }
997
+ }
998
+
999
+
1000
+ /**
1001
+ * Interface for navigating back and forth in the browser history.
1002
+ *
1003
+ * This class should never be instantiated directly. Insead, obtain an instance
1004
+ * with
1005
+ *
1006
+ * webdriver.navigate()
1007
+ *
1008
+ * @see WebDriver#navigate()
1009
+ */
1010
+ class Navigation {
1011
+ /**
1012
+ * @param {!WebDriver} driver The parent driver.
1013
+ * @private
1014
+ */
1015
+ constructor(driver) {
1016
+ /** @private {!WebDriver} */
1017
+ this.driver_ = driver;
1018
+ }
1019
+
1020
+ /**
1021
+ * Schedules a command to navigate to a new URL.
1022
+ * @param {string} url The URL to navigate to.
1023
+ * @return {!promise.Promise<void>} A promise that will be resolved
1024
+ * when the URL has been loaded.
1025
+ */
1026
+ to(url) {
1027
+ return this.driver_.schedule(
1028
+ new command.Command(command.Name.GET).
1029
+ setParameter('url', url),
1030
+ 'WebDriver.navigate().to(' + url + ')');
1031
+ }
1032
+
1033
+ /**
1034
+ * Schedules a command to move backwards in the browser history.
1035
+ * @return {!promise.Promise<void>} A promise that will be resolved
1036
+ * when the navigation event has completed.
1037
+ */
1038
+ back() {
1039
+ return this.driver_.schedule(
1040
+ new command.Command(command.Name.GO_BACK),
1041
+ 'WebDriver.navigate().back()');
1042
+ }
1043
+
1044
+ /**
1045
+ * Schedules a command to move forwards in the browser history.
1046
+ * @return {!promise.Promise<void>} A promise that will be resolved
1047
+ * when the navigation event has completed.
1048
+ */
1049
+ forward() {
1050
+ return this.driver_.schedule(
1051
+ new command.Command(command.Name.GO_FORWARD),
1052
+ 'WebDriver.navigate().forward()');
1053
+ }
1054
+
1055
+ /**
1056
+ * Schedules a command to refresh the current page.
1057
+ * @return {!promise.Promise<void>} A promise that will be resolved
1058
+ * when the navigation event has completed.
1059
+ */
1060
+ refresh() {
1061
+ return this.driver_.schedule(
1062
+ new command.Command(command.Name.REFRESH),
1063
+ 'WebDriver.navigate().refresh()');
1064
+ }
1065
+ }
1066
+
1067
+
1068
+ /**
1069
+ * Provides methods for managing browser and driver state.
1070
+ *
1071
+ * This class should never be instantiated directly. Insead, obtain an instance
1072
+ * with
1073
+ *
1074
+ * webdriver.manage()
1075
+ *
1076
+ * @see WebDriver#manage()
1077
+ */
1078
+ class Options {
1079
+ /**
1080
+ * @param {!WebDriver} driver The parent driver.
1081
+ * @private
1082
+ */
1083
+ constructor(driver) {
1084
+ /** @private {!WebDriver} */
1085
+ this.driver_ = driver;
1086
+ }
1087
+
1088
+ /**
1089
+ * Schedules a command to add a cookie.
1090
+ * @param {string} name The cookie name.
1091
+ * @param {string} value The cookie value.
1092
+ * @param {string=} opt_path The cookie path.
1093
+ * @param {string=} opt_domain The cookie domain.
1094
+ * @param {boolean=} opt_isSecure Whether the cookie is secure.
1095
+ * @param {(number|!Date)=} opt_expiry When the cookie expires. If specified
1096
+ * as a number, should be in milliseconds since midnight,
1097
+ * January 1, 1970 UTC.
1098
+ * @return {!promise.Promise<void>} A promise that will be resolved
1099
+ * when the cookie has been added to the page.
1100
+ */
1101
+ addCookie(name, value, opt_path, opt_domain, opt_isSecure, opt_expiry) {
1102
+ // We do not allow '=' or ';' in the name.
1103
+ if (/[;=]/.test(name)) {
1104
+ throw new error.InvalidArgumentError(
1105
+ 'Invalid cookie name "' + name + '"');
1106
+ }
1107
+
1108
+ // We do not allow ';' in value.
1109
+ if (/;/.test(value)) {
1110
+ throw new error.InvalidArgumentError(
1111
+ 'Invalid cookie value "' + value + '"');
1112
+ }
1113
+
1114
+ var cookieString = name + '=' + value +
1115
+ (opt_domain ? ';domain=' + opt_domain : '') +
1116
+ (opt_path ? ';path=' + opt_path : '') +
1117
+ (opt_isSecure ? ';secure' : '');
1118
+
1119
+ var expiry;
1120
+ if (opt_expiry !== void(0)) {
1121
+ var expiryDate;
1122
+ if (typeof opt_expiry === 'number') {
1123
+ expiryDate = new Date(opt_expiry);
1124
+ } else {
1125
+ expiryDate = /** @type {!Date} */ (opt_expiry);
1126
+ opt_expiry = expiryDate.getTime();
1127
+ }
1128
+ cookieString += ';expires=' + expiryDate.toUTCString();
1129
+ // Convert from milliseconds to seconds.
1130
+ expiry = Math.floor(/** @type {number} */ (opt_expiry) / 1000);
1131
+ }
1132
+
1133
+ return this.driver_.schedule(
1134
+ new command.Command(command.Name.ADD_COOKIE).
1135
+ setParameter('cookie', {
1136
+ 'name': name,
1137
+ 'value': value,
1138
+ 'path': opt_path,
1139
+ 'domain': opt_domain,
1140
+ 'secure': !!opt_isSecure,
1141
+ 'expiry': expiry
1142
+ }),
1143
+ 'WebDriver.manage().addCookie(' + cookieString + ')');
1144
+ }
1145
+
1146
+ /**
1147
+ * Schedules a command to delete all cookies visible to the current page.
1148
+ * @return {!promise.Promise<void>} A promise that will be resolved
1149
+ * when all cookies have been deleted.
1150
+ */
1151
+ deleteAllCookies() {
1152
+ return this.driver_.schedule(
1153
+ new command.Command(command.Name.DELETE_ALL_COOKIES),
1154
+ 'WebDriver.manage().deleteAllCookies()');
1155
+ }
1156
+
1157
+ /**
1158
+ * Schedules a command to delete the cookie with the given name. This command is
1159
+ * a no-op if there is no cookie with the given name visible to the current
1160
+ * page.
1161
+ * @param {string} name The name of the cookie to delete.
1162
+ * @return {!promise.Promise<void>} A promise that will be resolved
1163
+ * when the cookie has been deleted.
1164
+ */
1165
+ deleteCookie(name) {
1166
+ return this.driver_.schedule(
1167
+ new command.Command(command.Name.DELETE_COOKIE).
1168
+ setParameter('name', name),
1169
+ 'WebDriver.manage().deleteCookie(' + name + ')');
1170
+ }
1171
+
1172
+ /**
1173
+ * Schedules a command to retrieve all cookies visible to the current page.
1174
+ * Each cookie will be returned as a JSON object as described by the WebDriver
1175
+ * wire protocol.
1176
+ * @return {!promise.Promise<!Array<WebDriver.Options.Cookie>>} A
1177
+ * promise that will be resolved with the cookies visible to the current page.
1178
+ */
1179
+ getCookies() {
1180
+ return this.driver_.schedule(
1181
+ new command.Command(command.Name.GET_ALL_COOKIES),
1182
+ 'WebDriver.manage().getCookies()');
1183
+ }
1184
+
1185
+ /**
1186
+ * Schedules a command to retrieve the cookie with the given name. Returns null
1187
+ * if there is no such cookie. The cookie will be returned as a JSON object as
1188
+ * described by the WebDriver wire protocol.
1189
+ *
1190
+ * @param {string} name The name of the cookie to retrieve.
1191
+ * @return {!promise.Promise<?WebDriver.Options.Cookie>} A promise
1192
+ * that will be resolved with the named cookie, or `null` if there is no
1193
+ * such cookie.
1194
+ */
1195
+ getCookie(name) {
1196
+ return this.getCookies().then(function(cookies) {
1197
+ for (let cookie of cookies) {
1198
+ if (cookie && cookie['name'] === name) {
1199
+ return cookie;
1200
+ }
1201
+ }
1202
+ return null;
1203
+ });
1204
+ }
1205
+
1206
+ /**
1207
+ * @return {!Logs} The interface for managing driver
1208
+ * logs.
1209
+ */
1210
+ logs() {
1211
+ return new Logs(this.driver_);
1212
+ }
1213
+
1214
+ /**
1215
+ * @return {!Timeouts} The interface for managing driver timeouts.
1216
+ */
1217
+ timeouts() {
1218
+ return new Timeouts(this.driver_);
1219
+ }
1220
+
1221
+ /**
1222
+ * @return {!Window} The interface for managing the current window.
1223
+ */
1224
+ window() {
1225
+ return new Window(this.driver_);
1226
+ }
1227
+ }
1228
+
1229
+
1230
+ /**
1231
+ * A JSON description of a browser cookie.
1232
+ * @typedef {{
1233
+ * name: string,
1234
+ * value: string,
1235
+ * path: (string|undefined),
1236
+ * domain: (string|undefined),
1237
+ * secure: (boolean|undefined),
1238
+ * expiry: (number|undefined)
1239
+ * }}
1240
+ */
1241
+ Options.Cookie;
1242
+
1243
+
1244
+ /**
1245
+ * An interface for managing timeout behavior for WebDriver instances.
1246
+ *
1247
+ * This class should never be instantiated directly. Insead, obtain an instance
1248
+ * with
1249
+ *
1250
+ * webdriver.manage().timeouts()
1251
+ *
1252
+ * @see WebDriver#manage()
1253
+ * @see Options#timeouts()
1254
+ */
1255
+ class Timeouts {
1256
+ /**
1257
+ * @param {!WebDriver} driver The parent driver.
1258
+ * @private
1259
+ */
1260
+ constructor(driver) {
1261
+ /** @private {!WebDriver} */
1262
+ this.driver_ = driver;
1263
+ }
1264
+
1265
+ /**
1266
+ * Specifies the amount of time the driver should wait when searching for an
1267
+ * element if it is not immediately present.
1268
+ *
1269
+ * When searching for a single element, the driver should poll the page
1270
+ * until the element has been found, or this timeout expires before failing
1271
+ * with a {@link bot.ErrorCode.NO_SUCH_ELEMENT} error. When searching
1272
+ * for multiple elements, the driver should poll the page until at least one
1273
+ * element has been found or this timeout has expired.
1274
+ *
1275
+ * Setting the wait timeout to 0 (its default value), disables implicit
1276
+ * waiting.
1277
+ *
1278
+ * Increasing the implicit wait timeout should be used judiciously as it
1279
+ * will have an adverse effect on test run time, especially when used with
1280
+ * slower location strategies like XPath.
1281
+ *
1282
+ * @param {number} ms The amount of time to wait, in milliseconds.
1283
+ * @return {!promise.Promise<void>} A promise that will be resolved
1284
+ * when the implicit wait timeout has been set.
1285
+ */
1286
+ implicitlyWait(ms) {
1287
+ return this.driver_.schedule(
1288
+ new command.Command(command.Name.IMPLICITLY_WAIT).
1289
+ setParameter('ms', ms < 0 ? 0 : ms),
1290
+ 'WebDriver.manage().timeouts().implicitlyWait(' + ms + ')');
1291
+ }
1292
+
1293
+ /**
1294
+ * Sets the amount of time to wait, in milliseconds, for an asynchronous
1295
+ * script to finish execution before returning an error. If the timeout is
1296
+ * less than or equal to 0, the script will be allowed to run indefinitely.
1297
+ *
1298
+ * @param {number} ms The amount of time to wait, in milliseconds.
1299
+ * @return {!promise.Promise<void>} A promise that will be resolved
1300
+ * when the script timeout has been set.
1301
+ */
1302
+ setScriptTimeout(ms) {
1303
+ return this.driver_.schedule(
1304
+ new command.Command(command.Name.SET_SCRIPT_TIMEOUT).
1305
+ setParameter('ms', ms < 0 ? 0 : ms),
1306
+ 'WebDriver.manage().timeouts().setScriptTimeout(' + ms + ')');
1307
+ }
1308
+
1309
+ /**
1310
+ * Sets the amount of time to wait for a page load to complete before
1311
+ * returning an error. If the timeout is negative, page loads may be
1312
+ * indefinite.
1313
+ *
1314
+ * @param {number} ms The amount of time to wait, in milliseconds.
1315
+ * @return {!promise.Promise<void>} A promise that will be resolved
1316
+ * when the timeout has been set.
1317
+ */
1318
+ pageLoadTimeout(ms) {
1319
+ return this.driver_.schedule(
1320
+ new command.Command(command.Name.SET_TIMEOUT).
1321
+ setParameter('type', 'page load').
1322
+ setParameter('ms', ms),
1323
+ 'WebDriver.manage().timeouts().pageLoadTimeout(' + ms + ')');
1324
+ }
1325
+ }
1326
+
1327
+
1328
+ /**
1329
+ * An interface for managing the current window.
1330
+ *
1331
+ * This class should never be instantiated directly. Insead, obtain an instance
1332
+ * with
1333
+ *
1334
+ * webdriver.manage().window()
1335
+ *
1336
+ * @see WebDriver#manage()
1337
+ * @see Options#window()
1338
+ */
1339
+ class Window {
1340
+ /**
1341
+ * @param {!WebDriver} driver The parent driver.
1342
+ * @private
1343
+ */
1344
+ constructor(driver) {
1345
+ /** @private {!WebDriver} */
1346
+ this.driver_ = driver;
1347
+ }
1348
+
1349
+ /**
1350
+ * Retrieves the window's current position, relative to the top left corner of
1351
+ * the screen.
1352
+ * @return {!promise.Promise.<{x: number, y: number}>} A promise
1353
+ * that will be resolved with the window's position in the form of a
1354
+ * {x:number, y:number} object literal.
1355
+ */
1356
+ getPosition() {
1357
+ return this.driver_.schedule(
1358
+ new command.Command(command.Name.GET_WINDOW_POSITION).
1359
+ setParameter('windowHandle', 'current'),
1360
+ 'WebDriver.manage().window().getPosition()');
1361
+ }
1362
+
1363
+ /**
1364
+ * Repositions the current window.
1365
+ * @param {number} x The desired horizontal position, relative to the left
1366
+ * side of the screen.
1367
+ * @param {number} y The desired vertical position, relative to the top of the
1368
+ * of the screen.
1369
+ * @return {!promise.Promise<void>} A promise that will be resolved
1370
+ * when the command has completed.
1371
+ */
1372
+ setPosition(x, y) {
1373
+ return this.driver_.schedule(
1374
+ new command.Command(command.Name.SET_WINDOW_POSITION).
1375
+ setParameter('windowHandle', 'current').
1376
+ setParameter('x', x).
1377
+ setParameter('y', y),
1378
+ 'WebDriver.manage().window().setPosition(' + x + ', ' + y + ')');
1379
+ }
1380
+
1381
+ /**
1382
+ * Retrieves the window's current size.
1383
+ * @return {!promise.Promise<{width: number, height: number}>} A
1384
+ * promise that will be resolved with the window's size in the form of a
1385
+ * {width:number, height:number} object literal.
1386
+ */
1387
+ getSize() {
1388
+ return this.driver_.schedule(
1389
+ new command.Command(command.Name.GET_WINDOW_SIZE).
1390
+ setParameter('windowHandle', 'current'),
1391
+ 'WebDriver.manage().window().getSize()');
1392
+ }
1393
+
1394
+ /**
1395
+ * Resizes the current window.
1396
+ * @param {number} width The desired window width.
1397
+ * @param {number} height The desired window height.
1398
+ * @return {!promise.Promise<void>} A promise that will be resolved
1399
+ * when the command has completed.
1400
+ */
1401
+ setSize(width, height) {
1402
+ return this.driver_.schedule(
1403
+ new command.Command(command.Name.SET_WINDOW_SIZE).
1404
+ setParameter('windowHandle', 'current').
1405
+ setParameter('width', width).
1406
+ setParameter('height', height),
1407
+ 'WebDriver.manage().window().setSize(' + width + ', ' + height + ')');
1408
+ }
1409
+
1410
+ /**
1411
+ * Maximizes the current window.
1412
+ * @return {!promise.Promise<void>} A promise that will be resolved
1413
+ * when the command has completed.
1414
+ */
1415
+ maximize() {
1416
+ return this.driver_.schedule(
1417
+ new command.Command(command.Name.MAXIMIZE_WINDOW).
1418
+ setParameter('windowHandle', 'current'),
1419
+ 'WebDriver.manage().window().maximize()');
1420
+ }
1421
+ }
1422
+
1423
+
1424
+ /**
1425
+ * Interface for managing WebDriver log records.
1426
+ *
1427
+ * This class should never be instantiated directly. Instead, obtain an
1428
+ * instance with
1429
+ *
1430
+ * webdriver.manage().logs()
1431
+ *
1432
+ * @see WebDriver#manage()
1433
+ * @see Options#logs()
1434
+ */
1435
+ class Logs {
1436
+ /**
1437
+ * @param {!WebDriver} driver The parent driver.
1438
+ * @private
1439
+ */
1440
+ constructor(driver) {
1441
+ /** @private {!WebDriver} */
1442
+ this.driver_ = driver;
1443
+ }
1444
+
1445
+ /**
1446
+ * Fetches available log entries for the given type.
1447
+ *
1448
+ * Note that log buffers are reset after each call, meaning that available
1449
+ * log entries correspond to those entries not yet returned for a given log
1450
+ * type. In practice, this means that this call will return the available log
1451
+ * entries since the last call, or from the start of the session.
1452
+ *
1453
+ * @param {!logging.Type} type The desired log type.
1454
+ * @return {!promise.Promise.<!Array.<!logging.Entry>>} A
1455
+ * promise that will resolve to a list of log entries for the specified
1456
+ * type.
1457
+ */
1458
+ get(type) {
1459
+ let cmd = new command.Command(command.Name.GET_LOG).
1460
+ setParameter('type', type);
1461
+ return this.driver_.schedule(
1462
+ cmd, 'WebDriver.manage().logs().get(' + type + ')').
1463
+ then(function(entries) {
1464
+ return entries.map(function(entry) {
1465
+ if (!(entry instanceof logging.Entry)) {
1466
+ return new logging.Entry(
1467
+ entry['level'], entry['message'], entry['timestamp'],
1468
+ entry['type']);
1469
+ }
1470
+ return entry;
1471
+ });
1472
+ });
1473
+ }
1474
+
1475
+ /**
1476
+ * Retrieves the log types available to this driver.
1477
+ * @return {!promise.Promise<!Array<!logging.Type>>} A
1478
+ * promise that will resolve to a list of available log types.
1479
+ */
1480
+ getAvailableLogTypes() {
1481
+ return this.driver_.schedule(
1482
+ new command.Command(command.Name.GET_AVAILABLE_LOG_TYPES),
1483
+ 'WebDriver.manage().logs().getAvailableLogTypes()');
1484
+ }
1485
+ }
1486
+
1487
+
1488
+ /**
1489
+ * An interface for changing the focus of the driver to another frame or window.
1490
+ *
1491
+ * This class should never be instantiated directly. Instead, obtain an
1492
+ * instance with
1493
+ *
1494
+ * webdriver.switchTo()
1495
+ *
1496
+ * @see WebDriver#switchTo()
1497
+ */
1498
+ class TargetLocator {
1499
+ /**
1500
+ * @param {!WebDriver} driver The parent driver.
1501
+ * @private
1502
+ */
1503
+ constructor(driver) {
1504
+ /** @private {!WebDriver} */
1505
+ this.driver_ = driver;
1506
+ }
1507
+
1508
+ /**
1509
+ * Schedules a command retrieve the {@code document.activeElement} element on
1510
+ * the current document, or {@code document.body} if activeElement is not
1511
+ * available.
1512
+ * @return {!WebElementPromise} The active element.
1513
+ */
1514
+ activeElement() {
1515
+ var id = this.driver_.schedule(
1516
+ new command.Command(command.Name.GET_ACTIVE_ELEMENT),
1517
+ 'WebDriver.switchTo().activeElement()');
1518
+ return new WebElementPromise(this.driver_, id);
1519
+ }
1520
+
1521
+ /**
1522
+ * Schedules a command to switch focus of all future commands to the topmost
1523
+ * frame on the page.
1524
+ * @return {!promise.Promise<void>} A promise that will be resolved
1525
+ * when the driver has changed focus to the default content.
1526
+ */
1527
+ defaultContent() {
1528
+ return this.driver_.schedule(
1529
+ new command.Command(command.Name.SWITCH_TO_FRAME).
1530
+ setParameter('id', null),
1531
+ 'WebDriver.switchTo().defaultContent()');
1532
+ }
1533
+
1534
+ /**
1535
+ * Schedules a command to switch the focus of all future commands to another
1536
+ * frame on the page. The target frame may be specified as one of the
1537
+ * following:
1538
+ *
1539
+ * - A number that specifies a (zero-based) index into [window.frames](
1540
+ * https://developer.mozilla.org/en-US/docs/Web/API/Window.frames).
1541
+ * - A {@link WebElement} reference, which correspond to a `frame` or `iframe`
1542
+ * DOM element.
1543
+ * - The `null` value, to select the topmost frame on the page. Passing `null`
1544
+ * is the same as calling {@link #defaultContent defaultContent()}.
1545
+ *
1546
+ * If the specified frame can not be found, the returned promise will be
1547
+ * rejected with a {@linkplain error.NoSuchFrameError}.
1548
+ *
1549
+ * @param {(number|WebElement|null)} id The frame locator.
1550
+ * @return {!promise.Promise<void>} A promise that will be resolved
1551
+ * when the driver has changed focus to the specified frame.
1552
+ */
1553
+ frame(id) {
1554
+ return this.driver_.schedule(
1555
+ new command.Command(command.Name.SWITCH_TO_FRAME).
1556
+ setParameter('id', id),
1557
+ 'WebDriver.switchTo().frame(' + id + ')');
1558
+ }
1559
+
1560
+ /**
1561
+ * Schedules a command to switch the focus of all future commands to another
1562
+ * window. Windows may be specified by their {@code window.name} attribute or
1563
+ * by its handle (as returned by {@link WebDriver#getWindowHandles}).
1564
+ *
1565
+ * If the specified window cannot be found, the returned promise will be
1566
+ * rejected with a {@linkplain error.NoSuchWindowError}.
1567
+ *
1568
+ * @param {string} nameOrHandle The name or window handle of the window to
1569
+ * switch focus to.
1570
+ * @return {!promise.Promise<void>} A promise that will be resolved
1571
+ * when the driver has changed focus to the specified window.
1572
+ */
1573
+ window(nameOrHandle) {
1574
+ return this.driver_.schedule(
1575
+ new command.Command(command.Name.SWITCH_TO_WINDOW).
1576
+ setParameter('name', nameOrHandle),
1577
+ 'WebDriver.switchTo().window(' + nameOrHandle + ')');
1578
+ }
1579
+
1580
+ /**
1581
+ * Schedules a command to change focus to the active modal dialog, such as
1582
+ * those opened by `window.alert()`, `window.confirm()`, and
1583
+ * `window.prompt()`. The returned promise will be rejected with a
1584
+ * {@linkplain error.NoSuchAlertError} if there are no open alerts.
1585
+ *
1586
+ * @return {!AlertPromise} The open alert.
1587
+ */
1588
+ alert() {
1589
+ var text = this.driver_.schedule(
1590
+ new command.Command(command.Name.GET_ALERT_TEXT),
1591
+ 'WebDriver.switchTo().alert()');
1592
+ var driver = this.driver_;
1593
+ return new AlertPromise(driver, text.then(function(text) {
1594
+ return new Alert(driver, text);
1595
+ }));
1596
+ }
1597
+ }
1598
+
1599
+
1600
+ //////////////////////////////////////////////////////////////////////////////
1601
+ //
1602
+ // WebElement
1603
+ //
1604
+ //////////////////////////////////////////////////////////////////////////////
1605
+
1606
+
1607
+ const LEGACY_ELEMENT_ID_KEY = 'ELEMENT';
1608
+ const ELEMENT_ID_KEY = 'element-6066-11e4-a52e-4f735466cecf';
1609
+
1610
+
1611
+ /**
1612
+ * Represents a DOM element. WebElements can be found by searching from the
1613
+ * document root using a {@link WebDriver} instance, or by searching
1614
+ * under another WebElement:
1615
+ *
1616
+ * driver.get('http://www.google.com');
1617
+ * var searchForm = driver.findElement(By.tagName('form'));
1618
+ * var searchBox = searchForm.findElement(By.name('q'));
1619
+ * searchBox.sendKeys('webdriver');
1620
+ */
1621
+ class WebElement {
1622
+ /**
1623
+ * @param {!WebDriver} driver the parent WebDriver instance for this element.
1624
+ * @param {(!IThenable<string>|string)} id The server-assigned opaque ID for
1625
+ * the underlying DOM element.
1626
+ */
1627
+ constructor(driver, id) {
1628
+ /** @private {!WebDriver} */
1629
+ this.driver_ = driver;
1630
+
1631
+ /** @private {!promise.Promise<string>} */
1632
+ this.id_ = promise.fulfilled(id);
1633
+ }
1634
+
1635
+ /**
1636
+ * @param {string} id The raw ID.
1637
+ * @param {boolean=} opt_noLegacy Whether to exclude the legacy element key.
1638
+ * @return {!Object} The element ID for use with WebDriver's wire protocol.
1639
+ */
1640
+ static buildId(id, opt_noLegacy) {
1641
+ return opt_noLegacy
1642
+ ? {[ELEMENT_ID_KEY]: id}
1643
+ : {[ELEMENT_ID_KEY]: id, [LEGACY_ELEMENT_ID_KEY]: id};
1644
+ }
1645
+
1646
+ /**
1647
+ * Extracts the encoded WebElement ID from the object.
1648
+ *
1649
+ * @param {?} obj The object to extract the ID from.
1650
+ * @return {string} the extracted ID.
1651
+ * @throws {TypeError} if the object is not a valid encoded ID.
1652
+ */
1653
+ static extractId(obj) {
1654
+ if (obj && typeof obj === 'object') {
1655
+ if (typeof obj[ELEMENT_ID_KEY] === 'string') {
1656
+ return obj[ELEMENT_ID_KEY];
1657
+ } else if (typeof obj[LEGACY_ELEMENT_ID_KEY] === 'string') {
1658
+ return obj[LEGACY_ELEMENT_ID_KEY];
1659
+ }
1660
+ }
1661
+ throw new TypeError('object is not a WebElement ID');
1662
+ }
1663
+
1664
+ /**
1665
+ * @param {?} obj the object to test.
1666
+ * @return {boolean} whether the object is a valid encoded WebElement ID.
1667
+ */
1668
+ static isId(obj) {
1669
+ return obj && typeof obj === 'object'
1670
+ && (typeof obj[ELEMENT_ID_KEY] === 'string'
1671
+ || typeof obj[LEGACY_ELEMENT_ID_KEY] === 'string');
1672
+ }
1673
+
1674
+ /**
1675
+ * Compares two WebElements for equality.
1676
+ *
1677
+ * @param {!WebElement} a A WebElement.
1678
+ * @param {!WebElement} b A WebElement.
1679
+ * @return {!promise.Promise<boolean>} A promise that will be
1680
+ * resolved to whether the two WebElements are equal.
1681
+ */
1682
+ static equals(a, b) {
1683
+ if (a === b) {
1684
+ return promise.fulfilled(true);
1685
+ }
1686
+ let ids = [a.getId(), b.getId()];
1687
+ return promise.all(ids).then(function(ids) {
1688
+ // If the two element's have the same ID, they should be considered
1689
+ // equal. Otherwise, they may still be equivalent, but we'll need to
1690
+ // ask the server to check for us.
1691
+ if (ids[0] === ids[1]) {
1692
+ return true;
1693
+ }
1694
+
1695
+ let cmd = new command.Command(command.Name.ELEMENT_EQUALS);
1696
+ cmd.setParameter('id', ids[0]);
1697
+ cmd.setParameter('other', ids[1]);
1698
+ return a.driver_.schedule(cmd, 'WebElement.equals()');
1699
+ });
1700
+ }
1701
+
1702
+ /** @return {!WebDriver} The parent driver for this instance. */
1703
+ getDriver() {
1704
+ return this.driver_;
1705
+ }
1706
+
1707
+ /**
1708
+ * @return {!promise.Promise<string>} A promise that resolves to
1709
+ * the server-assigned opaque ID assigned to this element.
1710
+ */
1711
+ getId() {
1712
+ return this.id_;
1713
+ }
1714
+
1715
+ /**
1716
+ * @deprecated Use {@link #getId()} instead.
1717
+ */
1718
+ getRawId() {
1719
+ return this.getId();
1720
+ }
1721
+
1722
+ /**
1723
+ * @return {!Object} Returns the serialized representation of this WebElement.
1724
+ */
1725
+ [Symbols.serialize]() {
1726
+ return this.getId().then(WebElement.buildId);
1727
+ }
1728
+
1729
+ /**
1730
+ * Schedules a command that targets this element with the parent WebDriver
1731
+ * instance. Will ensure this element's ID is included in the command
1732
+ * parameters under the "id" key.
1733
+ *
1734
+ * @param {!command.Command} command The command to schedule.
1735
+ * @param {string} description A description of the command for debugging.
1736
+ * @return {!promise.Promise<T>} A promise that will be resolved
1737
+ * with the command result.
1738
+ * @template T
1739
+ * @see WebDriver#schedule
1740
+ * @private
1741
+ */
1742
+ schedule_(command, description) {
1743
+ command.setParameter('id', this.getId());
1744
+ return this.driver_.schedule(command, description);
1745
+ }
1746
+
1747
+ /**
1748
+ * Schedule a command to find a descendant of this element. If the element
1749
+ * cannot be found, the returned promise will be rejected with a
1750
+ * {@linkplain error.NoSuchElementError NoSuchElementError}.
1751
+ *
1752
+ * The search criteria for an element may be defined using one of the static
1753
+ * factories on the {@link by.By} class, or as a short-hand
1754
+ * {@link ./by.ByHash} object. For example, the following two statements
1755
+ * are equivalent:
1756
+ *
1757
+ * var e1 = element.findElement(By.id('foo'));
1758
+ * var e2 = element.findElement({id:'foo'});
1759
+ *
1760
+ * You may also provide a custom locator function, which takes as input this
1761
+ * instance and returns a {@link WebElement}, or a promise that will resolve
1762
+ * to a WebElement. If the returned promise resolves to an array of
1763
+ * WebElements, WebDriver will use the first element. For example, to find the
1764
+ * first visible link on a page, you could write:
1765
+ *
1766
+ * var link = element.findElement(firstVisibleLink);
1767
+ *
1768
+ * function firstVisibleLink(element) {
1769
+ * var links = element.findElements(By.tagName('a'));
1770
+ * return promise.filter(links, function(link) {
1771
+ * return link.isDisplayed();
1772
+ * });
1773
+ * }
1774
+ *
1775
+ * @param {!(by.By|Function)} locator The locator strategy to use when
1776
+ * searching for the element.
1777
+ * @return {!WebElementPromise} A WebElement that can be used to issue
1778
+ * commands against the located element. If the element is not found, the
1779
+ * element will be invalidated and all scheduled commands aborted.
1780
+ */
1781
+ findElement(locator) {
1782
+ locator = by.checkedLocator(locator);
1783
+ let id;
1784
+ if (typeof locator === 'function') {
1785
+ id = this.driver_.findElementInternal_(locator, this);
1786
+ } else {
1787
+ let cmd = new command.Command(
1788
+ command.Name.FIND_CHILD_ELEMENT).
1789
+ setParameter('using', locator.using).
1790
+ setParameter('value', locator.value);
1791
+ id = this.schedule_(cmd, 'WebElement.findElement(' + locator + ')');
1792
+ }
1793
+ return new WebElementPromise(this.driver_, id);
1794
+ }
1795
+
1796
+ /**
1797
+ * Schedules a command to test if there is at least one descendant of this
1798
+ * element that matches the given search criteria.
1799
+ *
1800
+ * @param {!(by.By|Function)} locator The locator strategy to use when
1801
+ * searching for the element.
1802
+ * @return {!promise.Promise<boolean>} A promise that will be
1803
+ * resolved with whether an element could be located on the page.
1804
+ * @deprecated This method will be removed in Selenium 3.0 for consistency
1805
+ * with the other Selenium language bindings. This method is equivalent
1806
+ * to
1807
+ *
1808
+ * element.findElements(locator).then(e => !!e.length);
1809
+ */
1810
+ isElementPresent(locator) {
1811
+ return this.findElements(locator).then(function(result) {
1812
+ return !!result.length;
1813
+ });
1814
+ }
1815
+
1816
+ /**
1817
+ * Schedules a command to find all of the descendants of this element that
1818
+ * match the given search criteria.
1819
+ *
1820
+ * @param {!(by.By|Function)} locator The locator strategy to use when
1821
+ * searching for the element.
1822
+ * @return {!promise.Promise<!Array<!WebElement>>} A
1823
+ * promise that will resolve to an array of WebElements.
1824
+ */
1825
+ findElements(locator) {
1826
+ locator = by.checkedLocator(locator);
1827
+ let id;
1828
+ if (typeof locator === 'function') {
1829
+ return this.driver_.findElementsInternal_(locator, this);
1830
+ } else {
1831
+ var cmd = new command.Command(
1832
+ command.Name.FIND_CHILD_ELEMENTS).
1833
+ setParameter('using', locator.using).
1834
+ setParameter('value', locator.value);
1835
+ return this.schedule_(cmd, 'WebElement.findElements(' + locator + ')');
1836
+ }
1837
+ }
1838
+
1839
+ /**
1840
+ * Schedules a command to click on this element.
1841
+ * @return {!promise.Promise<void>} A promise that will be resolved
1842
+ * when the click command has completed.
1843
+ */
1844
+ click() {
1845
+ return this.schedule_(
1846
+ new command.Command(command.Name.CLICK_ELEMENT),
1847
+ 'WebElement.click()');
1848
+ }
1849
+
1850
+ /**
1851
+ * Schedules a command to type a sequence on the DOM element represented by
1852
+ * this instance.
1853
+ *
1854
+ * Modifier keys (SHIFT, CONTROL, ALT, META) are stateful; once a modifier is
1855
+ * processed in the keysequence, that key state is toggled until one of the
1856
+ * following occurs:
1857
+ *
1858
+ * - The modifier key is encountered again in the sequence. At this point the
1859
+ * state of the key is toggled (along with the appropriate keyup/down
1860
+ * events).
1861
+ * - The {@link input.Key.NULL} key is encountered in the sequence. When
1862
+ * this key is encountered, all modifier keys current in the down state are
1863
+ * released (with accompanying keyup events). The NULL key can be used to
1864
+ * simulate common keyboard shortcuts:
1865
+ *
1866
+ * element.sendKeys("text was",
1867
+ * Key.CONTROL, "a", Key.NULL,
1868
+ * "now text is");
1869
+ * // Alternatively:
1870
+ * element.sendKeys("text was",
1871
+ * Key.chord(Key.CONTROL, "a"),
1872
+ * "now text is");
1873
+ *
1874
+ * - The end of the keysequence is encountered. When there are no more keys
1875
+ * to type, all depressed modifier keys are released (with accompanying
1876
+ * keyup events).
1877
+ *
1878
+ * If this element is a file input ({@code <input type="file">}), the
1879
+ * specified key sequence should specify the path to the file to attach to
1880
+ * the element. This is analgous to the user clicking "Browse..." and entering
1881
+ * the path into the file select dialog.
1882
+ *
1883
+ * var form = driver.findElement(By.css('form'));
1884
+ * var element = form.findElement(By.css('input[type=file]'));
1885
+ * element.sendKeys('/path/to/file.txt');
1886
+ * form.submit();
1887
+ *
1888
+ * For uploads to function correctly, the entered path must reference a file
1889
+ * on the _browser's_ machine, not the local machine running this script. When
1890
+ * running against a remote Selenium server, a {@link input.FileDetector}
1891
+ * may be used to transparently copy files to the remote machine before
1892
+ * attempting to upload them in the browser.
1893
+ *
1894
+ * __Note:__ On browsers where native keyboard events are not supported
1895
+ * (e.g. Firefox on OS X), key events will be synthesized. Special
1896
+ * punctionation keys will be synthesized according to a standard QWERTY en-us
1897
+ * keyboard layout.
1898
+ *
1899
+ * @param {...(string|!promise.Promise<string>)} var_args The
1900
+ * sequence of keys to type. All arguments will be joined into a single
1901
+ * sequence.
1902
+ * @return {!promise.Promise<void>} A promise that will be resolved
1903
+ * when all keys have been typed.
1904
+ */
1905
+ sendKeys(var_args) {
1906
+ // Coerce every argument to a string. This protects us from users that
1907
+ // ignore the jsdoc and give us a number (which ends up causing problems on
1908
+ // the server, which requires strings).
1909
+ let keys = promise.all(Array.prototype.slice.call(arguments, 0)).
1910
+ then(keys => {
1911
+ let ret = [];
1912
+ keys.forEach(key => {
1913
+ if (typeof key !== 'string') {
1914
+ key = String(key);
1915
+ }
1916
+
1917
+ // The W3C protocol requires keys to be specified as an array where
1918
+ // each element is a single key.
1919
+ ret.push.apply(ret, key.split(''));
1920
+ });
1921
+ return ret;
1922
+ });
1923
+ if (!this.driver_.fileDetector_) {
1924
+ return this.schedule_(
1925
+ new command.Command(command.Name.SEND_KEYS_TO_ELEMENT).
1926
+ setParameter('value', keys),
1927
+ 'WebElement.sendKeys()');
1928
+ }
1929
+
1930
+ // Suppress unhandled rejection errors until the flow executes the command.
1931
+ keys.catch(function() {});
1932
+
1933
+ var element = this;
1934
+ return this.driver_.flow_.execute(function() {
1935
+ return keys.then(function(keys) {
1936
+ return element.driver_.fileDetector_
1937
+ .handleFile(element.driver_, keys.join(''));
1938
+ }).then(function(keys) {
1939
+ return element.schedule_(
1940
+ new command.Command(command.Name.SEND_KEYS_TO_ELEMENT).
1941
+ setParameter('value', [keys]),
1942
+ 'WebElement.sendKeys()');
1943
+ });
1944
+ }, 'WebElement.sendKeys()');
1945
+ }
1946
+
1947
+ /**
1948
+ * Schedules a command to query for the tag/node name of this element.
1949
+ * @return {!promise.Promise<string>} A promise that will be
1950
+ * resolved with the element's tag name.
1951
+ */
1952
+ getTagName() {
1953
+ return this.schedule_(
1954
+ new command.Command(command.Name.GET_ELEMENT_TAG_NAME),
1955
+ 'WebElement.getTagName()');
1956
+ }
1957
+
1958
+ /**
1959
+ * Schedules a command to query for the computed style of the element
1960
+ * represented by this instance. If the element inherits the named style from
1961
+ * its parent, the parent will be queried for its value. Where possible, color
1962
+ * values will be converted to their hex representation (e.g. #00ff00 instead
1963
+ * of rgb(0, 255, 0)).
1964
+ *
1965
+ * _Warning:_ the value returned will be as the browser interprets it, so
1966
+ * it may be tricky to form a proper assertion.
1967
+ *
1968
+ * @param {string} cssStyleProperty The name of the CSS style property to look
1969
+ * up.
1970
+ * @return {!promise.Promise<string>} A promise that will be
1971
+ * resolved with the requested CSS value.
1972
+ */
1973
+ getCssValue(cssStyleProperty) {
1974
+ var name = command.Name.GET_ELEMENT_VALUE_OF_CSS_PROPERTY;
1975
+ return this.schedule_(
1976
+ new command.Command(name).
1977
+ setParameter('propertyName', cssStyleProperty),
1978
+ 'WebElement.getCssValue(' + cssStyleProperty + ')');
1979
+ }
1980
+
1981
+ /**
1982
+ * Schedules a command to query for the value of the given attribute of the
1983
+ * element. Will return the current value, even if it has been modified after
1984
+ * the page has been loaded. More exactly, this method will return the value
1985
+ * of the given attribute, unless that attribute is not present, in which case
1986
+ * the value of the property with the same name is returned. If neither value
1987
+ * is set, null is returned (for example, the "value" property of a textarea
1988
+ * element). The "style" attribute is converted as best can be to a
1989
+ * text representation with a trailing semi-colon. The following are deemed to
1990
+ * be "boolean" attributes and will return either "true" or null:
1991
+ *
1992
+ * async, autofocus, autoplay, checked, compact, complete, controls, declare,
1993
+ * defaultchecked, defaultselected, defer, disabled, draggable, ended,
1994
+ * formnovalidate, hidden, indeterminate, iscontenteditable, ismap, itemscope,
1995
+ * loop, multiple, muted, nohref, noresize, noshade, novalidate, nowrap, open,
1996
+ * paused, pubdate, readonly, required, reversed, scoped, seamless, seeking,
1997
+ * selected, spellcheck, truespeed, willvalidate
1998
+ *
1999
+ * Finally, the following commonly mis-capitalized attribute/property names
2000
+ * are evaluated as expected:
2001
+ *
2002
+ * - "class"
2003
+ * - "readonly"
2004
+ *
2005
+ * @param {string} attributeName The name of the attribute to query.
2006
+ * @return {!promise.Promise<?string>} A promise that will be
2007
+ * resolved with the attribute's value. The returned value will always be
2008
+ * either a string or null.
2009
+ */
2010
+ getAttribute(attributeName) {
2011
+ return this.schedule_(
2012
+ new command.Command(command.Name.GET_ELEMENT_ATTRIBUTE).
2013
+ setParameter('name', attributeName),
2014
+ 'WebElement.getAttribute(' + attributeName + ')');
2015
+ }
2016
+
2017
+ /**
2018
+ * Get the visible (i.e. not hidden by CSS) innerText of this element,
2019
+ * including sub-elements, without any leading or trailing whitespace.
2020
+ *
2021
+ * @return {!promise.Promise<string>} A promise that will be
2022
+ * resolved with the element's visible text.
2023
+ */
2024
+ getText() {
2025
+ return this.schedule_(
2026
+ new command.Command(command.Name.GET_ELEMENT_TEXT),
2027
+ 'WebElement.getText()');
2028
+ }
2029
+
2030
+ /**
2031
+ * Schedules a command to compute the size of this element's bounding box, in
2032
+ * pixels.
2033
+ * @return {!promise.Promise.<{width: number, height: number}>} A
2034
+ * promise that will be resolved with the element's size as a
2035
+ * {@code {width:number, height:number}} object.
2036
+ */
2037
+ getSize() {
2038
+ return this.schedule_(
2039
+ new command.Command(command.Name.GET_ELEMENT_SIZE),
2040
+ 'WebElement.getSize()');
2041
+ }
2042
+
2043
+ /**
2044
+ * Schedules a command to compute the location of this element in page space.
2045
+ * @return {!promise.Promise.<{x: number, y: number}>} A promise that
2046
+ * will be resolved to the element's location as a
2047
+ * {@code {x:number, y:number}} object.
2048
+ */
2049
+ getLocation() {
2050
+ return this.schedule_(
2051
+ new command.Command(command.Name.GET_ELEMENT_LOCATION),
2052
+ 'WebElement.getLocation()');
2053
+ }
2054
+
2055
+ /**
2056
+ * Schedules a command to query whether the DOM element represented by this
2057
+ * instance is enabled, as dicted by the {@code disabled} attribute.
2058
+ * @return {!promise.Promise<boolean>} A promise that will be
2059
+ * resolved with whether this element is currently enabled.
2060
+ */
2061
+ isEnabled() {
2062
+ return this.schedule_(
2063
+ new command.Command(command.Name.IS_ELEMENT_ENABLED),
2064
+ 'WebElement.isEnabled()');
2065
+ }
2066
+
2067
+ /**
2068
+ * Schedules a command to query whether this element is selected.
2069
+ * @return {!promise.Promise<boolean>} A promise that will be
2070
+ * resolved with whether this element is currently selected.
2071
+ */
2072
+ isSelected() {
2073
+ return this.schedule_(
2074
+ new command.Command(command.Name.IS_ELEMENT_SELECTED),
2075
+ 'WebElement.isSelected()');
2076
+ }
2077
+
2078
+ /**
2079
+ * Schedules a command to submit the form containing this element (or this
2080
+ * element if it is a FORM element). This command is a no-op if the element is
2081
+ * not contained in a form.
2082
+ * @return {!promise.Promise<void>} A promise that will be resolved
2083
+ * when the form has been submitted.
2084
+ */
2085
+ submit() {
2086
+ return this.schedule_(
2087
+ new command.Command(command.Name.SUBMIT_ELEMENT),
2088
+ 'WebElement.submit()');
2089
+ }
2090
+
2091
+ /**
2092
+ * Schedules a command to clear the `value` of this element. This command has
2093
+ * no effect if the underlying DOM element is neither a text INPUT element
2094
+ * nor a TEXTAREA element.
2095
+ * @return {!promise.Promise<void>} A promise that will be resolved
2096
+ * when the element has been cleared.
2097
+ */
2098
+ clear() {
2099
+ return this.schedule_(
2100
+ new command.Command(command.Name.CLEAR_ELEMENT),
2101
+ 'WebElement.clear()');
2102
+ }
2103
+
2104
+ /**
2105
+ * Schedules a command to test whether this element is currently displayed.
2106
+ * @return {!promise.Promise<boolean>} A promise that will be
2107
+ * resolved with whether this element is currently visible on the page.
2108
+ */
2109
+ isDisplayed() {
2110
+ return this.schedule_(
2111
+ new command.Command(command.Name.IS_ELEMENT_DISPLAYED),
2112
+ 'WebElement.isDisplayed()');
2113
+ }
2114
+
2115
+ /**
2116
+ * Take a screenshot of the visible region encompassed by this element's
2117
+ * bounding rectangle.
2118
+ *
2119
+ * @param {boolean=} opt_scroll Optional argument that indicates whether the
2120
+ * element should be scrolled into view before taking a screenshot.
2121
+ * Defaults to false.
2122
+ * @return {!promise.Promise<string>} A promise that will be
2123
+ * resolved to the screenshot as a base-64 encoded PNG.
2124
+ */
2125
+ takeScreenshot(opt_scroll) {
2126
+ var scroll = !!opt_scroll;
2127
+ return this.schedule_(
2128
+ new command.Command(command.Name.TAKE_ELEMENT_SCREENSHOT)
2129
+ .setParameter('scroll', scroll),
2130
+ 'WebElement.takeScreenshot(' + scroll + ')');
2131
+ }
2132
+
2133
+ /**
2134
+ * Schedules a command to retrieve the outer HTML of this element.
2135
+ * @return {!promise.Promise<string>} A promise that will be
2136
+ * resolved with the element's outer HTML.
2137
+ * @deprecated Use {@link WebDriver#executeScript()}
2138
+ */
2139
+ getOuterHtml() {
2140
+ return this.driver_.executeScript(function() {
2141
+ var element = /** @type {!Element} */(arguments[0]);
2142
+ if ('outerHTML' in element) {
2143
+ return element.outerHTML;
2144
+ } else {
2145
+ var div = element.ownerDocument.createElement('div');
2146
+ div.appendChild(element.cloneNode(true));
2147
+ return div.innerHTML;
2148
+ }
2149
+ }, this);
2150
+ }
2151
+
2152
+ /**
2153
+ * Schedules a command to retrieve the inner HTML of this element.
2154
+ * @return {!promise.Promise<string>} A promise that will be
2155
+ * resolved with the element's inner HTML.
2156
+ * @deprecated Use {@link WebDriver#executeScript()}
2157
+ */
2158
+ getInnerHtml() {
2159
+ return this.driver_.executeScript('return arguments[0].innerHTML', this);
2160
+ }
2161
+ }
2162
+
2163
+
2164
+ /**
2165
+ * WebElementPromise is a promise that will be fulfilled with a WebElement.
2166
+ * This serves as a forward proxy on WebElement, allowing calls to be
2167
+ * scheduled without directly on this instance before the underlying
2168
+ * WebElement has been fulfilled. In other words, the following two statements
2169
+ * are equivalent:
2170
+ *
2171
+ * driver.findElement({id: 'my-button'}).click();
2172
+ * driver.findElement({id: 'my-button'}).then(function(el) {
2173
+ * return el.click();
2174
+ * });
2175
+ *
2176
+ * @implements {promise.Thenable<!WebElement>}
2177
+ * @final
2178
+ */
2179
+ class WebElementPromise extends WebElement {
2180
+ /**
2181
+ * @param {!WebDriver} driver The parent WebDriver instance for this
2182
+ * element.
2183
+ * @param {!promise.Promise<!WebElement>} el A promise
2184
+ * that will resolve to the promised element.
2185
+ */
2186
+ constructor(driver, el) {
2187
+ super(driver, 'unused');
2188
+
2189
+ /** @override */
2190
+ this.cancel = el.cancel.bind(el);
2191
+
2192
+ /** @override */
2193
+ this.isPending = el.isPending.bind(el);
2194
+
2195
+ /** @override */
2196
+ this.then = el.then.bind(el);
2197
+
2198
+ /** @override */
2199
+ this.catch = el.catch.bind(el);
2200
+
2201
+ /** @override */
2202
+ this.thenCatch = el.catch.bind(el);
2203
+
2204
+ /** @override */
2205
+ this.finally = el.finally.bind(el);
2206
+
2207
+ /** @override */
2208
+ this.thenFinally = el.finally.bind(el);
2209
+
2210
+ /**
2211
+ * Defers returning the element ID until the wrapped WebElement has been
2212
+ * resolved.
2213
+ * @override
2214
+ */
2215
+ this.getId = function() {
2216
+ return el.then(function(el) {
2217
+ return el.getId();
2218
+ });
2219
+ };
2220
+ }
2221
+ }
2222
+ promise.Thenable.addImplementation(WebElementPromise);
2223
+
2224
+
2225
+ //////////////////////////////////////////////////////////////////////////////
2226
+ //
2227
+ // Alert
2228
+ //
2229
+ //////////////////////////////////////////////////////////////////////////////
2230
+
2231
+
2232
+ /**
2233
+ * Represents a modal dialog such as {@code alert}, {@code confirm}, or
2234
+ * {@code prompt}. Provides functions to retrieve the message displayed with
2235
+ * the alert, accept or dismiss the alert, and set the response text (in the
2236
+ * case of {@code prompt}).
2237
+ */
2238
+ class Alert {
2239
+ /**
2240
+ * @param {!WebDriver} driver The driver controlling the browser this alert
2241
+ * is attached to.
2242
+ * @param {string} text The message text displayed with this alert.
2243
+ */
2244
+ constructor(driver, text) {
2245
+ /** @private {!WebDriver} */
2246
+ this.driver_ = driver;
2247
+
2248
+ /** @private {!promise.Promise<string>} */
2249
+ this.text_ = promise.fulfilled(text);
2250
+ }
2251
+
2252
+ /**
2253
+ * Retrieves the message text displayed with this alert. For instance, if the
2254
+ * alert were opened with alert("hello"), then this would return "hello".
2255
+ *
2256
+ * @return {!promise.Promise<string>} A promise that will be
2257
+ * resolved to the text displayed with this alert.
2258
+ */
2259
+ getText() {
2260
+ return this.text_;
2261
+ }
2262
+
2263
+ /**
2264
+ * Sets the username and password in an alert prompting for credentials (such
2265
+ * as a Basic HTTP Auth prompt). This method will implicitly
2266
+ * {@linkplain #accept() submit} the dialog.
2267
+ *
2268
+ * @param {string} username The username to send.
2269
+ * @param {string} password The password to send.
2270
+ * @return {!promise.Promise<void>} A promise that will be resolved when this
2271
+ * command has completed.
2272
+ */
2273
+ authenticateAs(username, password) {
2274
+ return this.driver_.schedule(
2275
+ new command.Command(command.Name.SET_ALERT_CREDENTIALS),
2276
+ 'WebDriver.switchTo().alert()'
2277
+ + `.authenticateAs("${username}", "${password}")`);
2278
+ }
2279
+
2280
+ /**
2281
+ * Accepts this alert.
2282
+ *
2283
+ * @return {!promise.Promise<void>} A promise that will be resolved
2284
+ * when this command has completed.
2285
+ */
2286
+ accept() {
2287
+ return this.driver_.schedule(
2288
+ new command.Command(command.Name.ACCEPT_ALERT),
2289
+ 'WebDriver.switchTo().alert().accept()');
2290
+ }
2291
+
2292
+ /**
2293
+ * Dismisses this alert.
2294
+ *
2295
+ * @return {!promise.Promise<void>} A promise that will be resolved
2296
+ * when this command has completed.
2297
+ */
2298
+ dismiss() {
2299
+ return this.driver_.schedule(
2300
+ new command.Command(command.Name.DISMISS_ALERT),
2301
+ 'WebDriver.switchTo().alert().dismiss()');
2302
+ }
2303
+
2304
+ /**
2305
+ * Sets the response text on this alert. This command will return an error if
2306
+ * the underlying alert does not support response text (e.g. window.alert and
2307
+ * window.confirm).
2308
+ *
2309
+ * @param {string} text The text to set.
2310
+ * @return {!promise.Promise<void>} A promise that will be resolved
2311
+ * when this command has completed.
2312
+ */
2313
+ sendKeys(text) {
2314
+ return this.driver_.schedule(
2315
+ new command.Command(command.Name.SET_ALERT_TEXT).
2316
+ setParameter('text', text),
2317
+ 'WebDriver.switchTo().alert().sendKeys(' + text + ')');
2318
+ }
2319
+ }
2320
+
2321
+
2322
+ /**
2323
+ * AlertPromise is a promise that will be fulfilled with an Alert. This promise
2324
+ * serves as a forward proxy on an Alert, allowing calls to be scheduled
2325
+ * directly on this instance before the underlying Alert has been fulfilled. In
2326
+ * other words, the following two statements are equivalent:
2327
+ *
2328
+ * driver.switchTo().alert().dismiss();
2329
+ * driver.switchTo().alert().then(function(alert) {
2330
+ * return alert.dismiss();
2331
+ * });
2332
+ *
2333
+ * @implements {promise.Thenable.<!webdriver.Alert>}
2334
+ * @final
2335
+ */
2336
+ class AlertPromise extends Alert {
2337
+ /**
2338
+ * @param {!WebDriver} driver The driver controlling the browser this
2339
+ * alert is attached to.
2340
+ * @param {!promise.Thenable<!Alert>} alert A thenable
2341
+ * that will be fulfilled with the promised alert.
2342
+ */
2343
+ constructor(driver, alert) {
2344
+ super(driver, 'unused');
2345
+
2346
+ /** @override */
2347
+ this.cancel = alert.cancel.bind(alert);
2348
+
2349
+ /** @override */
2350
+ this.isPending = alert.isPending.bind(alert);
2351
+
2352
+ /** @override */
2353
+ this.then = alert.then.bind(alert);
2354
+
2355
+ /** @override */
2356
+ this.catch = alert.catch.bind(alert);
2357
+
2358
+ /** @override */
2359
+ this.thenCatch = alert.catch.bind(alert);
2360
+
2361
+ /** @override */
2362
+ this.finally = alert.finally.bind(alert);
2363
+
2364
+ /** @override */
2365
+ this.thenFinally = alert.finally.bind(alert);
2366
+
2367
+ /**
2368
+ * Defer returning text until the promised alert has been resolved.
2369
+ * @override
2370
+ */
2371
+ this.getText = function() {
2372
+ return alert.then(function(alert) {
2373
+ return alert.getText();
2374
+ });
2375
+ };
2376
+
2377
+ /**
2378
+ * Defers action until the alert has been located.
2379
+ * @override
2380
+ */
2381
+ this.authenticateAs = function(username, password) {
2382
+ return alert.then(function(alert) {
2383
+ return alert.authenticateAs(username, password);
2384
+ });
2385
+ };
2386
+
2387
+ /**
2388
+ * Defers action until the alert has been located.
2389
+ * @override
2390
+ */
2391
+ this.accept = function() {
2392
+ return alert.then(function(alert) {
2393
+ return alert.accept();
2394
+ });
2395
+ };
2396
+
2397
+ /**
2398
+ * Defers action until the alert has been located.
2399
+ * @override
2400
+ */
2401
+ this.dismiss = function() {
2402
+ return alert.then(function(alert) {
2403
+ return alert.dismiss();
2404
+ });
2405
+ };
2406
+
2407
+ /**
2408
+ * Defers action until the alert has been located.
2409
+ * @override
2410
+ */
2411
+ this.sendKeys = function(text) {
2412
+ return alert.then(function(alert) {
2413
+ return alert.sendKeys(text);
2414
+ });
2415
+ };
2416
+ }
2417
+ }
2418
+ promise.Thenable.addImplementation(AlertPromise);
2419
+
2420
+
2421
+ // PUBLIC API
2422
+
2423
+
2424
+ module.exports = {
2425
+ Alert: Alert,
2426
+ AlertPromise: AlertPromise,
2427
+ Condition: Condition,
2428
+ Logs: Logs,
2429
+ Navigation: Navigation,
2430
+ Options: Options,
2431
+ TargetLocator: TargetLocator,
2432
+ Timeouts: Timeouts,
2433
+ /** @deprecated Use {@link error.UnexpectedAlertOpenError} instead. */
2434
+ UnhandledAlertError: error.UnexpectedAlertOpenError,
2435
+ WebDriver: WebDriver,
2436
+ WebElement: WebElement,
2437
+ WebElementCondition: WebElementCondition,
2438
+ WebElementPromise: WebElementPromise,
2439
+ Window: Window
2440
+ };