selenium-webdriver 2.47.0 → 2.52.0

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