selenium-webdriver 3.5.0 → 4.0.0-alpha.4
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.
- package/CHANGES.md +246 -0
- package/LICENSE +1 -1
- package/NOTICE +1 -1
- package/README.md +40 -40
- package/chrome.js +118 -134
- package/edge.js +43 -117
- package/example/chrome_android.js +8 -9
- package/example/chrome_mobile_emulation.js +8 -9
- package/example/firefox_channels.js +23 -19
- package/example/google_search.js +3 -3
- package/example/google_search_test.js +38 -27
- package/example/{chrome_headless.js → headless.js} +15 -7
- package/example/logging.js +40 -7
- package/firefox.js +789 -0
- package/http/index.js +62 -9
- package/http/util.js +11 -6
- package/ie.js +83 -97
- package/index.js +198 -114
- package/io/exec.js +29 -15
- package/io/index.js +1 -1
- package/io/zip.js +1 -1
- package/lib/actions.js +68 -63
- package/lib/atoms/get-attribute.js +86 -0
- package/lib/atoms/is-displayed.js +76 -76
- package/lib/by.js +7 -4
- package/lib/capabilities.js +310 -210
- package/lib/command.js +27 -51
- package/lib/error.js +100 -41
- package/lib/http.js +161 -120
- package/lib/input.js +1044 -8
- package/lib/logging.js +1 -5
- package/lib/promise.js +222 -3331
- package/lib/proxy.js +134 -39
- package/lib/session.js +2 -2
- package/lib/symbols.js +0 -0
- package/lib/until.js +1 -1
- package/lib/webdriver.js +717 -953
- package/net/index.js +21 -25
- package/net/portprober.js +51 -68
- package/package.json +17 -12
- package/proxy.js +0 -0
- package/remote/index.js +63 -44
- package/safari.js +41 -128
- package/testing/index.js +386 -315
- package/.npmignore +0 -2
- package/example/async_await_test.js +0 -68
- package/example/google_search_generator.js +0 -50
- package/example/parallel_flows.js +0 -54
- package/firefox/binary.js +0 -344
- package/firefox/extension.js +0 -224
- package/firefox/index.js +0 -626
- package/firefox/profile.js +0 -394
- package/lib/README +0 -5
- package/lib/atoms/getAttribute.js +0 -9
- package/lib/devmode.js +0 -34
- package/lib/events.js +0 -210
- package/lib/firefox/webdriver.json +0 -70
- package/lib/test/build.js +0 -151
- package/lib/test/data/ClickTest_testClicksASurroundingStrongTag.html +0 -11
- package/lib/test/data/Page.aspx +0 -17
- package/lib/test/data/Page.aspx.cs +0 -22
- package/lib/test/data/Redirect.aspx +0 -11
- package/lib/test/data/Redirect.aspx.cs +0 -9
- package/lib/test/data/Settings.StyleCop +0 -759
- package/lib/test/data/Web.Config +0 -59
- package/lib/test/data/actualXhtmlPage.xhtml +0 -14
- package/lib/test/data/ajaxy_page.html +0 -81
- package/lib/test/data/alerts.html +0 -85
- package/lib/test/data/banner.gif +0 -0
- package/lib/test/data/beach.jpg +0 -0
- package/lib/test/data/blank.html +0 -1
- package/lib/test/data/bodyTypingTest.html +0 -41
- package/lib/test/data/booleanAttributes.html +0 -19
- package/lib/test/data/child/childPage.html +0 -8
- package/lib/test/data/child/grandchild/grandchildPage.html +0 -8
- package/lib/test/data/clickEventPage.html +0 -26
- package/lib/test/data/click_frames.html +0 -10
- package/lib/test/data/click_jacker.html +0 -38
- package/lib/test/data/click_out_of_bounds.html +0 -23
- package/lib/test/data/click_out_of_bounds_overflow.html +0 -85
- package/lib/test/data/click_rtl.html +0 -19
- package/lib/test/data/click_source.html +0 -18
- package/lib/test/data/click_tests/click_iframe.html +0 -6
- package/lib/test/data/click_tests/click_in_iframe.html +0 -8
- package/lib/test/data/click_tests/disabled_element.html +0 -12
- package/lib/test/data/click_tests/disappearing_element.html +0 -62
- package/lib/test/data/click_tests/google_map.html +0 -15
- package/lib/test/data/click_tests/google_map.png +0 -0
- package/lib/test/data/click_tests/html5_submit_buttons.html +0 -16
- package/lib/test/data/click_tests/issue5237.html +0 -9
- package/lib/test/data/click_tests/issue5237_frame.html +0 -1
- package/lib/test/data/click_tests/issue5237_target.html +0 -10
- package/lib/test/data/click_tests/link_that_wraps.html +0 -11
- package/lib/test/data/click_tests/mapped_page1.html +0 -9
- package/lib/test/data/click_tests/mapped_page2.html +0 -9
- package/lib/test/data/click_tests/mapped_page3.html +0 -9
- package/lib/test/data/click_tests/overlapping_elements.html +0 -70
- package/lib/test/data/click_tests/partially_overlapping_elements.html +0 -124
- package/lib/test/data/click_tests/span_that_wraps.html +0 -11
- package/lib/test/data/click_tests/submitted_page.html +0 -9
- package/lib/test/data/click_tests/wrapped_overlapping_elements.html +0 -13
- package/lib/test/data/click_too_big.html +0 -10
- package/lib/test/data/click_too_big_in_frame.html +0 -11
- package/lib/test/data/clicks.html +0 -35
- package/lib/test/data/closeable_window.html +0 -8
- package/lib/test/data/cn-test.html +0 -156
- package/lib/test/data/colorPage.html +0 -20
- package/lib/test/data/cookies.html +0 -30
- package/lib/test/data/coordinates_tests/element_in_frame.html +0 -9
- package/lib/test/data/coordinates_tests/element_in_nested_frame.html +0 -9
- package/lib/test/data/coordinates_tests/page_with_element_out_of_view.html +0 -11
- package/lib/test/data/coordinates_tests/page_with_empty_element.html +0 -10
- package/lib/test/data/coordinates_tests/page_with_fixed_element.html +0 -12
- package/lib/test/data/coordinates_tests/page_with_hidden_element.html +0 -10
- package/lib/test/data/coordinates_tests/page_with_invisible_element.html +0 -10
- package/lib/test/data/coordinates_tests/page_with_transparent_element.html +0 -10
- package/lib/test/data/coordinates_tests/simple_page.html +0 -10
- package/lib/test/data/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
- package/lib/test/data/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
- package/lib/test/data/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png +0 -0
- package/lib/test/data/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
- package/lib/test/data/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
- package/lib/test/data/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- package/lib/test/data/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
- package/lib/test/data/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
- package/lib/test/data/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
- package/lib/test/data/css/ui-lightness/images/ui-icons_222222_256x240.png +0 -0
- package/lib/test/data/css/ui-lightness/images/ui-icons_228ef1_256x240.png +0 -0
- package/lib/test/data/css/ui-lightness/images/ui-icons_ef8c08_256x240.png +0 -0
- package/lib/test/data/css/ui-lightness/images/ui-icons_ffd27a_256x240.png +0 -0
- package/lib/test/data/css/ui-lightness/images/ui-icons_ffffff_256x240.png +0 -0
- package/lib/test/data/css/ui-lightness/jquery-ui-1.8.10.custom.css +0 -573
- package/lib/test/data/cssTransform.html +0 -61
- package/lib/test/data/cssTransform2.html +0 -20
- package/lib/test/data/document_write_in_onload.html +0 -13
- package/lib/test/data/dragAndDropInsideScrolledDiv.html +0 -67
- package/lib/test/data/dragAndDropTest.html +0 -102
- package/lib/test/data/dragDropOverflow.html +0 -104
- package/lib/test/data/draggableLists.html +0 -67
- package/lib/test/data/droppableItems.html +0 -65
- package/lib/test/data/dynamic.html +0 -39
- package/lib/test/data/dynamicallyModifiedPage.html +0 -42
- package/lib/test/data/errors.html +0 -15
- package/lib/test/data/firefox/jetpack-sample.xpi +0 -0
- package/lib/test/data/firefox/sample.xpi +0 -0
- package/lib/test/data/firefox/webextension.xpi +0 -0
- package/lib/test/data/fixedFooterNoScroll.html +0 -13
- package/lib/test/data/fixedFooterNoScrollQuirksMode.html +0 -12
- package/lib/test/data/formPage.html +0 -175
- package/lib/test/data/formSelectionPage.html +0 -46
- package/lib/test/data/form_handling_js_submit.html +0 -30
- package/lib/test/data/framePage3.html +0 -7
- package/lib/test/data/frameScrollChild.html +0 -26
- package/lib/test/data/frameScrollPage.html +0 -14
- package/lib/test/data/frameScrollParent.html +0 -11
- package/lib/test/data/frameWithAnimals.html +0 -11
- package/lib/test/data/frame_switching_tests/bug4876.html +0 -9
- package/lib/test/data/frame_switching_tests/bug4876_iframe.html +0 -9
- package/lib/test/data/frame_switching_tests/deletingFrame.html +0 -29
- package/lib/test/data/frame_switching_tests/deletingFrame_iframe.html +0 -8
- package/lib/test/data/frame_switching_tests/deletingFrame_iframe2.html +0 -7
- package/lib/test/data/frameset.html +0 -14
- package/lib/test/data/framesetPage2.html +0 -7
- package/lib/test/data/framesetPage3.html +0 -4
- package/lib/test/data/globalscope.html +0 -15
- package/lib/test/data/hidden.html +0 -5
- package/lib/test/data/hidden_partially.html +0 -45
- package/lib/test/data/html5/blue.jpg +0 -0
- package/lib/test/data/html5/database.js +0 -84
- package/lib/test/data/html5/geolocation.js +0 -18
- package/lib/test/data/html5/green.jpg +0 -0
- package/lib/test/data/html5/red.jpg +0 -0
- package/lib/test/data/html5/status.html +0 -1
- package/lib/test/data/html5/test.appcache +0 -11
- package/lib/test/data/html5/yellow.jpg +0 -0
- package/lib/test/data/html5Page.html +0 -32
- package/lib/test/data/icon.gif +0 -0
- package/lib/test/data/idElements.html +0 -2
- package/lib/test/data/iframeAtBottom.html +0 -15
- package/lib/test/data/iframeWithAlert.html +0 -1
- package/lib/test/data/iframeWithIframe.html +0 -1
- package/lib/test/data/iframes.html +0 -11
- package/lib/test/data/injectableContent.html +0 -22
- package/lib/test/data/javascriptEnhancedForm.html +0 -30
- package/lib/test/data/javascriptPage.html +0 -285
- package/lib/test/data/jquery-1.3.2.js +0 -4376
- package/lib/test/data/js/jquery-1.4.4.min.js +0 -167
- package/lib/test/data/js/jquery-ui-1.8.10.custom.min.js +0 -782
- package/lib/test/data/js/skins/lightgray/content.inline.min.css +0 -1
- package/lib/test/data/js/skins/lightgray/content.min.css +0 -1
- package/lib/test/data/js/skins/lightgray/fonts/readme.md +0 -1
- package/lib/test/data/js/skins/lightgray/fonts/tinymce-small.dev.svg +0 -175
- package/lib/test/data/js/skins/lightgray/fonts/tinymce-small.eot +0 -0
- package/lib/test/data/js/skins/lightgray/fonts/tinymce-small.svg +0 -62
- package/lib/test/data/js/skins/lightgray/fonts/tinymce-small.ttf +0 -0
- package/lib/test/data/js/skins/lightgray/fonts/tinymce-small.woff +0 -0
- package/lib/test/data/js/skins/lightgray/fonts/tinymce.dev.svg +0 -153
- package/lib/test/data/js/skins/lightgray/fonts/tinymce.eot +0 -0
- package/lib/test/data/js/skins/lightgray/fonts/tinymce.svg +0 -63
- package/lib/test/data/js/skins/lightgray/fonts/tinymce.ttf +0 -0
- package/lib/test/data/js/skins/lightgray/fonts/tinymce.woff +0 -0
- package/lib/test/data/js/skins/lightgray/img/anchor.gif +0 -0
- package/lib/test/data/js/skins/lightgray/img/loader.gif +0 -0
- package/lib/test/data/js/skins/lightgray/img/object.gif +0 -0
- package/lib/test/data/js/skins/lightgray/img/trans.gif +0 -0
- package/lib/test/data/js/skins/lightgray/skin.ie7.min.css +0 -1
- package/lib/test/data/js/skins/lightgray/skin.min.css +0 -1
- package/lib/test/data/js/themes/modern/theme.min.js +0 -1
- package/lib/test/data/js/tinymce.min.js +0 -10
- package/lib/test/data/key_logger.html +0 -34
- package/lib/test/data/key_tests/remove_on_keypress.html +0 -36
- package/lib/test/data/keyboard_shortcut.html +0 -36
- package/lib/test/data/linked_image.html +0 -16
- package/lib/test/data/locators_tests/boolean_attribute_selected.html +0 -13
- package/lib/test/data/locators_tests/boolean_attribute_selected_html4.html +0 -13
- package/lib/test/data/longContentPage.html +0 -55
- package/lib/test/data/macbeth.html +0 -5255
- package/lib/test/data/map.png +0 -0
- package/lib/test/data/map_visibility.html +0 -8
- package/lib/test/data/markerTransparent.png +0 -0
- package/lib/test/data/messages.html +0 -15
- package/lib/test/data/meta-redirect.html +0 -11
- package/lib/test/data/missedJsReference.html +0 -11
- package/lib/test/data/modal_dialogs/modal_1.html +0 -21
- package/lib/test/data/modal_dialogs/modal_2.html +0 -21
- package/lib/test/data/modal_dialogs/modal_3.html +0 -15
- package/lib/test/data/modal_dialogs/modalindex.html +0 -21
- package/lib/test/data/mouseOver.html +0 -17
- package/lib/test/data/mousePositionTracker.html +0 -33
- package/lib/test/data/nestedElements.html +0 -164
- package/lib/test/data/overflow/x_auto_y_auto.html +0 -30
- package/lib/test/data/overflow/x_auto_y_hidden.html +0 -30
- package/lib/test/data/overflow/x_auto_y_scroll.html +0 -30
- package/lib/test/data/overflow/x_hidden_y_auto.html +0 -30
- package/lib/test/data/overflow/x_hidden_y_hidden.html +0 -30
- package/lib/test/data/overflow/x_hidden_y_scroll.html +0 -30
- package/lib/test/data/overflow/x_scroll_y_auto.html +0 -30
- package/lib/test/data/overflow/x_scroll_y_hidden.html +0 -30
- package/lib/test/data/overflow/x_scroll_y_scroll.html +0 -30
- package/lib/test/data/overflow-body.html +0 -15
- package/lib/test/data/pageWithOnBeforeUnloadMessage.html +0 -20
- package/lib/test/data/pageWithOnLoad.html +0 -6
- package/lib/test/data/pageWithOnUnload.html +0 -6
- package/lib/test/data/page_with_link_to_slow_loading_page.html +0 -6
- package/lib/test/data/plain.txt +0 -1
- package/lib/test/data/proxy/page1.html +0 -20
- package/lib/test/data/proxy/page2.html +0 -24
- package/lib/test/data/proxy/page3.html +0 -5
- package/lib/test/data/readOnlyPage.html +0 -24
- package/lib/test/data/rectangles.html +0 -40
- package/lib/test/data/resultPage.html +0 -25
- package/lib/test/data/rich_text.html +0 -161
- package/lib/test/data/safari/frames_benchmark.html +0 -31
- package/lib/test/data/screen/screen.css +0 -19
- package/lib/test/data/screen/screen.html +0 -72
- package/lib/test/data/screen/screen.js +0 -7
- package/lib/test/data/screen/screen_frame1.html +0 -72
- package/lib/test/data/screen/screen_frame2.html +0 -72
- package/lib/test/data/screen/screen_frames.html +0 -11
- package/lib/test/data/screen/screen_iframes.html +0 -12
- package/lib/test/data/screen/screen_too_long.html +0 -68
- package/lib/test/data/screen/screen_x_long.html +0 -72
- package/lib/test/data/screen/screen_x_too_long.html +0 -72
- package/lib/test/data/screen/screen_y_long.html +0 -72
- package/lib/test/data/screen/screen_y_too_long.html +0 -72
- package/lib/test/data/scroll.html +0 -27
- package/lib/test/data/scroll2.html +0 -21
- package/lib/test/data/scroll3.html +0 -8
- package/lib/test/data/scroll4.html +0 -7
- package/lib/test/data/scroll5.html +0 -18
- package/lib/test/data/scrolling_tests/frame_with_height_above_200.html +0 -26
- package/lib/test/data/scrolling_tests/frame_with_height_above_2000.html +0 -26
- package/lib/test/data/scrolling_tests/frame_with_nested_scrolling_frame.html +0 -11
- package/lib/test/data/scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html +0 -12
- package/lib/test/data/scrolling_tests/frame_with_small_height.html +0 -10
- package/lib/test/data/scrolling_tests/page_with_double_overflow_auto.html +0 -19
- package/lib/test/data/scrolling_tests/page_with_frame_out_of_view.html +0 -12
- package/lib/test/data/scrolling_tests/page_with_nested_scrolling_frames.html +0 -11
- package/lib/test/data/scrolling_tests/page_with_nested_scrolling_frames_out_of_view.html +0 -12
- package/lib/test/data/scrolling_tests/page_with_non_scrolling_frame.html +0 -11
- package/lib/test/data/scrolling_tests/page_with_scrolling_frame.html +0 -11
- package/lib/test/data/scrolling_tests/page_with_scrolling_frame_out_of_view.html +0 -12
- package/lib/test/data/scrolling_tests/page_with_tall_frame.html +0 -11
- package/lib/test/data/scrolling_tests/page_with_y_overflow_auto.html +0 -14
- package/lib/test/data/scrolling_tests/target_page.html +0 -9
- package/lib/test/data/selectPage.html +0 -58
- package/lib/test/data/selectableItems.html +0 -65
- package/lib/test/data/sessionCookie.html +0 -21
- package/lib/test/data/sessionCookieDest.html +0 -34
- package/lib/test/data/simple.xml +0 -5
- package/lib/test/data/simpleTest.html +0 -98
- package/lib/test/data/single_text_input.html +0 -12
- package/lib/test/data/slowLoadingAlert.html +0 -10
- package/lib/test/data/slowLoadingResourcePage.html +0 -12
- package/lib/test/data/slow_loading_iframes.html +0 -14
- package/lib/test/data/styledPage.html +0 -28
- package/lib/test/data/svgPiechart.xhtml +0 -81
- package/lib/test/data/svgTest.svg +0 -4
- package/lib/test/data/tables.html +0 -36
- package/lib/test/data/tinymce.html +0 -10
- package/lib/test/data/transformable.xml +0 -11
- package/lib/test/data/transformable.xsl +0 -37
- package/lib/test/data/transparentUpload.html +0 -70
- package/lib/test/data/underscore.html +0 -9
- package/lib/test/data/unicode_ltr.html +0 -8
- package/lib/test/data/upload.html +0 -45
- package/lib/test/data/userDefinedProperty.html +0 -8
- package/lib/test/data/veryLargeCanvas.html +0 -81
- package/lib/test/data/visibility-css.html +0 -21
- package/lib/test/data/win32frameset.html +0 -8
- package/lib/test/data/window_switching_tests/page_with_frame.html +0 -12
- package/lib/test/data/window_switching_tests/simple_page.html +0 -9
- package/lib/test/data/xhtmlFormPage.xhtml +0 -17
- package/lib/test/data/xhtmlTest.html +0 -76
- package/lib/test/fileserver.js +0 -321
- package/lib/test/httpserver.js +0 -120
- package/lib/test/index.js +0 -270
- package/lib/test/promise.js +0 -79
- package/lib/test/resources.js +0 -44
- package/opera.js +0 -405
- package/phantomjs.js +0 -282
- package/test/actions_test.js +0 -52
- package/test/chrome/options_test.js +0 -227
- package/test/chrome/service_test.js +0 -45
- package/test/cookie_test.js +0 -214
- package/test/element_finding_test.js +0 -426
- package/test/execute_script_test.js +0 -350
- package/test/fingerprint_test.js +0 -62
- package/test/firefox/extension_test.js +0 -120
- package/test/firefox/firefox_test.js +0 -261
- package/test/firefox/profile_test.js +0 -140
- package/test/http/http_test.js +0 -223
- package/test/http/util_test.js +0 -178
- package/test/io/io_test.js +0 -360
- package/test/io/zip_test.js +0 -128
- package/test/lib/by_test.js +0 -160
- package/test/lib/capabilities_test.js +0 -111
- package/test/lib/error_test.js +0 -305
- package/test/lib/events_test.js +0 -177
- package/test/lib/http_test.js +0 -696
- package/test/lib/logging_test.js +0 -272
- package/test/lib/promise_aplus_test.js +0 -78
- package/test/lib/promise_error_test.js +0 -884
- package/test/lib/promise_flow_test.js +0 -2288
- package/test/lib/promise_generator_test.js +0 -310
- package/test/lib/promise_test.js +0 -1109
- package/test/lib/testutil.js +0 -90
- package/test/lib/until_test.js +0 -478
- package/test/lib/webdriver_test.js +0 -2311
- package/test/logging_test.js +0 -167
- package/test/net/index_test.js +0 -60
- package/test/net/portprober_test.js +0 -128
- package/test/page_loading_test.js +0 -166
- package/test/phantomjs/execute_phantomjs_test.js +0 -59
- package/test/proxy_test.js +0 -180
- package/test/rect_test.js +0 -60
- package/test/remote_test.js +0 -117
- package/test/safari_test.js +0 -108
- package/test/session_test.js +0 -99
- package/test/stale_element_test.js +0 -63
- package/test/tag_name_test.js +0 -36
- package/test/testing/assert_test.js +0 -373
- package/test/testing/index_test.js +0 -224
- package/test/upload_test.js +0 -86
- package/test/window_test.js +0 -161
- package/testing/assert.js +0 -378
package/lib/webdriver.js
CHANGED
|
@@ -21,16 +21,29 @@
|
|
|
21
21
|
|
|
22
22
|
'use strict';
|
|
23
23
|
|
|
24
|
-
const actions = require('./actions');
|
|
25
24
|
const by = require('./by');
|
|
26
|
-
const Capabilities = require('./capabilities').Capabilities;
|
|
27
25
|
const command = require('./command');
|
|
28
26
|
const error = require('./error');
|
|
29
27
|
const input = require('./input');
|
|
30
28
|
const logging = require('./logging');
|
|
31
|
-
const {Session} = require('./session');
|
|
32
|
-
const Symbols = require('./symbols');
|
|
33
29
|
const promise = require('./promise');
|
|
30
|
+
const Symbols = require('./symbols');
|
|
31
|
+
const {Capabilities} = require('./capabilities');
|
|
32
|
+
const {Session} = require('./session');
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
// Capability names that are defined in the W3C spec.
|
|
36
|
+
const W3C_CAPABILITY_NAMES = new Set([
|
|
37
|
+
'acceptInsecureCerts',
|
|
38
|
+
'browserName',
|
|
39
|
+
'browserVersion',
|
|
40
|
+
'platformName',
|
|
41
|
+
'pageLoadStrategy',
|
|
42
|
+
'proxy',
|
|
43
|
+
'setWindowRect',
|
|
44
|
+
'timeouts',
|
|
45
|
+
'unhandledPromptBehavior',
|
|
46
|
+
]);
|
|
34
47
|
|
|
35
48
|
|
|
36
49
|
/**
|
|
@@ -121,15 +134,8 @@ function executeCommand(executor, command) {
|
|
|
121
134
|
* @return {!Promise<?>} A promise that will resolve to the input value's JSON
|
|
122
135
|
* representation.
|
|
123
136
|
*/
|
|
124
|
-
function toWireValue(obj) {
|
|
125
|
-
|
|
126
|
-
return Promise.resolve(obj).then(toWireValue);
|
|
127
|
-
}
|
|
128
|
-
return Promise.resolve(convertValue(obj));
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
function convertValue(value) {
|
|
137
|
+
async function toWireValue(obj) {
|
|
138
|
+
let value = await Promise.resolve(obj);
|
|
133
139
|
if (value === void 0 || value === null) {
|
|
134
140
|
return value;
|
|
135
141
|
}
|
|
@@ -157,53 +163,33 @@ function convertValue(value) {
|
|
|
157
163
|
}
|
|
158
164
|
|
|
159
165
|
|
|
160
|
-
function convertKeys(obj) {
|
|
166
|
+
async function convertKeys(obj) {
|
|
161
167
|
const isArray = Array.isArray(obj);
|
|
162
168
|
const numKeys = isArray ? obj.length : Object.keys(obj).length;
|
|
163
169
|
const ret = isArray ? new Array(numKeys) : {};
|
|
164
170
|
if (!numKeys) {
|
|
165
|
-
return
|
|
171
|
+
return ret;
|
|
166
172
|
}
|
|
167
173
|
|
|
168
174
|
let numResolved = 0;
|
|
169
175
|
|
|
170
|
-
function forEachKey(obj, fn) {
|
|
176
|
+
async function forEachKey(obj, fn) {
|
|
171
177
|
if (Array.isArray(obj)) {
|
|
172
178
|
for (let i = 0, n = obj.length; i < n; i++) {
|
|
173
|
-
fn(obj[i], i);
|
|
179
|
+
await fn(obj[i], i);
|
|
174
180
|
}
|
|
175
181
|
} else {
|
|
176
182
|
for (let key in obj) {
|
|
177
|
-
fn(obj[key], key);
|
|
183
|
+
await fn(obj[key], key);
|
|
178
184
|
}
|
|
179
185
|
}
|
|
180
186
|
}
|
|
181
187
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
if (promise.isPromise(value)) {
|
|
185
|
-
value.then(toWireValue).then(setValue, reject);
|
|
186
|
-
} else {
|
|
187
|
-
value = convertValue(value);
|
|
188
|
-
if (promise.isPromise(value)) {
|
|
189
|
-
value.then(toWireValue).then(setValue, reject);
|
|
190
|
-
} else {
|
|
191
|
-
setValue(value);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
function setValue(value) {
|
|
196
|
-
ret[key] = value;
|
|
197
|
-
maybeFulfill();
|
|
198
|
-
}
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
function maybeFulfill() {
|
|
202
|
-
if (++numResolved === numKeys) {
|
|
203
|
-
done(ret);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
188
|
+
await forEachKey(obj, async function(value, key) {
|
|
189
|
+
ret[key] = await toWireValue(value);
|
|
206
190
|
});
|
|
191
|
+
|
|
192
|
+
return ret;
|
|
207
193
|
}
|
|
208
194
|
|
|
209
195
|
|
|
@@ -243,25 +229,21 @@ function fromWireValue(driver, value) {
|
|
|
243
229
|
*/
|
|
244
230
|
class IWebDriver {
|
|
245
231
|
|
|
246
|
-
/** @return {!promise.ControlFlow} The control flow used by this instance. */
|
|
247
|
-
controlFlow() {}
|
|
248
|
-
|
|
249
232
|
/**
|
|
250
|
-
*
|
|
233
|
+
* Executes the provided {@link command.Command} using this driver's
|
|
251
234
|
* {@link command.Executor}.
|
|
252
235
|
*
|
|
253
236
|
* @param {!command.Command} command The command to schedule.
|
|
254
|
-
* @
|
|
255
|
-
*
|
|
256
|
-
* with the command result.
|
|
237
|
+
* @return {!Promise<T>} A promise that will be resolved with the command
|
|
238
|
+
* result.
|
|
257
239
|
* @template T
|
|
258
240
|
*/
|
|
259
|
-
|
|
241
|
+
execute(command) {}
|
|
260
242
|
|
|
261
243
|
/**
|
|
262
244
|
* Sets the {@linkplain input.FileDetector file detector} that should be
|
|
263
245
|
* used with this instance.
|
|
264
|
-
* @param {input.FileDetector} detector The detector to use or
|
|
246
|
+
* @param {input.FileDetector} detector The detector to use or `null`.
|
|
265
247
|
*/
|
|
266
248
|
setFileDetector(detector) {}
|
|
267
249
|
|
|
@@ -271,12 +253,12 @@ class IWebDriver {
|
|
|
271
253
|
getExecutor() {}
|
|
272
254
|
|
|
273
255
|
/**
|
|
274
|
-
* @return {!
|
|
256
|
+
* @return {!Promise<!Session>} A promise for this client's session.
|
|
275
257
|
*/
|
|
276
258
|
getSession() {}
|
|
277
259
|
|
|
278
260
|
/**
|
|
279
|
-
* @return {!
|
|
261
|
+
* @return {!Promise<!Capabilities>} A promise that will resolve with
|
|
280
262
|
* the this instance's capabilities.
|
|
281
263
|
*/
|
|
282
264
|
getCapabilities() {}
|
|
@@ -286,56 +268,40 @@ class IWebDriver {
|
|
|
286
268
|
* invalidated and may no longer be used to issue commands against the
|
|
287
269
|
* browser.
|
|
288
270
|
*
|
|
289
|
-
* @return {!
|
|
271
|
+
* @return {!Promise<void>} A promise that will be resolved when the
|
|
290
272
|
* command has completed.
|
|
291
273
|
*/
|
|
292
274
|
quit() {}
|
|
293
275
|
|
|
294
276
|
/**
|
|
295
277
|
* Creates a new action sequence using this driver. The sequence will not be
|
|
296
|
-
*
|
|
297
|
-
* called.
|
|
278
|
+
* submitted for execution until
|
|
279
|
+
* {@link ./input.Actions#perform Actions.perform()} is called.
|
|
298
280
|
*
|
|
299
|
-
*
|
|
300
|
-
*
|
|
301
|
-
*
|
|
302
|
-
*
|
|
303
|
-
*
|
|
304
|
-
*
|
|
305
|
-
* @return {!actions.ActionSequence} A new action sequence for this instance.
|
|
281
|
+
* @param {{async: (boolean|undefined),
|
|
282
|
+
* bridge: (boolean|undefined)}=} options Configuration options for
|
|
283
|
+
* the action sequence (see {@link ./input.Actions Actions} documentation
|
|
284
|
+
* for details).
|
|
285
|
+
* @return {!input.Actions} A new action sequence for this instance.
|
|
306
286
|
*/
|
|
307
|
-
actions() {}
|
|
287
|
+
actions(options) {}
|
|
308
288
|
|
|
309
289
|
/**
|
|
310
|
-
*
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
*
|
|
314
|
-
* driver.touchActions().
|
|
315
|
-
* tap(element1).
|
|
316
|
-
* doubleTap(element2).
|
|
317
|
-
* perform();
|
|
318
|
-
*
|
|
319
|
-
* @return {!actions.TouchSequence} A new touch sequence for this instance.
|
|
320
|
-
*/
|
|
321
|
-
touchActions() {}
|
|
322
|
-
|
|
323
|
-
/**
|
|
324
|
-
* Schedules a command to execute JavaScript in the context of the currently
|
|
325
|
-
* selected frame or window. The script fragment will be executed as the body
|
|
326
|
-
* of an anonymous function. If the script is provided as a function object,
|
|
327
|
-
* that function will be converted to a string for injection into the target
|
|
290
|
+
* Executes a snippet of JavaScript in the context of the currently selected
|
|
291
|
+
* frame or window. The script fragment will be executed as the body of an
|
|
292
|
+
* anonymous function. If the script is provided as a function object, that
|
|
293
|
+
* function will be converted to a string for injection into the target
|
|
328
294
|
* window.
|
|
329
295
|
*
|
|
330
296
|
* Any arguments provided in addition to the script will be included as script
|
|
331
|
-
* arguments and may be referenced using the
|
|
332
|
-
*
|
|
333
|
-
*
|
|
334
|
-
*
|
|
297
|
+
* arguments and may be referenced using the `arguments` object. Arguments may
|
|
298
|
+
* be a boolean, number, string, or {@linkplain WebElement}. Arrays and
|
|
299
|
+
* objects may also be used as script arguments as long as each item adheres
|
|
300
|
+
* to the types previously mentioned.
|
|
335
301
|
*
|
|
336
302
|
* The script may refer to any variables accessible from the current window.
|
|
337
303
|
* Furthermore, the script will execute in the window's context, thus
|
|
338
|
-
*
|
|
304
|
+
* `document` may be used to refer to the current document. Any local
|
|
339
305
|
* variables will not be available once the script has finished executing,
|
|
340
306
|
* though global variables will persist.
|
|
341
307
|
*
|
|
@@ -351,36 +317,35 @@ class IWebDriver {
|
|
|
351
317
|
* the rules above
|
|
352
318
|
*
|
|
353
319
|
* @param {!(string|Function)} script The script to execute.
|
|
354
|
-
* @param {...*}
|
|
355
|
-
* @return {!
|
|
320
|
+
* @param {...*} args The arguments to pass to the script.
|
|
321
|
+
* @return {!IThenable<T>} A promise that will resolve to the
|
|
356
322
|
* scripts return value.
|
|
357
323
|
* @template T
|
|
358
324
|
*/
|
|
359
|
-
executeScript(script,
|
|
325
|
+
executeScript(script, ...args) {}
|
|
360
326
|
|
|
361
327
|
/**
|
|
362
|
-
*
|
|
328
|
+
* Executes a snippet of asynchronous JavaScript in the context of the
|
|
363
329
|
* currently selected frame or window. The script fragment will be executed as
|
|
364
330
|
* the body of an anonymous function. If the script is provided as a function
|
|
365
331
|
* object, that function will be converted to a string for injection into the
|
|
366
332
|
* target window.
|
|
367
333
|
*
|
|
368
334
|
* Any arguments provided in addition to the script will be included as script
|
|
369
|
-
* arguments and may be referenced using the
|
|
370
|
-
*
|
|
371
|
-
*
|
|
372
|
-
*
|
|
335
|
+
* arguments and may be referenced using the `arguments` object. Arguments may
|
|
336
|
+
* be a boolean, number, string, or {@linkplain WebElement}. Arrays and
|
|
337
|
+
* objects may also be used as script arguments as long as each item adheres
|
|
338
|
+
* to the types previously mentioned.
|
|
373
339
|
*
|
|
374
340
|
* Unlike executing synchronous JavaScript with {@link #executeScript},
|
|
375
|
-
* scripts executed with this function must explicitly signal they are
|
|
376
|
-
* by invoking the provided callback. This callback will always be
|
|
377
|
-
* into the executed function as the last argument, and thus may be
|
|
378
|
-
* with
|
|
379
|
-
* taken for resolving this functions return value against the first
|
|
380
|
-
* to the script's callback function:
|
|
381
|
-
*
|
|
382
|
-
* - For a HTML element, the value will resolve to a
|
|
383
|
-
* {@link WebElement}
|
|
341
|
+
* scripts executed with this function must explicitly signal they are
|
|
342
|
+
* finished by invoking the provided callback. This callback will always be
|
|
343
|
+
* injected into the executed function as the last argument, and thus may be
|
|
344
|
+
* referenced with `arguments[arguments.length - 1]`. The following steps
|
|
345
|
+
* will be taken for resolving this functions return value against the first
|
|
346
|
+
* argument to the script's callback function:
|
|
347
|
+
*
|
|
348
|
+
* - For a HTML element, the value will resolve to a {@link WebElement}
|
|
384
349
|
* - Null and undefined return values will resolve to null
|
|
385
350
|
* - Booleans, numbers, and strings will resolve as is
|
|
386
351
|
* - Functions will resolve to their string representation
|
|
@@ -410,9 +375,9 @@ class IWebDriver {
|
|
|
410
375
|
*
|
|
411
376
|
* __Example #3:__ Injecting a XMLHttpRequest and waiting for the result. In
|
|
412
377
|
* this example, the inject script is specified with a function literal. When
|
|
413
|
-
* using this format, the function is converted to a string for injection, so
|
|
414
|
-
* should not reference any symbols not defined in the scope of the page
|
|
415
|
-
* test.
|
|
378
|
+
* using this format, the function is converted to a string for injection, so
|
|
379
|
+
* it should not reference any symbols not defined in the scope of the page
|
|
380
|
+
* under test.
|
|
416
381
|
*
|
|
417
382
|
* driver.executeAsyncScript(function() {
|
|
418
383
|
* var callback = arguments[arguments.length - 1];
|
|
@@ -429,70 +394,50 @@ class IWebDriver {
|
|
|
429
394
|
* });
|
|
430
395
|
*
|
|
431
396
|
* @param {!(string|Function)} script The script to execute.
|
|
432
|
-
* @param {...*}
|
|
433
|
-
* @return {!
|
|
434
|
-
*
|
|
435
|
-
* @template T
|
|
436
|
-
*/
|
|
437
|
-
executeAsyncScript(script, var_args) {}
|
|
438
|
-
|
|
439
|
-
/**
|
|
440
|
-
* Schedules a command to execute a custom function.
|
|
441
|
-
* @param {function(...): (T|IThenable<T>)} fn The function to execute.
|
|
442
|
-
* @param {Object=} opt_scope The object in whose scope to execute the function.
|
|
443
|
-
* @param {...*} var_args Any arguments to pass to the function.
|
|
444
|
-
* @return {!promise.Thenable<T>} A promise that will be resolved'
|
|
445
|
-
* with the function's result.
|
|
397
|
+
* @param {...*} args The arguments to pass to the script.
|
|
398
|
+
* @return {!IThenable<T>} A promise that will resolve to the scripts return
|
|
399
|
+
* value.
|
|
446
400
|
* @template T
|
|
447
401
|
*/
|
|
448
|
-
|
|
402
|
+
executeAsyncScript(script, ...args) {}
|
|
449
403
|
|
|
450
404
|
/**
|
|
451
|
-
*
|
|
405
|
+
* Waits for a condition to evaluate to a "truthy" value. The condition may be
|
|
452
406
|
* specified by a {@link Condition}, as a custom function, or as any
|
|
453
407
|
* promise-like thenable.
|
|
454
408
|
*
|
|
455
409
|
* For a {@link Condition} or function, the wait will repeatedly
|
|
456
410
|
* evaluate the condition until it returns a truthy value. If any errors occur
|
|
457
411
|
* while evaluating the condition, they will be allowed to propagate. In the
|
|
458
|
-
* event a condition returns a {@
|
|
459
|
-
*
|
|
460
|
-
*
|
|
461
|
-
*
|
|
412
|
+
* event a condition returns a {@linkplain Promise}, the polling loop will
|
|
413
|
+
* wait for it to be resolved and use the resolved value for whether the
|
|
414
|
+
* condition has been satisfied. The resolution time for a promise is always
|
|
415
|
+
* factored into whether a wait has timed out.
|
|
462
416
|
*
|
|
463
|
-
*
|
|
417
|
+
* If the provided condition is a {@link WebElementCondition}, then
|
|
464
418
|
* the wait will return a {@link WebElementPromise} that will resolve to the
|
|
465
419
|
* element that satisfied the condition.
|
|
466
420
|
*
|
|
467
421
|
* _Example:_ waiting up to 10 seconds for an element to be present on the
|
|
468
422
|
* page.
|
|
469
423
|
*
|
|
470
|
-
*
|
|
471
|
-
*
|
|
472
|
-
*
|
|
473
|
-
*
|
|
474
|
-
*
|
|
475
|
-
* simply wait for its resolution before completing. A timeout may be provided
|
|
476
|
-
* to fail the command if the promise does not resolve before the timeout
|
|
477
|
-
* expires.
|
|
478
|
-
*
|
|
479
|
-
* _Example:_ Suppose you have a function, `startTestServer`, that returns a
|
|
480
|
-
* promise for when a server is ready for requests. You can block a WebDriver
|
|
481
|
-
* client on this promise with:
|
|
482
|
-
*
|
|
483
|
-
* var started = startTestServer();
|
|
484
|
-
* driver.wait(started, 5 * 1000, 'Server should start within 5 seconds');
|
|
485
|
-
* driver.get(getServerUrl());
|
|
424
|
+
* async function example() {
|
|
425
|
+
* let button =
|
|
426
|
+
* await driver.wait(until.elementLocated(By.id('foo')), 10000);
|
|
427
|
+
* await button.click();
|
|
428
|
+
* }
|
|
486
429
|
*
|
|
487
430
|
* @param {!(IThenable<T>|
|
|
488
431
|
* Condition<T>|
|
|
489
432
|
* function(!WebDriver): T)} condition The condition to
|
|
490
433
|
* wait on, defined as a promise, condition object, or a function to
|
|
491
434
|
* evaluate as a condition.
|
|
492
|
-
* @param {number=}
|
|
493
|
-
*
|
|
494
|
-
*
|
|
495
|
-
* @
|
|
435
|
+
* @param {number=} timeout The duration in milliseconds, how long to wait
|
|
436
|
+
* for the condition to be true.
|
|
437
|
+
* @param {string=} message An optional message to use if the wait times out.
|
|
438
|
+
* @param {number=} pollTimeout The duration in milliseconds, how long to
|
|
439
|
+
* wait between polling the condition.
|
|
440
|
+
* @return {!(IThenable<T>|WebElementPromise)} A promise that will be
|
|
496
441
|
* resolved with the first truthy value returned by the condition
|
|
497
442
|
* function, or rejected if the condition times out. If the input
|
|
498
443
|
* input condition is an instance of a {@link WebElementCondition},
|
|
@@ -500,76 +445,82 @@ class IWebDriver {
|
|
|
500
445
|
* @throws {TypeError} if the provided `condition` is not a valid type.
|
|
501
446
|
* @template T
|
|
502
447
|
*/
|
|
503
|
-
wait(condition,
|
|
448
|
+
wait(condition, timeout = undefined, message = undefined, pollTimeout = undefined) {}
|
|
504
449
|
|
|
505
450
|
/**
|
|
506
|
-
*
|
|
451
|
+
* Makes the driver sleep for the given amount of time.
|
|
452
|
+
*
|
|
507
453
|
* @param {number} ms The amount of time, in milliseconds, to sleep.
|
|
508
|
-
* @return {!
|
|
509
|
-
*
|
|
454
|
+
* @return {!Promise<void>} A promise that will be resolved when the sleep has
|
|
455
|
+
* finished.
|
|
510
456
|
*/
|
|
511
457
|
sleep(ms) {}
|
|
512
458
|
|
|
513
459
|
/**
|
|
514
|
-
*
|
|
515
|
-
*
|
|
516
|
-
*
|
|
460
|
+
* Retrieves the current window handle.
|
|
461
|
+
*
|
|
462
|
+
* @return {!Promise<string>} A promise that will be resolved with the current
|
|
463
|
+
* window handle.
|
|
517
464
|
*/
|
|
518
465
|
getWindowHandle() {}
|
|
519
466
|
|
|
520
467
|
/**
|
|
521
|
-
*
|
|
522
|
-
*
|
|
523
|
-
*
|
|
468
|
+
* Retrieves a list of all available window handles.
|
|
469
|
+
*
|
|
470
|
+
* @return {!Promise<!Array<string>>} A promise that will be resolved with an
|
|
471
|
+
* array of window handles.
|
|
524
472
|
*/
|
|
525
473
|
getAllWindowHandles() {}
|
|
526
474
|
|
|
527
475
|
/**
|
|
528
|
-
*
|
|
529
|
-
*
|
|
530
|
-
*
|
|
531
|
-
*
|
|
532
|
-
* @return {!
|
|
533
|
-
*
|
|
476
|
+
* Retrieves the current page's source. The returned souce is a representation
|
|
477
|
+
* of the underlying DOM: do not expect it to be formatted or escaped in the
|
|
478
|
+
* same way as the raw response sent from the web server.
|
|
479
|
+
*
|
|
480
|
+
* @return {!Promise<string>} A promise that will be resolved with the current
|
|
481
|
+
* page source.
|
|
534
482
|
*/
|
|
535
483
|
getPageSource() {}
|
|
536
484
|
|
|
537
485
|
/**
|
|
538
|
-
*
|
|
539
|
-
*
|
|
540
|
-
*
|
|
486
|
+
* Closes the current window.
|
|
487
|
+
*
|
|
488
|
+
* @return {!Promise<void>} A promise that will be resolved when this command
|
|
489
|
+
* has completed.
|
|
541
490
|
*/
|
|
542
491
|
close() {}
|
|
543
492
|
|
|
544
493
|
/**
|
|
545
|
-
*
|
|
494
|
+
* Navigates to the given URL.
|
|
495
|
+
*
|
|
546
496
|
* @param {string} url The fully qualified URL to open.
|
|
547
|
-
* @return {!
|
|
548
|
-
*
|
|
497
|
+
* @return {!Promise<void>} A promise that will be resolved when the document
|
|
498
|
+
* has finished loading.
|
|
549
499
|
*/
|
|
550
500
|
get(url) {}
|
|
551
501
|
|
|
552
502
|
/**
|
|
553
|
-
*
|
|
554
|
-
*
|
|
555
|
-
*
|
|
503
|
+
* Retrieves the URL for the current page.
|
|
504
|
+
*
|
|
505
|
+
* @return {!Promise<string>} A promise that will be resolved with the
|
|
506
|
+
* current URL.
|
|
556
507
|
*/
|
|
557
508
|
getCurrentUrl() {}
|
|
558
509
|
|
|
559
510
|
/**
|
|
560
|
-
*
|
|
561
|
-
*
|
|
562
|
-
*
|
|
511
|
+
* Retrieves the current page title.
|
|
512
|
+
*
|
|
513
|
+
* @return {!Promise<string>} A promise that will be resolved with the current
|
|
514
|
+
* page's title.
|
|
563
515
|
*/
|
|
564
516
|
getTitle() {}
|
|
565
517
|
|
|
566
518
|
/**
|
|
567
|
-
*
|
|
568
|
-
*
|
|
569
|
-
*
|
|
570
|
-
*
|
|
571
|
-
*
|
|
572
|
-
* present on the page, use {@link #findElements}:
|
|
519
|
+
* Locates an element on the page. If the element cannot be found, a
|
|
520
|
+
* {@link error.NoSuchEementError} will be returned by the driver.
|
|
521
|
+
*
|
|
522
|
+
* This function should not be used to test whether an element is present on
|
|
523
|
+
* the page. Rather, you should use {@link #findElements}:
|
|
573
524
|
*
|
|
574
525
|
* driver.findElements(By.id('foo'))
|
|
575
526
|
* .then(found => console.log('Element found? %s', !!found.length));
|
|
@@ -605,16 +556,17 @@ class IWebDriver {
|
|
|
605
556
|
findElement(locator) {}
|
|
606
557
|
|
|
607
558
|
/**
|
|
608
|
-
*
|
|
559
|
+
* Search for multiple elements on the page. Refer to the documentation on
|
|
560
|
+
* {@link #findElement(by)} for information on element locator strategies.
|
|
609
561
|
*
|
|
610
562
|
* @param {!(by.By|Function)} locator The locator to use.
|
|
611
|
-
* @return {!
|
|
612
|
-
*
|
|
563
|
+
* @return {!Promise<!Array<!WebElement>>} A promise that will resolve to an
|
|
564
|
+
* array of WebElements.
|
|
613
565
|
*/
|
|
614
566
|
findElements(locator) {}
|
|
615
567
|
|
|
616
568
|
/**
|
|
617
|
-
*
|
|
569
|
+
* Takes a screenshot of the current page. The driver makes a best effort to
|
|
618
570
|
* return a screenshot of the following, in order of preference:
|
|
619
571
|
*
|
|
620
572
|
* 1. Entire page
|
|
@@ -622,8 +574,8 @@ class IWebDriver {
|
|
|
622
574
|
* 3. Visible portion of the current frame
|
|
623
575
|
* 4. The entire display containing the browser
|
|
624
576
|
*
|
|
625
|
-
* @return {!
|
|
626
|
-
*
|
|
577
|
+
* @return {!Promise<string>} A promise that will be resolved to the
|
|
578
|
+
* screenshot as a base-64 encoded PNG.
|
|
627
579
|
*/
|
|
628
580
|
takeScreenshot() {}
|
|
629
581
|
|
|
@@ -645,6 +597,23 @@ class IWebDriver {
|
|
|
645
597
|
}
|
|
646
598
|
|
|
647
599
|
|
|
600
|
+
/**
|
|
601
|
+
* @param {!Capabilities} capabilities A capabilities object.
|
|
602
|
+
* @return {!Capabilities} A copy of the parameter capabilities, omitting
|
|
603
|
+
* capability names that are not valid W3C names.
|
|
604
|
+
*/
|
|
605
|
+
function filterNonW3CCaps(capabilities) {
|
|
606
|
+
let newCaps = new Capabilities(capabilities);
|
|
607
|
+
for (let k of newCaps.keys()) {
|
|
608
|
+
// Any key containing a colon is a vendor-prefixed capability.
|
|
609
|
+
if (!(W3C_CAPABILITY_NAMES.has(k) || k.indexOf(':') >= 0)) {
|
|
610
|
+
newCaps.delete(k);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
return newCaps;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
|
|
648
617
|
/**
|
|
649
618
|
* Each WebDriver instance provides automated control over a browser session.
|
|
650
619
|
*
|
|
@@ -652,21 +621,21 @@ class IWebDriver {
|
|
|
652
621
|
*/
|
|
653
622
|
class WebDriver {
|
|
654
623
|
/**
|
|
655
|
-
* @param {!(Session|IThenable
|
|
656
|
-
* promise that will be resolved to a session.
|
|
624
|
+
* @param {!(./session.Session|IThenable<!./session.Session>)} session Either
|
|
625
|
+
* a known session or a promise that will be resolved to a session.
|
|
657
626
|
* @param {!command.Executor} executor The executor to use when sending
|
|
658
627
|
* commands to the browser.
|
|
659
|
-
* @param {
|
|
660
|
-
* schedule commands through. Defaults to the active flow object.
|
|
661
|
-
* @param {(function(this: void): ?)=} opt_onQuit A function to call, if any,
|
|
628
|
+
* @param {(function(this: void): ?)=} onQuit A function to call, if any,
|
|
662
629
|
* when the session is terminated.
|
|
663
630
|
*/
|
|
664
|
-
constructor(session, executor,
|
|
665
|
-
/** @private {!
|
|
666
|
-
this.
|
|
631
|
+
constructor(session, executor, onQuit = undefined) {
|
|
632
|
+
/** @private {!Promise<!Session>} */
|
|
633
|
+
this.session_ = Promise.resolve(session);
|
|
667
634
|
|
|
668
|
-
|
|
669
|
-
|
|
635
|
+
// If session is a rejected promise, add a no-op rejection handler.
|
|
636
|
+
// This effectively hides setup errors until users attempt to interact
|
|
637
|
+
// with the session.
|
|
638
|
+
this.session_.catch(function() {});
|
|
670
639
|
|
|
671
640
|
/** @private {!command.Executor} */
|
|
672
641
|
this.executor_ = executor;
|
|
@@ -675,63 +644,17 @@ class WebDriver {
|
|
|
675
644
|
this.fileDetector_ = null;
|
|
676
645
|
|
|
677
646
|
/** @private @const {(function(this: void): ?|undefined)} */
|
|
678
|
-
this.onQuit_ =
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
/**
|
|
682
|
-
* Creates a new WebDriver client for an existing session.
|
|
683
|
-
* @param {!command.Executor} executor Command executor to use when querying
|
|
684
|
-
* for session details.
|
|
685
|
-
* @param {string} sessionId ID of the session to attach to.
|
|
686
|
-
* @param {promise.ControlFlow=} opt_flow The control flow all
|
|
687
|
-
* driver commands should execute under. Defaults to the
|
|
688
|
-
* {@link promise.controlFlow() currently active} control flow.
|
|
689
|
-
* @return {!WebDriver} A new client for the specified session.
|
|
690
|
-
*/
|
|
691
|
-
static attachToSession(executor, sessionId, opt_flow) {
|
|
692
|
-
let flow = opt_flow || promise.controlFlow();
|
|
693
|
-
let cmd = new command.Command(command.Name.DESCRIBE_SESSION)
|
|
694
|
-
.setParameter('sessionId', sessionId);
|
|
695
|
-
let session = flow.execute(
|
|
696
|
-
() => executeCommand(executor, cmd).catch(err => {
|
|
697
|
-
// The DESCRIBE_SESSION command is not supported by the W3C spec, so
|
|
698
|
-
// if we get back an unknown command, just return a session with
|
|
699
|
-
// unknown capabilities.
|
|
700
|
-
if (err instanceof error.UnknownCommandError) {
|
|
701
|
-
return new Session(sessionId, new Capabilities);
|
|
702
|
-
}
|
|
703
|
-
throw err;
|
|
704
|
-
}),
|
|
705
|
-
'WebDriver.attachToSession()');
|
|
706
|
-
return new WebDriver(session, executor, flow);
|
|
647
|
+
this.onQuit_ = onQuit;
|
|
707
648
|
}
|
|
708
649
|
|
|
709
650
|
/**
|
|
710
651
|
* Creates a new WebDriver session.
|
|
711
652
|
*
|
|
712
|
-
* By default, the requested session `capabilities` are merely "desired" and
|
|
713
|
-
* the remote end will still create a new session even if it cannot satisfy
|
|
714
|
-
* all of the requested capabilities. You can query which capabilities a
|
|
715
|
-
* session actually has using the
|
|
716
|
-
* {@linkplain #getCapabilities() getCapabilities()} method on the returned
|
|
717
|
-
* WebDriver instance.
|
|
718
|
-
*
|
|
719
|
-
* To define _required capabilities_, provide the `capabilities` as an object
|
|
720
|
-
* literal with `required` and `desired` keys. The `desired` key may be
|
|
721
|
-
* omitted if all capabilities are required, and vice versa. If the server
|
|
722
|
-
* cannot create a session with all of the required capabilities, it will
|
|
723
|
-
* return an {@linkplain error.SessionNotCreatedError}.
|
|
724
|
-
*
|
|
725
|
-
* let required = new Capabilities().set('browserName', 'firefox');
|
|
726
|
-
* let desired = new Capabilities().set('version', '45');
|
|
727
|
-
* let driver = WebDriver.createSession(executor, {required, desired});
|
|
728
|
-
*
|
|
729
653
|
* This function will always return a WebDriver instance. If there is an error
|
|
730
654
|
* creating the session, such as the aforementioned SessionNotCreatedError,
|
|
731
655
|
* the driver will have a rejected {@linkplain #getSession session} promise.
|
|
732
|
-
*
|
|
733
|
-
*
|
|
734
|
-
* cause subsequent commands to fail.
|
|
656
|
+
* This rejection will propagate through any subsequent commands scheduled
|
|
657
|
+
* on the returned WebDriver instance.
|
|
735
658
|
*
|
|
736
659
|
* let required = Capabilities.firefox();
|
|
737
660
|
* let driver = WebDriver.createSession(executor, {required});
|
|
@@ -742,77 +665,39 @@ class WebDriver {
|
|
|
742
665
|
*
|
|
743
666
|
* @param {!command.Executor} executor The executor to create the new session
|
|
744
667
|
* with.
|
|
745
|
-
* @param {
|
|
746
|
-
*
|
|
747
|
-
*
|
|
748
|
-
* capabilities for the new session.
|
|
749
|
-
* @param {promise.ControlFlow=} opt_flow The control flow all driver
|
|
750
|
-
* commands should execute under, including the initial session creation.
|
|
751
|
-
* Defaults to the {@link promise.controlFlow() currently active}
|
|
752
|
-
* control flow.
|
|
753
|
-
* @param {(function(this: void): ?)=} opt_onQuit A callback to invoke when
|
|
668
|
+
* @param {!Capabilities} capabilities The desired capabilities for the new
|
|
669
|
+
* session.
|
|
670
|
+
* @param {(function(this: void): ?)=} onQuit A callback to invoke when
|
|
754
671
|
* the newly created session is terminated. This should be used to clean
|
|
755
672
|
* up any resources associated with the session.
|
|
756
673
|
* @return {!WebDriver} The driver for the newly created session.
|
|
757
674
|
*/
|
|
758
|
-
static createSession(executor, capabilities,
|
|
759
|
-
let flow = opt_flow || promise.controlFlow();
|
|
675
|
+
static createSession(executor, capabilities, onQuit = undefined) {
|
|
760
676
|
let cmd = new command.Command(command.Name.NEW_SESSION);
|
|
761
677
|
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
}
|
|
678
|
+
// For OSS remote ends.
|
|
679
|
+
cmd.setParameter('desiredCapabilities', capabilities);
|
|
680
|
+
// For W3C remote ends.
|
|
681
|
+
cmd.setParameter('capabilities', {
|
|
682
|
+
alwaysMatch: filterNonW3CCaps(capabilities),
|
|
683
|
+
});
|
|
768
684
|
|
|
769
|
-
let session =
|
|
770
|
-
|
|
771
|
-
'WebDriver.createSession()');
|
|
772
|
-
if (typeof opt_onQuit === 'function') {
|
|
685
|
+
let session = executeCommand(executor, cmd);
|
|
686
|
+
if (typeof onQuit === 'function') {
|
|
773
687
|
session = session.catch(err => {
|
|
774
|
-
return Promise.resolve(
|
|
688
|
+
return Promise.resolve(onQuit.call(void 0)).then(_ => {throw err;});
|
|
775
689
|
});
|
|
776
690
|
}
|
|
777
|
-
return new this(session, executor,
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
/** @override */
|
|
781
|
-
controlFlow() {
|
|
782
|
-
return this.flow_;
|
|
691
|
+
return new this(session, executor, onQuit);
|
|
783
692
|
}
|
|
784
693
|
|
|
785
694
|
/** @override */
|
|
786
|
-
|
|
695
|
+
async execute(command) {
|
|
787
696
|
command.setParameter('sessionId', this.session_);
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
// propagate through the command itself, we resolve all of the
|
|
793
|
-
// command parameters now, but suppress any errors until the ControlFlow
|
|
794
|
-
// actually executes the command. This addresses scenarios like catching
|
|
795
|
-
// an element not found error in:
|
|
796
|
-
//
|
|
797
|
-
// driver.findElement(By.id('foo')).click().catch(function(e) {
|
|
798
|
-
// if (e instanceof NoSuchElementError) {
|
|
799
|
-
// // Do something.
|
|
800
|
-
// }
|
|
801
|
-
// });
|
|
802
|
-
var prepCommand = toWireValue(command.getParameters());
|
|
803
|
-
prepCommand.catch(function() {});
|
|
804
|
-
|
|
805
|
-
var flow = this.flow_;
|
|
806
|
-
var executor = this.executor_;
|
|
807
|
-
return flow.execute(() => {
|
|
808
|
-
// Retrieve resolved command parameters; any previously suppressed errors
|
|
809
|
-
// will now propagate up through the control flow as part of the command
|
|
810
|
-
// execution.
|
|
811
|
-
return prepCommand.then(function(parameters) {
|
|
812
|
-
command.setParameters(parameters);
|
|
813
|
-
return executor.execute(command);
|
|
814
|
-
}).then(value => fromWireValue(this, value));
|
|
815
|
-
}, description);
|
|
697
|
+
let parameters = await toWireValue(command.getParameters());
|
|
698
|
+
command.setParameters(parameters);
|
|
699
|
+
let value = await this.executor_.execute(command);
|
|
700
|
+
return fromWireValue(this, value);
|
|
816
701
|
}
|
|
817
702
|
|
|
818
703
|
/** @override */
|
|
@@ -837,17 +722,13 @@ class WebDriver {
|
|
|
837
722
|
|
|
838
723
|
/** @override */
|
|
839
724
|
quit() {
|
|
840
|
-
|
|
841
|
-
new command.Command(command.Name.QUIT),
|
|
842
|
-
'WebDriver.quit()');
|
|
725
|
+
let result = this.execute(new command.Command(command.Name.QUIT));
|
|
843
726
|
// Delete our session ID when the quit command finishes; this will allow us
|
|
844
727
|
// to throw an error when attempting to use a driver post-quit.
|
|
845
|
-
return
|
|
846
|
-
this.session_ =
|
|
847
|
-
reject(new error.NoSuchSessionError(
|
|
728
|
+
return promise.finally(result, () => {
|
|
729
|
+
this.session_ = Promise.reject(new error.NoSuchSessionError(
|
|
848
730
|
'This driver instance does not have a valid session ID ' +
|
|
849
731
|
'(did you call WebDriver.quit()?) and may no longer be used.'));
|
|
850
|
-
});
|
|
851
732
|
|
|
852
733
|
// Only want the session rejection to bubble if accessed.
|
|
853
734
|
this.session_.catch(function() {});
|
|
@@ -855,70 +736,77 @@ class WebDriver {
|
|
|
855
736
|
if (this.onQuit_) {
|
|
856
737
|
return this.onQuit_.call(void 0);
|
|
857
738
|
}
|
|
858
|
-
})
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
/** @override */
|
|
862
|
-
actions() {
|
|
863
|
-
return new actions.ActionSequence(this);
|
|
739
|
+
});
|
|
864
740
|
}
|
|
865
741
|
|
|
866
742
|
/** @override */
|
|
867
|
-
|
|
868
|
-
return new
|
|
743
|
+
actions(options) {
|
|
744
|
+
return new input.Actions(this, options || undefined);
|
|
869
745
|
}
|
|
870
746
|
|
|
871
747
|
/** @override */
|
|
872
|
-
executeScript(script,
|
|
748
|
+
executeScript(script, ...args) {
|
|
873
749
|
if (typeof script === 'function') {
|
|
874
750
|
script = 'return (' + script + ').apply(null, arguments);';
|
|
875
751
|
}
|
|
876
|
-
|
|
877
|
-
arguments.length > 1 ? Array.prototype.slice.call(arguments, 1) : [];
|
|
878
|
-
return this.schedule(
|
|
752
|
+
return this.execute(
|
|
879
753
|
new command.Command(command.Name.EXECUTE_SCRIPT).
|
|
880
754
|
setParameter('script', script).
|
|
881
|
-
setParameter('args', args)
|
|
882
|
-
'WebDriver.executeScript()');
|
|
755
|
+
setParameter('args', args));
|
|
883
756
|
}
|
|
884
757
|
|
|
885
758
|
/** @override */
|
|
886
|
-
executeAsyncScript(script,
|
|
759
|
+
executeAsyncScript(script, ...args) {
|
|
887
760
|
if (typeof script === 'function') {
|
|
888
761
|
script = 'return (' + script + ').apply(null, arguments);';
|
|
889
762
|
}
|
|
890
|
-
|
|
891
|
-
return this.schedule(
|
|
763
|
+
return this.execute(
|
|
892
764
|
new command.Command(command.Name.EXECUTE_ASYNC_SCRIPT).
|
|
893
765
|
setParameter('script', script).
|
|
894
|
-
setParameter('args', args)
|
|
895
|
-
'WebDriver.executeScript()');
|
|
766
|
+
setParameter('args', args));
|
|
896
767
|
}
|
|
897
768
|
|
|
898
769
|
/** @override */
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
return fn.apply(opt_scope, args);
|
|
908
|
-
});
|
|
909
|
-
}, 'WebDriver.call(' + (fn.name || 'function') + ')');
|
|
910
|
-
}
|
|
770
|
+
wait(condition, timeout = 0, message = undefined, pollTimeout = 200) {
|
|
771
|
+
if (typeof timeout !== 'number' || timeout < 0) {
|
|
772
|
+
throw TypeError('timeout must be a number >= 0: ' + timeout);
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
if (typeof pollTimeout !== 'number' || pollTimeout < 0) {
|
|
776
|
+
throw TypeError('pollTimeout must be a number >= 0: ' + pollTimeout);
|
|
777
|
+
}
|
|
911
778
|
|
|
912
|
-
/** @override */
|
|
913
|
-
wait(condition, opt_timeout, opt_message) {
|
|
914
779
|
if (promise.isPromise(condition)) {
|
|
915
|
-
return
|
|
916
|
-
|
|
917
|
-
|
|
780
|
+
return new Promise((resolve, reject) => {
|
|
781
|
+
if (!timeout) {
|
|
782
|
+
resolve(condition);
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
let start = Date.now();
|
|
787
|
+
let timer = setTimeout(function() {
|
|
788
|
+
timer = null;
|
|
789
|
+
reject(
|
|
790
|
+
new error.TimeoutError(
|
|
791
|
+
(message ? `${message}\n` : '')
|
|
792
|
+
+ 'Timed out waiting for promise to resolve after '
|
|
793
|
+
+ (Date.now() - start) + 'ms'));
|
|
794
|
+
}, timeout);
|
|
795
|
+
const clearTimer = () => timer && clearTimeout(timer);
|
|
796
|
+
|
|
797
|
+
/** @type {!IThenable} */(condition).then(
|
|
798
|
+
function(value) {
|
|
799
|
+
clearTimer();
|
|
800
|
+
resolve(value);
|
|
801
|
+
},
|
|
802
|
+
function(error) {
|
|
803
|
+
clearTimer();
|
|
804
|
+
reject(error);
|
|
805
|
+
});
|
|
806
|
+
});
|
|
918
807
|
}
|
|
919
808
|
|
|
920
|
-
|
|
921
|
-
var fn = /** @type {!Function} */(condition);
|
|
809
|
+
let fn = /** @type {!Function} */(condition);
|
|
922
810
|
if (condition instanceof Condition) {
|
|
923
811
|
message = message || condition.description();
|
|
924
812
|
fn = condition.fn;
|
|
@@ -930,13 +818,36 @@ class WebDriver {
|
|
|
930
818
|
+ 'Condition object');
|
|
931
819
|
}
|
|
932
820
|
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
821
|
+
const driver = this;
|
|
822
|
+
function evaluateCondition() {
|
|
823
|
+
return new Promise((resolve, reject) => {
|
|
824
|
+
try {
|
|
825
|
+
resolve(fn(driver));
|
|
826
|
+
} catch (ex) {
|
|
827
|
+
reject(ex);
|
|
828
|
+
}
|
|
829
|
+
});
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
let result = new Promise((resolve, reject) => {
|
|
833
|
+
const startTime = Date.now();
|
|
834
|
+
const pollCondition = async () => {
|
|
835
|
+
evaluateCondition().then(function(value) {
|
|
836
|
+
const elapsed = Date.now() - startTime;
|
|
837
|
+
if (!!value) {
|
|
838
|
+
resolve(value);
|
|
839
|
+
} else if (timeout && elapsed >= timeout) {
|
|
840
|
+
reject(
|
|
841
|
+
new error.TimeoutError(
|
|
842
|
+
(message ? `${message}\n` : '')
|
|
843
|
+
+ `Wait timed out after ${elapsed}ms`));
|
|
844
|
+
} else {
|
|
845
|
+
setTimeout(pollCondition, pollTimeout);
|
|
846
|
+
}
|
|
847
|
+
}, reject);
|
|
848
|
+
};
|
|
849
|
+
pollCondition();
|
|
850
|
+
});
|
|
940
851
|
|
|
941
852
|
if (condition instanceof WebElementCondition) {
|
|
942
853
|
result = new WebElementPromise(this, result.then(function(value) {
|
|
@@ -953,34 +864,30 @@ class WebDriver {
|
|
|
953
864
|
|
|
954
865
|
/** @override */
|
|
955
866
|
sleep(ms) {
|
|
956
|
-
return
|
|
867
|
+
return new Promise(resolve => setTimeout(() => resolve(), ms));
|
|
957
868
|
}
|
|
958
869
|
|
|
959
870
|
/** @override */
|
|
960
871
|
getWindowHandle() {
|
|
961
|
-
return this.
|
|
962
|
-
new command.Command(command.Name.GET_CURRENT_WINDOW_HANDLE)
|
|
963
|
-
'WebDriver.getWindowHandle()');
|
|
872
|
+
return this.execute(
|
|
873
|
+
new command.Command(command.Name.GET_CURRENT_WINDOW_HANDLE));
|
|
964
874
|
}
|
|
965
875
|
|
|
966
876
|
/** @override */
|
|
967
877
|
getAllWindowHandles() {
|
|
968
|
-
return this.
|
|
969
|
-
new command.Command(command.Name.GET_WINDOW_HANDLES)
|
|
970
|
-
'WebDriver.getAllWindowHandles()');
|
|
878
|
+
return this.execute(
|
|
879
|
+
new command.Command(command.Name.GET_WINDOW_HANDLES));
|
|
971
880
|
}
|
|
972
881
|
|
|
973
882
|
/** @override */
|
|
974
883
|
getPageSource() {
|
|
975
|
-
return this.
|
|
976
|
-
new command.Command(command.Name.GET_PAGE_SOURCE)
|
|
977
|
-
'WebDriver.getPageSource()');
|
|
884
|
+
return this.execute(
|
|
885
|
+
new command.Command(command.Name.GET_PAGE_SOURCE));
|
|
978
886
|
}
|
|
979
887
|
|
|
980
888
|
/** @override */
|
|
981
889
|
close() {
|
|
982
|
-
return this.
|
|
983
|
-
'WebDriver.close()');
|
|
890
|
+
return this.execute(new command.Command(command.Name.CLOSE));
|
|
984
891
|
}
|
|
985
892
|
|
|
986
893
|
/** @override */
|
|
@@ -990,15 +897,12 @@ class WebDriver {
|
|
|
990
897
|
|
|
991
898
|
/** @override */
|
|
992
899
|
getCurrentUrl() {
|
|
993
|
-
return this.
|
|
994
|
-
new command.Command(command.Name.GET_CURRENT_URL),
|
|
995
|
-
'WebDriver.getCurrentUrl()');
|
|
900
|
+
return this.execute(new command.Command(command.Name.GET_CURRENT_URL));
|
|
996
901
|
}
|
|
997
902
|
|
|
998
903
|
/** @override */
|
|
999
904
|
getTitle() {
|
|
1000
|
-
return this.
|
|
1001
|
-
'WebDriver.getTitle()');
|
|
905
|
+
return this.execute(new command.Command(command.Name.GET_TITLE));
|
|
1002
906
|
}
|
|
1003
907
|
|
|
1004
908
|
/** @override */
|
|
@@ -1011,33 +915,31 @@ class WebDriver {
|
|
|
1011
915
|
let cmd = new command.Command(command.Name.FIND_ELEMENT).
|
|
1012
916
|
setParameter('using', locator.using).
|
|
1013
917
|
setParameter('value', locator.value);
|
|
1014
|
-
id = this.
|
|
918
|
+
id = this.execute(cmd);
|
|
1015
919
|
}
|
|
1016
920
|
return new WebElementPromise(this, id);
|
|
1017
921
|
}
|
|
1018
922
|
|
|
1019
923
|
/**
|
|
1020
924
|
* @param {!Function} locatorFn The locator function to use.
|
|
1021
|
-
* @param {!(WebDriver|WebElement)} context The search
|
|
1022
|
-
*
|
|
1023
|
-
*
|
|
1024
|
-
* promise that will resolve to a list of WebElements.
|
|
925
|
+
* @param {!(WebDriver|WebElement)} context The search context.
|
|
926
|
+
* @return {!Promise<!WebElement>} A promise that will resolve to a list of
|
|
927
|
+
* WebElements.
|
|
1025
928
|
* @private
|
|
1026
929
|
*/
|
|
1027
|
-
findElementInternal_(locatorFn, context) {
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
});
|
|
930
|
+
async findElementInternal_(locatorFn, context) {
|
|
931
|
+
let result = await locatorFn(context);
|
|
932
|
+
if (Array.isArray(result)) {
|
|
933
|
+
result = result[0];
|
|
934
|
+
}
|
|
935
|
+
if (!(result instanceof WebElement)) {
|
|
936
|
+
throw new TypeError('Custom locator did not return a WebElement');
|
|
937
|
+
}
|
|
938
|
+
return result;
|
|
1037
939
|
}
|
|
1038
940
|
|
|
1039
941
|
/** @override */
|
|
1040
|
-
findElements(locator) {
|
|
942
|
+
async findElements(locator) {
|
|
1041
943
|
locator = by.checkedLocator(locator);
|
|
1042
944
|
if (typeof locator === 'function') {
|
|
1043
945
|
return this.findElementsInternal_(locator, this);
|
|
@@ -1045,43 +947,43 @@ class WebDriver {
|
|
|
1045
947
|
let cmd = new command.Command(command.Name.FIND_ELEMENTS).
|
|
1046
948
|
setParameter('using', locator.using).
|
|
1047
949
|
setParameter('value', locator.value);
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
950
|
+
try {
|
|
951
|
+
let res = await this.execute(cmd);
|
|
952
|
+
return Array.isArray(res) ? res : [];
|
|
953
|
+
} catch (ex) {
|
|
954
|
+
if (ex instanceof error.NoSuchElementError) {
|
|
1051
955
|
return [];
|
|
1052
956
|
}
|
|
1053
|
-
throw
|
|
1054
|
-
}
|
|
957
|
+
throw ex;
|
|
958
|
+
}
|
|
1055
959
|
}
|
|
1056
960
|
}
|
|
1057
961
|
|
|
1058
962
|
/**
|
|
1059
963
|
* @param {!Function} locatorFn The locator function to use.
|
|
1060
964
|
* @param {!(WebDriver|WebElement)} context The search context.
|
|
1061
|
-
* @return {!
|
|
1062
|
-
*
|
|
965
|
+
* @return {!Promise<!Array<!WebElement>>} A promise that will resolve to an
|
|
966
|
+
* array of WebElements.
|
|
1063
967
|
* @private
|
|
1064
968
|
*/
|
|
1065
|
-
findElementsInternal_(locatorFn, context) {
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
969
|
+
async findElementsInternal_(locatorFn, context) {
|
|
970
|
+
const result = await locatorFn(context);
|
|
971
|
+
if (result instanceof WebElement) {
|
|
972
|
+
return [result];
|
|
973
|
+
}
|
|
1070
974
|
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
975
|
+
if (!Array.isArray(result)) {
|
|
976
|
+
return [];
|
|
977
|
+
}
|
|
1074
978
|
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
});
|
|
979
|
+
return result.filter(function(item) {
|
|
980
|
+
return item instanceof WebElement;
|
|
1078
981
|
});
|
|
1079
982
|
}
|
|
1080
983
|
|
|
1081
984
|
/** @override */
|
|
1082
985
|
takeScreenshot() {
|
|
1083
|
-
return this.
|
|
1084
|
-
'WebDriver.takeScreenshot()');
|
|
986
|
+
return this.execute(new command.Command(command.Name.SCREENSHOT));
|
|
1085
987
|
}
|
|
1086
988
|
|
|
1087
989
|
/** @override */
|
|
@@ -1122,49 +1024,46 @@ class Navigation {
|
|
|
1122
1024
|
}
|
|
1123
1025
|
|
|
1124
1026
|
/**
|
|
1125
|
-
*
|
|
1027
|
+
* Navigates to a new URL.
|
|
1028
|
+
*
|
|
1126
1029
|
* @param {string} url The URL to navigate to.
|
|
1127
|
-
* @return {!
|
|
1128
|
-
*
|
|
1030
|
+
* @return {!Promise<void>} A promise that will be resolved when the URL
|
|
1031
|
+
* has been loaded.
|
|
1129
1032
|
*/
|
|
1130
1033
|
to(url) {
|
|
1131
|
-
return this.driver_.
|
|
1034
|
+
return this.driver_.execute(
|
|
1132
1035
|
new command.Command(command.Name.GET).
|
|
1133
|
-
setParameter('url', url)
|
|
1134
|
-
'WebDriver.navigate().to(' + url + ')');
|
|
1036
|
+
setParameter('url', url));
|
|
1135
1037
|
}
|
|
1136
1038
|
|
|
1137
1039
|
/**
|
|
1138
|
-
*
|
|
1139
|
-
*
|
|
1140
|
-
*
|
|
1040
|
+
* Moves backwards in the browser history.
|
|
1041
|
+
*
|
|
1042
|
+
* @return {!Promise<void>} A promise that will be resolved when the
|
|
1043
|
+
* navigation event has completed.
|
|
1141
1044
|
*/
|
|
1142
1045
|
back() {
|
|
1143
|
-
return this.driver_.
|
|
1144
|
-
new command.Command(command.Name.GO_BACK),
|
|
1145
|
-
'WebDriver.navigate().back()');
|
|
1046
|
+
return this.driver_.execute(new command.Command(command.Name.GO_BACK));
|
|
1146
1047
|
}
|
|
1147
1048
|
|
|
1148
1049
|
/**
|
|
1149
|
-
*
|
|
1150
|
-
*
|
|
1151
|
-
*
|
|
1050
|
+
* Moves forwards in the browser history.
|
|
1051
|
+
*
|
|
1052
|
+
* @return {!Promise<void>} A promise that will be resolved when the
|
|
1053
|
+
* navigation event has completed.
|
|
1152
1054
|
*/
|
|
1153
1055
|
forward() {
|
|
1154
|
-
return this.driver_.
|
|
1155
|
-
new command.Command(command.Name.GO_FORWARD),
|
|
1156
|
-
'WebDriver.navigate().forward()');
|
|
1056
|
+
return this.driver_.execute(new command.Command(command.Name.GO_FORWARD));
|
|
1157
1057
|
}
|
|
1158
1058
|
|
|
1159
1059
|
/**
|
|
1160
|
-
*
|
|
1161
|
-
*
|
|
1162
|
-
*
|
|
1060
|
+
* Refreshes the current page.
|
|
1061
|
+
*
|
|
1062
|
+
* @return {!Promise<void>} A promise that will be resolved when the
|
|
1063
|
+
* navigation event has completed.
|
|
1163
1064
|
*/
|
|
1164
1065
|
refresh() {
|
|
1165
|
-
return this.driver_.
|
|
1166
|
-
new command.Command(command.Name.REFRESH),
|
|
1167
|
-
'WebDriver.navigate().refresh()');
|
|
1066
|
+
return this.driver_.execute(new command.Command(command.Name.REFRESH));
|
|
1168
1067
|
}
|
|
1169
1068
|
}
|
|
1170
1069
|
|
|
@@ -1186,142 +1085,137 @@ class Options {
|
|
|
1186
1085
|
}
|
|
1187
1086
|
|
|
1188
1087
|
/**
|
|
1189
|
-
*
|
|
1088
|
+
* Adds a cookie.
|
|
1190
1089
|
*
|
|
1191
1090
|
* __Sample Usage:__
|
|
1192
1091
|
*
|
|
1193
1092
|
* // Set a basic cookie.
|
|
1194
|
-
* driver.
|
|
1093
|
+
* driver.manage().addCookie({name: 'foo', value: 'bar'});
|
|
1195
1094
|
*
|
|
1196
1095
|
* // Set a cookie that expires in 10 minutes.
|
|
1197
1096
|
* let expiry = new Date(Date.now() + (10 * 60 * 1000));
|
|
1198
|
-
* driver.
|
|
1097
|
+
* driver.manage().addCookie({name: 'foo', value: 'bar', expiry});
|
|
1199
1098
|
*
|
|
1200
1099
|
* // The cookie expiration may also be specified in seconds since epoch.
|
|
1201
|
-
* driver.
|
|
1100
|
+
* driver.manage().addCookie({
|
|
1202
1101
|
* name: 'foo',
|
|
1203
1102
|
* value: 'bar',
|
|
1204
1103
|
* expiry: Math.floor(Date.now() / 1000)
|
|
1205
1104
|
* });
|
|
1206
1105
|
*
|
|
1207
1106
|
* @param {!Options.Cookie} spec Defines the cookie to add.
|
|
1208
|
-
* @return {!
|
|
1107
|
+
* @return {!Promise<void>} A promise that will be resolved
|
|
1209
1108
|
* when the cookie has been added to the page.
|
|
1210
1109
|
* @throws {error.InvalidArgumentError} if any of the cookie parameters are
|
|
1211
1110
|
* invalid.
|
|
1212
1111
|
* @throws {TypeError} if `spec` is not a cookie object.
|
|
1213
1112
|
*/
|
|
1214
|
-
addCookie(
|
|
1215
|
-
if (!spec || typeof spec !== 'object') {
|
|
1216
|
-
throw TypeError('addCookie called with non-cookie parameter');
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1113
|
+
addCookie({name, value, path, domain, secure, httpOnly, expiry}) {
|
|
1219
1114
|
// We do not allow '=' or ';' in the name.
|
|
1220
|
-
let name = spec.name;
|
|
1221
1115
|
if (/[;=]/.test(name)) {
|
|
1222
1116
|
throw new error.InvalidArgumentError(
|
|
1223
1117
|
'Invalid cookie name "' + name + '"');
|
|
1224
1118
|
}
|
|
1225
1119
|
|
|
1226
1120
|
// We do not allow ';' in value.
|
|
1227
|
-
let value = spec.value;
|
|
1228
1121
|
if (/;/.test(value)) {
|
|
1229
1122
|
throw new error.InvalidArgumentError(
|
|
1230
1123
|
'Invalid cookie value "' + value + '"');
|
|
1231
1124
|
}
|
|
1232
1125
|
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
let expiry;
|
|
1239
|
-
if (typeof spec.expiry === 'number') {
|
|
1240
|
-
expiry = Math.floor(spec.expiry);
|
|
1241
|
-
cookieString += ';expires=' + new Date(spec.expiry * 1000).toUTCString();
|
|
1242
|
-
} else if (spec.expiry instanceof Date) {
|
|
1243
|
-
let date = /** @type {!Date} */(spec.expiry);
|
|
1126
|
+
if (typeof expiry === 'number') {
|
|
1127
|
+
expiry = Math.floor(expiry);
|
|
1128
|
+
} else if (expiry instanceof Date) {
|
|
1129
|
+
let date = /** @type {!Date} */(expiry);
|
|
1244
1130
|
expiry = Math.floor(date.getTime() / 1000);
|
|
1245
|
-
cookieString += ';expires=' + date.toUTCString();
|
|
1246
1131
|
}
|
|
1247
1132
|
|
|
1248
|
-
return this.driver_.
|
|
1133
|
+
return this.driver_.execute(
|
|
1249
1134
|
new command.Command(command.Name.ADD_COOKIE).
|
|
1250
1135
|
setParameter('cookie', {
|
|
1251
1136
|
'name': name,
|
|
1252
1137
|
'value': value,
|
|
1253
|
-
'path':
|
|
1254
|
-
'domain':
|
|
1255
|
-
'secure': !!
|
|
1138
|
+
'path': path,
|
|
1139
|
+
'domain': domain,
|
|
1140
|
+
'secure': !!secure,
|
|
1141
|
+
'httpOnly': !!httpOnly,
|
|
1256
1142
|
'expiry': expiry
|
|
1257
|
-
})
|
|
1258
|
-
'WebDriver.manage().addCookie(' + cookieString + ')');
|
|
1143
|
+
}));
|
|
1259
1144
|
}
|
|
1260
1145
|
|
|
1261
1146
|
/**
|
|
1262
|
-
*
|
|
1263
|
-
*
|
|
1147
|
+
* Deletes all cookies visible to the current page.
|
|
1148
|
+
*
|
|
1149
|
+
* @return {!Promise<void>} A promise that will be resolved
|
|
1264
1150
|
* when all cookies have been deleted.
|
|
1265
1151
|
*/
|
|
1266
1152
|
deleteAllCookies() {
|
|
1267
|
-
return this.driver_.
|
|
1268
|
-
new command.Command(command.Name.DELETE_ALL_COOKIES)
|
|
1269
|
-
'WebDriver.manage().deleteAllCookies()');
|
|
1153
|
+
return this.driver_.execute(
|
|
1154
|
+
new command.Command(command.Name.DELETE_ALL_COOKIES));
|
|
1270
1155
|
}
|
|
1271
1156
|
|
|
1272
1157
|
/**
|
|
1273
|
-
*
|
|
1274
|
-
*
|
|
1275
|
-
*
|
|
1158
|
+
* Deletes the cookie with the given name. This command is a no-op if there is
|
|
1159
|
+
* no cookie with the given name visible to the current page.
|
|
1160
|
+
*
|
|
1276
1161
|
* @param {string} name The name of the cookie to delete.
|
|
1277
|
-
* @return {!
|
|
1162
|
+
* @return {!Promise<void>} A promise that will be resolved
|
|
1278
1163
|
* when the cookie has been deleted.
|
|
1279
1164
|
*/
|
|
1280
1165
|
deleteCookie(name) {
|
|
1281
|
-
return this.driver_.
|
|
1166
|
+
return this.driver_.execute(
|
|
1282
1167
|
new command.Command(command.Name.DELETE_COOKIE).
|
|
1283
|
-
setParameter('name', name)
|
|
1284
|
-
'WebDriver.manage().deleteCookie(' + name + ')');
|
|
1168
|
+
setParameter('name', name));
|
|
1285
1169
|
}
|
|
1286
1170
|
|
|
1287
1171
|
/**
|
|
1288
|
-
*
|
|
1289
|
-
*
|
|
1290
|
-
*
|
|
1291
|
-
* @return {!
|
|
1172
|
+
* Retrieves all cookies visible to the current page. Each cookie will be
|
|
1173
|
+
* returned as a JSON object as described by the WebDriver wire protocol.
|
|
1174
|
+
*
|
|
1175
|
+
* @return {!Promise<!Array<!Options.Cookie>>} A promise that will be
|
|
1292
1176
|
* resolved with the cookies visible to the current browsing context.
|
|
1293
1177
|
*/
|
|
1294
1178
|
getCookies() {
|
|
1295
|
-
return this.driver_.
|
|
1296
|
-
new command.Command(command.Name.GET_ALL_COOKIES)
|
|
1297
|
-
'WebDriver.manage().getCookies()');
|
|
1179
|
+
return this.driver_.execute(
|
|
1180
|
+
new command.Command(command.Name.GET_ALL_COOKIES));
|
|
1298
1181
|
}
|
|
1299
1182
|
|
|
1300
1183
|
/**
|
|
1301
|
-
*
|
|
1302
|
-
*
|
|
1303
|
-
*
|
|
1184
|
+
* Retrieves the cookie with the given name. Returns null if there is no such
|
|
1185
|
+
* cookie. The cookie will be returned as a JSON object as described by the
|
|
1186
|
+
* WebDriver wire protocol.
|
|
1304
1187
|
*
|
|
1305
1188
|
* @param {string} name The name of the cookie to retrieve.
|
|
1306
|
-
* @return {!
|
|
1189
|
+
* @return {!Promise<?Options.Cookie>} A promise that will be resolved
|
|
1307
1190
|
* with the named cookie, or `null` if there is no such cookie.
|
|
1308
1191
|
*/
|
|
1309
|
-
getCookie(name) {
|
|
1310
|
-
|
|
1192
|
+
async getCookie(name) {
|
|
1193
|
+
try {
|
|
1194
|
+
const cookie =
|
|
1195
|
+
await this.driver_.execute(
|
|
1196
|
+
new command.Command(command.Name.GET_COOKIE)
|
|
1197
|
+
.setParameter('name', name));
|
|
1198
|
+
return cookie;
|
|
1199
|
+
} catch (err) {
|
|
1200
|
+
if (!(err instanceof error.UnknownCommandError)
|
|
1201
|
+
&& !(err instanceof error.UnsupportedOperationError)) {
|
|
1202
|
+
throw err;
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
const cookies = await this.getCookies();
|
|
1311
1206
|
for (let cookie of cookies) {
|
|
1312
1207
|
if (cookie && cookie['name'] === name) {
|
|
1313
1208
|
return cookie;
|
|
1314
1209
|
}
|
|
1315
1210
|
}
|
|
1316
1211
|
return null;
|
|
1317
|
-
}
|
|
1212
|
+
}
|
|
1318
1213
|
}
|
|
1319
1214
|
|
|
1320
1215
|
/**
|
|
1321
|
-
*
|
|
1322
|
-
* current session.
|
|
1216
|
+
* Fetches the timeouts currently configured for the current session.
|
|
1323
1217
|
*
|
|
1324
|
-
* @return {!
|
|
1218
|
+
* @return {!Promise<{script: number,
|
|
1325
1219
|
* pageLoad: number,
|
|
1326
1220
|
* implicit: number}>} A promise that will be
|
|
1327
1221
|
* resolved with the timeouts currently configured for the current
|
|
@@ -1329,14 +1223,11 @@ class Options {
|
|
|
1329
1223
|
* @see #setTimeouts()
|
|
1330
1224
|
*/
|
|
1331
1225
|
getTimeouts() {
|
|
1332
|
-
return this.driver_.
|
|
1333
|
-
new command.Command(command.Name.GET_TIMEOUT),
|
|
1334
|
-
`WebDriver.manage().getTimeouts()`)
|
|
1226
|
+
return this.driver_.execute(new command.Command(command.Name.GET_TIMEOUT));
|
|
1335
1227
|
}
|
|
1336
1228
|
|
|
1337
1229
|
/**
|
|
1338
|
-
*
|
|
1339
|
-
* session.
|
|
1230
|
+
* Sets the timeout durations associated with the current session.
|
|
1340
1231
|
*
|
|
1341
1232
|
* The following timeouts are supported (all timeouts are specified in
|
|
1342
1233
|
* milliseconds):
|
|
@@ -1358,8 +1249,8 @@ class Options {
|
|
|
1358
1249
|
* pageLoad: (number|null|undefined),
|
|
1359
1250
|
* implicit: (number|null|undefined)}} conf
|
|
1360
1251
|
* The desired timeout configuration.
|
|
1361
|
-
* @return {!
|
|
1362
|
-
*
|
|
1252
|
+
* @return {!Promise<void>} A promise that will be resolved when the timeouts
|
|
1253
|
+
* have been set.
|
|
1363
1254
|
* @throws {!TypeError} if an invalid options object is provided.
|
|
1364
1255
|
* @see #getTimeouts()
|
|
1365
1256
|
* @see <https://w3c.github.io/webdriver/webdriver-spec.html#dfn-set-timeouts>
|
|
@@ -1383,7 +1274,7 @@ class Options {
|
|
|
1383
1274
|
setParam('script', script);
|
|
1384
1275
|
|
|
1385
1276
|
if (valid) {
|
|
1386
|
-
return this.driver_.
|
|
1277
|
+
return this.driver_.execute(cmd)
|
|
1387
1278
|
.catch(() => {
|
|
1388
1279
|
// Fallback to the legacy method.
|
|
1389
1280
|
let cmds = [];
|
|
@@ -1403,21 +1294,12 @@ class Options {
|
|
|
1403
1294
|
}
|
|
1404
1295
|
|
|
1405
1296
|
/**
|
|
1406
|
-
* @return {!Logs} The interface for managing driver
|
|
1407
|
-
* logs.
|
|
1297
|
+
* @return {!Logs} The interface for managing driver logs.
|
|
1408
1298
|
*/
|
|
1409
1299
|
logs() {
|
|
1410
1300
|
return new Logs(this.driver_);
|
|
1411
1301
|
}
|
|
1412
1302
|
|
|
1413
|
-
/**
|
|
1414
|
-
* @return {!Timeouts} The interface for managing driver timeouts.
|
|
1415
|
-
* @deprecated Use {@link #setTimeouts()} instead.
|
|
1416
|
-
*/
|
|
1417
|
-
timeouts() {
|
|
1418
|
-
return new Timeouts(this.driver_);
|
|
1419
|
-
}
|
|
1420
|
-
|
|
1421
1303
|
/**
|
|
1422
1304
|
* @return {!Window} The interface for managing the current window.
|
|
1423
1305
|
*/
|
|
@@ -1431,14 +1313,13 @@ class Options {
|
|
|
1431
1313
|
* @param {!WebDriver} driver
|
|
1432
1314
|
* @param {string} type
|
|
1433
1315
|
* @param {number} ms
|
|
1434
|
-
* @return {!
|
|
1316
|
+
* @return {!Promise<void>}
|
|
1435
1317
|
*/
|
|
1436
1318
|
function legacyTimeout(driver, type, ms) {
|
|
1437
|
-
return driver.
|
|
1319
|
+
return driver.execute(
|
|
1438
1320
|
new command.Command(command.Name.SET_TIMEOUT)
|
|
1439
1321
|
.setParameter('type', type)
|
|
1440
|
-
.setParameter('ms', ms)
|
|
1441
|
-
`WebDriver.manage().setTimeouts({${type}: ${ms}})`);
|
|
1322
|
+
.setParameter('ms', ms));
|
|
1442
1323
|
}
|
|
1443
1324
|
|
|
1444
1325
|
|
|
@@ -1506,8 +1387,7 @@ Options.Cookie.prototype.httpOnly;
|
|
|
1506
1387
|
* When the cookie expires.
|
|
1507
1388
|
*
|
|
1508
1389
|
* When {@linkplain Options#addCookie() adding a cookie}, this may be specified
|
|
1509
|
-
* in _seconds_ since Unix epoch (January 1, 1970).
|
|
1510
|
-
* 20 years in the future if omitted.
|
|
1390
|
+
* as a {@link Date} object, or in _seconds_ since Unix epoch (January 1, 1970).
|
|
1511
1391
|
*
|
|
1512
1392
|
* The expiry is always returned in seconds since epoch when
|
|
1513
1393
|
* {@linkplain Options#getCookies() retrieving cookies} from the browser.
|
|
@@ -1517,89 +1397,6 @@ Options.Cookie.prototype.httpOnly;
|
|
|
1517
1397
|
Options.Cookie.prototype.expiry;
|
|
1518
1398
|
|
|
1519
1399
|
|
|
1520
|
-
/**
|
|
1521
|
-
* An interface for managing timeout behavior for WebDriver instances.
|
|
1522
|
-
*
|
|
1523
|
-
* This class should never be instantiated directly. Instead, obtain an instance
|
|
1524
|
-
* with
|
|
1525
|
-
*
|
|
1526
|
-
* webdriver.manage().timeouts()
|
|
1527
|
-
*
|
|
1528
|
-
* @deprecated This has been deprecated in favor of
|
|
1529
|
-
* {@link Options#setTimeouts()}, which supports setting multiple timeouts
|
|
1530
|
-
* at once.
|
|
1531
|
-
* @see WebDriver#manage()
|
|
1532
|
-
* @see Options#timeouts()
|
|
1533
|
-
*/
|
|
1534
|
-
class Timeouts {
|
|
1535
|
-
/**
|
|
1536
|
-
* @param {!WebDriver} driver The parent driver.
|
|
1537
|
-
* @private
|
|
1538
|
-
*/
|
|
1539
|
-
constructor(driver) {
|
|
1540
|
-
/** @private {!WebDriver} */
|
|
1541
|
-
this.driver_ = driver;
|
|
1542
|
-
}
|
|
1543
|
-
|
|
1544
|
-
/**
|
|
1545
|
-
* Specifies the amount of time the driver should wait when searching for an
|
|
1546
|
-
* element if it is not immediately present.
|
|
1547
|
-
*
|
|
1548
|
-
* When searching for a single element, the driver should poll the page
|
|
1549
|
-
* until the element has been found, or this timeout expires before failing
|
|
1550
|
-
* with a {@link bot.ErrorCode.NO_SUCH_ELEMENT} error. When searching
|
|
1551
|
-
* for multiple elements, the driver should poll the page until at least one
|
|
1552
|
-
* element has been found or this timeout has expired.
|
|
1553
|
-
*
|
|
1554
|
-
* Setting the wait timeout to 0 (its default value), disables implicit
|
|
1555
|
-
* waiting.
|
|
1556
|
-
*
|
|
1557
|
-
* Increasing the implicit wait timeout should be used judiciously as it
|
|
1558
|
-
* will have an adverse effect on test run time, especially when used with
|
|
1559
|
-
* slower location strategies like XPath.
|
|
1560
|
-
*
|
|
1561
|
-
* @param {number} ms The amount of time to wait, in milliseconds.
|
|
1562
|
-
* @return {!promise.Thenable<void>} A promise that will be resolved
|
|
1563
|
-
* when the implicit wait timeout has been set.
|
|
1564
|
-
* @deprecated Use {@link Options#setTimeouts()
|
|
1565
|
-
* driver.manage().setTimeouts({implicit: ms})}.
|
|
1566
|
-
*/
|
|
1567
|
-
implicitlyWait(ms) {
|
|
1568
|
-
return this.driver_.manage().setTimeouts({implicit: ms});
|
|
1569
|
-
}
|
|
1570
|
-
|
|
1571
|
-
/**
|
|
1572
|
-
* Sets the amount of time to wait, in milliseconds, for an asynchronous
|
|
1573
|
-
* script to finish execution before returning an error. If the timeout is
|
|
1574
|
-
* less than or equal to 0, the script will be allowed to run indefinitely.
|
|
1575
|
-
*
|
|
1576
|
-
* @param {number} ms The amount of time to wait, in milliseconds.
|
|
1577
|
-
* @return {!promise.Thenable<void>} A promise that will be resolved
|
|
1578
|
-
* when the script timeout has been set.
|
|
1579
|
-
* @deprecated Use {@link Options#setTimeouts()
|
|
1580
|
-
* driver.manage().setTimeouts({script: ms})}.
|
|
1581
|
-
*/
|
|
1582
|
-
setScriptTimeout(ms) {
|
|
1583
|
-
return this.driver_.manage().setTimeouts({script: ms});
|
|
1584
|
-
}
|
|
1585
|
-
|
|
1586
|
-
/**
|
|
1587
|
-
* Sets the amount of time to wait for a page load to complete before
|
|
1588
|
-
* returning an error. If the timeout is negative, page loads may be
|
|
1589
|
-
* indefinite.
|
|
1590
|
-
*
|
|
1591
|
-
* @param {number} ms The amount of time to wait, in milliseconds.
|
|
1592
|
-
* @return {!promise.Thenable<void>} A promise that will be resolved
|
|
1593
|
-
* when the timeout has been set.
|
|
1594
|
-
* @deprecated Use {@link Options#setTimeouts()
|
|
1595
|
-
* driver.manage().setTimeouts({pageLoad: ms})}.
|
|
1596
|
-
*/
|
|
1597
|
-
pageLoadTimeout(ms) {
|
|
1598
|
-
return this.driver_.manage().setTimeouts({pageLoad: ms});
|
|
1599
|
-
}
|
|
1600
|
-
}
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
1400
|
/**
|
|
1604
1401
|
* An interface for managing the current window.
|
|
1605
1402
|
*
|
|
@@ -1622,76 +1419,114 @@ class Window {
|
|
|
1622
1419
|
}
|
|
1623
1420
|
|
|
1624
1421
|
/**
|
|
1625
|
-
* Retrieves the
|
|
1626
|
-
*
|
|
1627
|
-
*
|
|
1628
|
-
*
|
|
1629
|
-
*
|
|
1630
|
-
*/
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1422
|
+
* Retrieves the a rect describing the current top-level window's size and
|
|
1423
|
+
* position.
|
|
1424
|
+
*
|
|
1425
|
+
* @return {!Promise<{x: number, y: number, width: number, height: number}>}
|
|
1426
|
+
* A promise that will resolve to the window rect of the current window.
|
|
1427
|
+
*/
|
|
1428
|
+
async getRect() {
|
|
1429
|
+
try {
|
|
1430
|
+
return await this.driver_.execute(
|
|
1431
|
+
new command.Command(command.Name.GET_WINDOW_RECT));
|
|
1432
|
+
} catch (ex) {
|
|
1433
|
+
if (ex instanceof error.UnknownCommandError) {
|
|
1434
|
+
let {width, height} =
|
|
1435
|
+
await this.driver_.execute(
|
|
1436
|
+
new command.Command(command.Name.GET_WINDOW_SIZE)
|
|
1437
|
+
.setParameter('windowHandle', 'current'));
|
|
1438
|
+
let {x, y} =
|
|
1439
|
+
await this.driver_.execute(
|
|
1440
|
+
new command.Command(command.Name.GET_WINDOW_POSITION)
|
|
1441
|
+
.setParameter('windowHandle', 'current'));
|
|
1442
|
+
return {x, y, width, height};
|
|
1443
|
+
}
|
|
1444
|
+
throw ex;
|
|
1445
|
+
}
|
|
1636
1446
|
}
|
|
1637
1447
|
|
|
1638
1448
|
/**
|
|
1639
|
-
*
|
|
1640
|
-
*
|
|
1641
|
-
*
|
|
1642
|
-
*
|
|
1643
|
-
*
|
|
1644
|
-
*
|
|
1645
|
-
*
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1449
|
+
* Sets the current top-level window's size and position. You may update just
|
|
1450
|
+
* the size by omitting `x` & `y`, or just the position by omitting
|
|
1451
|
+
* `width` & `height` options.
|
|
1452
|
+
*
|
|
1453
|
+
* @param {{x: (number|undefined),
|
|
1454
|
+
* y: (number|undefined),
|
|
1455
|
+
* width: (number|undefined),
|
|
1456
|
+
* height: (number|undefined)}} options
|
|
1457
|
+
* The desired window size and position.
|
|
1458
|
+
* @return {!Promise<{x: number, y: number, width: number, height: number}>}
|
|
1459
|
+
* A promise that will resolve to the current widnow's updated window
|
|
1460
|
+
* rect.
|
|
1461
|
+
*/
|
|
1462
|
+
async setRect({x, y, width, height}) {
|
|
1463
|
+
try {
|
|
1464
|
+
return await this.driver_.execute(
|
|
1465
|
+
new command.Command(command.Name.SET_WINDOW_RECT)
|
|
1466
|
+
.setParameters({x, y, width, height}));
|
|
1467
|
+
} catch (ex) {
|
|
1468
|
+
if (ex instanceof error.UnknownCommandError) {
|
|
1469
|
+
if (typeof x === 'number' && typeof y === 'number') {
|
|
1470
|
+
await this.driver_.execute(
|
|
1471
|
+
new command.Command(command.Name.SET_WINDOW_POSITION)
|
|
1472
|
+
.setParameter('windowHandle', 'current')
|
|
1473
|
+
.setParameter('x', x)
|
|
1474
|
+
.setParameter('y', y));
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
if (typeof width === 'number' && typeof height === 'number') {
|
|
1478
|
+
await this.driver_.execute(
|
|
1479
|
+
new command.Command(command.Name.SET_WINDOW_SIZE)
|
|
1480
|
+
.setParameter('windowHandle', 'current')
|
|
1481
|
+
.setParameter('width', width)
|
|
1482
|
+
.setParameter('height', height));
|
|
1483
|
+
}
|
|
1484
|
+
return this.getRect();
|
|
1485
|
+
}
|
|
1486
|
+
throw ex;
|
|
1487
|
+
}
|
|
1654
1488
|
}
|
|
1655
1489
|
|
|
1656
1490
|
/**
|
|
1657
|
-
*
|
|
1658
|
-
*
|
|
1659
|
-
*
|
|
1660
|
-
*
|
|
1491
|
+
* Maximizes the current window. The exact behavior of this command is
|
|
1492
|
+
* specific to individual window managers, but typically involves increasing
|
|
1493
|
+
* the window to the maximum available size without going full-screen.
|
|
1494
|
+
*
|
|
1495
|
+
* @return {!Promise<void>} A promise that will be resolved when the command
|
|
1496
|
+
* has completed.
|
|
1661
1497
|
*/
|
|
1662
|
-
|
|
1663
|
-
return this.driver_.
|
|
1664
|
-
new command.Command(command.Name.
|
|
1665
|
-
setParameter('windowHandle', 'current')
|
|
1666
|
-
'WebDriver.manage().window().getSize()');
|
|
1498
|
+
maximize() {
|
|
1499
|
+
return this.driver_.execute(
|
|
1500
|
+
new command.Command(command.Name.MAXIMIZE_WINDOW).
|
|
1501
|
+
setParameter('windowHandle', 'current'));
|
|
1667
1502
|
}
|
|
1668
1503
|
|
|
1669
1504
|
/**
|
|
1670
|
-
*
|
|
1671
|
-
*
|
|
1672
|
-
*
|
|
1673
|
-
*
|
|
1674
|
-
*
|
|
1505
|
+
* Minimizes the current window. The exact behavior of this command is
|
|
1506
|
+
* specific to individual window managers, but typicallly involves hiding
|
|
1507
|
+
* the window in the system tray.
|
|
1508
|
+
*
|
|
1509
|
+
* @return {!Promise<void>} A promise that will be resolved when the command
|
|
1510
|
+
* has completed.
|
|
1675
1511
|
*/
|
|
1676
|
-
|
|
1677
|
-
return this.driver_.
|
|
1678
|
-
new command.Command(command.Name.
|
|
1679
|
-
setParameter('windowHandle', 'current').
|
|
1680
|
-
setParameter('width', width).
|
|
1681
|
-
setParameter('height', height),
|
|
1682
|
-
'WebDriver.manage().window().setSize(' + width + ', ' + height + ')');
|
|
1512
|
+
minimize() {
|
|
1513
|
+
return this.driver_.execute(
|
|
1514
|
+
new command.Command(command.Name.MINIMIZE_WINDOW));
|
|
1683
1515
|
}
|
|
1684
1516
|
|
|
1685
1517
|
/**
|
|
1686
|
-
*
|
|
1687
|
-
*
|
|
1688
|
-
*
|
|
1518
|
+
* Invokes the "full screen" operation on the current window. The exact
|
|
1519
|
+
* behavior of this command is specific to individual window managers, but
|
|
1520
|
+
* this will typically increase the window size to the size of the physical
|
|
1521
|
+
* display and hide the browser chrome.
|
|
1522
|
+
*
|
|
1523
|
+
* @return {!Promise<void>} A promise that will be resolved when the command
|
|
1524
|
+
* has completed.
|
|
1525
|
+
* @see <https://fullscreen.spec.whatwg.org/#fullscreen-an-element>
|
|
1689
1526
|
*/
|
|
1690
|
-
|
|
1691
|
-
return this.driver_.
|
|
1692
|
-
new command.Command(command.Name.
|
|
1693
|
-
setParameter('windowHandle', 'current'),
|
|
1694
|
-
'WebDriver.manage().window().maximize()');
|
|
1527
|
+
fullscreen() {
|
|
1528
|
+
return this.driver_.execute(
|
|
1529
|
+
new command.Command(command.Name.FULLSCREEN_WINDOW));
|
|
1695
1530
|
}
|
|
1696
1531
|
}
|
|
1697
1532
|
|
|
@@ -1726,15 +1561,14 @@ class Logs {
|
|
|
1726
1561
|
* entries since the last call, or from the start of the session.
|
|
1727
1562
|
*
|
|
1728
1563
|
* @param {!logging.Type} type The desired log type.
|
|
1729
|
-
* @return {!
|
|
1564
|
+
* @return {!Promise<!Array.<!logging.Entry>>} A
|
|
1730
1565
|
* promise that will resolve to a list of log entries for the specified
|
|
1731
1566
|
* type.
|
|
1732
1567
|
*/
|
|
1733
1568
|
get(type) {
|
|
1734
1569
|
let cmd = new command.Command(command.Name.GET_LOG).
|
|
1735
1570
|
setParameter('type', type);
|
|
1736
|
-
return this.driver_.
|
|
1737
|
-
cmd, 'WebDriver.manage().logs().get(' + type + ')').
|
|
1571
|
+
return this.driver_.execute(cmd).
|
|
1738
1572
|
then(function(entries) {
|
|
1739
1573
|
return entries.map(function(entry) {
|
|
1740
1574
|
if (!(entry instanceof logging.Entry)) {
|
|
@@ -1749,13 +1583,12 @@ class Logs {
|
|
|
1749
1583
|
|
|
1750
1584
|
/**
|
|
1751
1585
|
* Retrieves the log types available to this driver.
|
|
1752
|
-
* @return {!
|
|
1586
|
+
* @return {!Promise<!Array<!logging.Type>>} A
|
|
1753
1587
|
* promise that will resolve to a list of available log types.
|
|
1754
1588
|
*/
|
|
1755
1589
|
getAvailableLogTypes() {
|
|
1756
|
-
return this.driver_.
|
|
1757
|
-
new command.Command(command.Name.GET_AVAILABLE_LOG_TYPES)
|
|
1758
|
-
'WebDriver.manage().logs().getAvailableLogTypes()');
|
|
1590
|
+
return this.driver_.execute(
|
|
1591
|
+
new command.Command(command.Name.GET_AVAILABLE_LOG_TYPES));
|
|
1759
1592
|
}
|
|
1760
1593
|
}
|
|
1761
1594
|
|
|
@@ -1781,35 +1614,34 @@ class TargetLocator {
|
|
|
1781
1614
|
}
|
|
1782
1615
|
|
|
1783
1616
|
/**
|
|
1784
|
-
*
|
|
1785
|
-
*
|
|
1617
|
+
* Locates the DOM element on the current page that corresponds to
|
|
1618
|
+
* `document.activeElement` or `document.body` if the active element is not
|
|
1786
1619
|
* available.
|
|
1620
|
+
*
|
|
1787
1621
|
* @return {!WebElementPromise} The active element.
|
|
1788
1622
|
*/
|
|
1789
1623
|
activeElement() {
|
|
1790
|
-
var id = this.driver_.
|
|
1791
|
-
new command.Command(command.Name.GET_ACTIVE_ELEMENT)
|
|
1792
|
-
'WebDriver.switchTo().activeElement()');
|
|
1624
|
+
var id = this.driver_.execute(
|
|
1625
|
+
new command.Command(command.Name.GET_ACTIVE_ELEMENT));
|
|
1793
1626
|
return new WebElementPromise(this.driver_, id);
|
|
1794
1627
|
}
|
|
1795
1628
|
|
|
1796
1629
|
/**
|
|
1797
|
-
*
|
|
1798
|
-
*
|
|
1799
|
-
*
|
|
1630
|
+
* Switches focus of all future commands to the topmost frame in the current
|
|
1631
|
+
* window.
|
|
1632
|
+
*
|
|
1633
|
+
* @return {!Promise<void>} A promise that will be resolved
|
|
1800
1634
|
* when the driver has changed focus to the default content.
|
|
1801
1635
|
*/
|
|
1802
1636
|
defaultContent() {
|
|
1803
|
-
return this.driver_.
|
|
1637
|
+
return this.driver_.execute(
|
|
1804
1638
|
new command.Command(command.Name.SWITCH_TO_FRAME).
|
|
1805
|
-
setParameter('id', null)
|
|
1806
|
-
'WebDriver.switchTo().defaultContent()');
|
|
1639
|
+
setParameter('id', null));
|
|
1807
1640
|
}
|
|
1808
1641
|
|
|
1809
1642
|
/**
|
|
1810
|
-
*
|
|
1811
|
-
*
|
|
1812
|
-
* following:
|
|
1643
|
+
* Changes the focus of all future commands to another frame on the page. The
|
|
1644
|
+
* target frame may be specified as one of the following:
|
|
1813
1645
|
*
|
|
1814
1646
|
* - A number that specifies a (zero-based) index into [window.frames](
|
|
1815
1647
|
* https://developer.mozilla.org/en-US/docs/Web/API/Window.frames).
|
|
@@ -1822,51 +1654,82 @@ class TargetLocator {
|
|
|
1822
1654
|
* rejected with a {@linkplain error.NoSuchFrameError}.
|
|
1823
1655
|
*
|
|
1824
1656
|
* @param {(number|WebElement|null)} id The frame locator.
|
|
1825
|
-
* @return {!
|
|
1657
|
+
* @return {!Promise<void>} A promise that will be resolved
|
|
1826
1658
|
* when the driver has changed focus to the specified frame.
|
|
1827
1659
|
*/
|
|
1828
1660
|
frame(id) {
|
|
1829
|
-
return this.driver_.
|
|
1661
|
+
return this.driver_.execute(
|
|
1830
1662
|
new command.Command(command.Name.SWITCH_TO_FRAME).
|
|
1831
|
-
setParameter('id', id)
|
|
1832
|
-
'WebDriver.switchTo().frame(' + id + ')');
|
|
1663
|
+
setParameter('id', id));
|
|
1833
1664
|
}
|
|
1834
1665
|
|
|
1835
1666
|
/**
|
|
1836
|
-
*
|
|
1837
|
-
*
|
|
1838
|
-
*
|
|
1667
|
+
* Changes the focus of all future commands to the parent frame of the
|
|
1668
|
+
* currently selected frame. This command has no effect if the driver is
|
|
1669
|
+
* already focused on the top-level browsing context.
|
|
1670
|
+
*
|
|
1671
|
+
* @return {!Promise<void>} A promise that will be resolved when the command
|
|
1672
|
+
* has completed.
|
|
1673
|
+
*/
|
|
1674
|
+
parentFrame() {
|
|
1675
|
+
return this.driver_.execute(
|
|
1676
|
+
new command.Command(command.Name.SWITCH_TO_FRAME_PARENT));
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
/**
|
|
1680
|
+
* Changes the focus of all future commands to another window. Windows may be
|
|
1681
|
+
* specified by their {@code window.name} attribute or by its handle
|
|
1682
|
+
* (as returned by {@link WebDriver#getWindowHandles}).
|
|
1839
1683
|
*
|
|
1840
1684
|
* If the specified window cannot be found, the returned promise will be
|
|
1841
1685
|
* rejected with a {@linkplain error.NoSuchWindowError}.
|
|
1842
1686
|
*
|
|
1843
1687
|
* @param {string} nameOrHandle The name or window handle of the window to
|
|
1844
1688
|
* switch focus to.
|
|
1845
|
-
* @return {!
|
|
1689
|
+
* @return {!Promise<void>} A promise that will be resolved
|
|
1846
1690
|
* when the driver has changed focus to the specified window.
|
|
1847
1691
|
*/
|
|
1848
1692
|
window(nameOrHandle) {
|
|
1849
|
-
return this.driver_.
|
|
1693
|
+
return this.driver_.execute(
|
|
1850
1694
|
new command.Command(command.Name.SWITCH_TO_WINDOW).
|
|
1851
1695
|
// "name" supports the legacy drivers. "handle" is the W3C
|
|
1852
1696
|
// compliant parameter.
|
|
1853
1697
|
setParameter('name', nameOrHandle).
|
|
1854
|
-
setParameter('handle', nameOrHandle)
|
|
1855
|
-
|
|
1698
|
+
setParameter('handle', nameOrHandle));
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
/**
|
|
1702
|
+
* Creates a new browser window and switches the focus for future
|
|
1703
|
+
* commands of this driver to the new window.
|
|
1704
|
+
*
|
|
1705
|
+
* @param {string} typeHint 'window' or 'tab'. The created window is not
|
|
1706
|
+
* guaranteed to be of the requested type; if the driver does not support
|
|
1707
|
+
* the requested type, a new browser window will be created of whatever type
|
|
1708
|
+
* the driver does support.
|
|
1709
|
+
* @return {!Promise<void>} A promise that will be resolved
|
|
1710
|
+
* when the driver has changed focus to the new window.
|
|
1711
|
+
*/
|
|
1712
|
+
newWindow(typeHint) {
|
|
1713
|
+
var driver = this.driver_
|
|
1714
|
+
return this.driver_.execute(
|
|
1715
|
+
new command.Command(command.Name.SWITCH_TO_NEW_WINDOW).
|
|
1716
|
+
setParameter('type', typeHint)
|
|
1717
|
+
).then(function(response) {
|
|
1718
|
+
return driver.switchTo().window(response.handle);
|
|
1719
|
+
});
|
|
1856
1720
|
}
|
|
1857
1721
|
|
|
1858
1722
|
/**
|
|
1859
|
-
*
|
|
1860
|
-
*
|
|
1861
|
-
*
|
|
1723
|
+
* Changes focus to the active modal dialog, such as those opened by
|
|
1724
|
+
* `window.alert()`, `window.confirm()`, and `window.prompt()`. The returned
|
|
1725
|
+
* promise will be rejected with a
|
|
1862
1726
|
* {@linkplain error.NoSuchAlertError} if there are no open alerts.
|
|
1863
1727
|
*
|
|
1864
1728
|
* @return {!AlertPromise} The open alert.
|
|
1865
1729
|
*/
|
|
1866
1730
|
alert() {
|
|
1867
|
-
var text = this.driver_.
|
|
1868
|
-
new command.Command(command.Name.GET_ALERT_TEXT)
|
|
1869
|
-
'WebDriver.switchTo().alert()');
|
|
1731
|
+
var text = this.driver_.execute(
|
|
1732
|
+
new command.Command(command.Name.GET_ALERT_TEXT));
|
|
1870
1733
|
var driver = this.driver_;
|
|
1871
1734
|
return new AlertPromise(driver, text.then(function(text) {
|
|
1872
1735
|
return new Alert(driver, text);
|
|
@@ -1906,17 +1769,17 @@ class WebElement {
|
|
|
1906
1769
|
/** @private {!WebDriver} */
|
|
1907
1770
|
this.driver_ = driver;
|
|
1908
1771
|
|
|
1909
|
-
/** @private {!
|
|
1910
|
-
this.id_ =
|
|
1772
|
+
/** @private {!Promise<string>} */
|
|
1773
|
+
this.id_ = Promise.resolve(id);
|
|
1911
1774
|
}
|
|
1912
1775
|
|
|
1913
1776
|
/**
|
|
1914
1777
|
* @param {string} id The raw ID.
|
|
1915
|
-
* @param {boolean=}
|
|
1778
|
+
* @param {boolean=} noLegacy Whether to exclude the legacy element key.
|
|
1916
1779
|
* @return {!Object} The element ID for use with WebDriver's wire protocol.
|
|
1917
1780
|
*/
|
|
1918
|
-
static buildId(id,
|
|
1919
|
-
return
|
|
1781
|
+
static buildId(id, noLegacy = false) {
|
|
1782
|
+
return noLegacy
|
|
1920
1783
|
? {[ELEMENT_ID_KEY]: id}
|
|
1921
1784
|
: {[ELEMENT_ID_KEY]: id, [LEGACY_ELEMENT_ID_KEY]: id};
|
|
1922
1785
|
}
|
|
@@ -1954,27 +1817,15 @@ class WebElement {
|
|
|
1954
1817
|
*
|
|
1955
1818
|
* @param {!WebElement} a A WebElement.
|
|
1956
1819
|
* @param {!WebElement} b A WebElement.
|
|
1957
|
-
* @return {!
|
|
1820
|
+
* @return {!Promise<boolean>} A promise that will be
|
|
1958
1821
|
* resolved to whether the two WebElements are equal.
|
|
1959
1822
|
*/
|
|
1960
|
-
static equals(a, b) {
|
|
1823
|
+
static async equals(a, b) {
|
|
1961
1824
|
if (a === b) {
|
|
1962
|
-
return
|
|
1825
|
+
return true;
|
|
1963
1826
|
}
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
// If the two element's have the same ID, they should be considered
|
|
1967
|
-
// equal. Otherwise, they may still be equivalent, but we'll need to
|
|
1968
|
-
// ask the server to check for us.
|
|
1969
|
-
if (ids[0] === ids[1]) {
|
|
1970
|
-
return true;
|
|
1971
|
-
}
|
|
1972
|
-
|
|
1973
|
-
let cmd = new command.Command(command.Name.ELEMENT_EQUALS);
|
|
1974
|
-
cmd.setParameter('id', ids[0]);
|
|
1975
|
-
cmd.setParameter('other', ids[1]);
|
|
1976
|
-
return a.driver_.schedule(cmd, 'WebElement.equals()');
|
|
1977
|
-
});
|
|
1827
|
+
return a.driver_.executeScript(
|
|
1828
|
+
'return arguments[0] === arguments[1]', a, b);
|
|
1978
1829
|
}
|
|
1979
1830
|
|
|
1980
1831
|
/** @return {!WebDriver} The parent driver for this instance. */
|
|
@@ -1983,7 +1834,7 @@ class WebElement {
|
|
|
1983
1834
|
}
|
|
1984
1835
|
|
|
1985
1836
|
/**
|
|
1986
|
-
* @return {!
|
|
1837
|
+
* @return {!Promise<string>} A promise that resolves to
|
|
1987
1838
|
* the server-assigned opaque ID assigned to this element.
|
|
1988
1839
|
*/
|
|
1989
1840
|
getId() {
|
|
@@ -2003,16 +1854,14 @@ class WebElement {
|
|
|
2003
1854
|
* parameters under the "id" key.
|
|
2004
1855
|
*
|
|
2005
1856
|
* @param {!command.Command} command The command to schedule.
|
|
2006
|
-
* @
|
|
2007
|
-
* @return {!promise.Thenable<T>} A promise that will be resolved
|
|
2008
|
-
* with the command result.
|
|
1857
|
+
* @return {!Promise<T>} A promise that will be resolved with the result.
|
|
2009
1858
|
* @template T
|
|
2010
1859
|
* @see WebDriver#schedule
|
|
2011
1860
|
* @private
|
|
2012
1861
|
*/
|
|
2013
|
-
|
|
1862
|
+
execute_(command) {
|
|
2014
1863
|
command.setParameter('id', this);
|
|
2015
|
-
return this.driver_.
|
|
1864
|
+
return this.driver_.execute(command);
|
|
2016
1865
|
}
|
|
2017
1866
|
|
|
2018
1867
|
/**
|
|
@@ -2059,48 +1908,46 @@ class WebElement {
|
|
|
2059
1908
|
command.Name.FIND_CHILD_ELEMENT).
|
|
2060
1909
|
setParameter('using', locator.using).
|
|
2061
1910
|
setParameter('value', locator.value);
|
|
2062
|
-
id = this.
|
|
1911
|
+
id = this.execute_(cmd);
|
|
2063
1912
|
}
|
|
2064
1913
|
return new WebElementPromise(this.driver_, id);
|
|
2065
1914
|
}
|
|
2066
1915
|
|
|
2067
1916
|
/**
|
|
2068
|
-
*
|
|
2069
|
-
*
|
|
1917
|
+
* Locates all of the descendants of this element that match the given search
|
|
1918
|
+
* criteria.
|
|
2070
1919
|
*
|
|
2071
1920
|
* @param {!(by.By|Function)} locator The locator strategy to use when
|
|
2072
1921
|
* searching for the element.
|
|
2073
|
-
* @return {!
|
|
2074
|
-
*
|
|
1922
|
+
* @return {!Promise<!Array<!WebElement>>} A promise that will resolve to an
|
|
1923
|
+
* array of WebElements.
|
|
2075
1924
|
*/
|
|
2076
|
-
findElements(locator) {
|
|
1925
|
+
async findElements(locator) {
|
|
2077
1926
|
locator = by.checkedLocator(locator);
|
|
2078
1927
|
let id;
|
|
2079
1928
|
if (typeof locator === 'function') {
|
|
2080
1929
|
return this.driver_.findElementsInternal_(locator, this);
|
|
2081
1930
|
} else {
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
setParameter('
|
|
2085
|
-
|
|
2086
|
-
return
|
|
1931
|
+
let cmd = new command.Command(command.Name.FIND_CHILD_ELEMENTS)
|
|
1932
|
+
.setParameter('using', locator.using)
|
|
1933
|
+
.setParameter('value', locator.value);
|
|
1934
|
+
let result = await this.execute_(cmd);
|
|
1935
|
+
return Array.isArray(result) ? result : [];
|
|
2087
1936
|
}
|
|
2088
1937
|
}
|
|
2089
1938
|
|
|
2090
1939
|
/**
|
|
2091
|
-
*
|
|
2092
|
-
*
|
|
2093
|
-
*
|
|
1940
|
+
* Clicks on this element.
|
|
1941
|
+
*
|
|
1942
|
+
* @return {!Promise<void>} A promise that will be resolved when the click
|
|
1943
|
+
* command has completed.
|
|
2094
1944
|
*/
|
|
2095
1945
|
click() {
|
|
2096
|
-
return this.
|
|
2097
|
-
new command.Command(command.Name.CLICK_ELEMENT),
|
|
2098
|
-
'WebElement.click()');
|
|
1946
|
+
return this.execute_(new command.Command(command.Name.CLICK_ELEMENT));
|
|
2099
1947
|
}
|
|
2100
1948
|
|
|
2101
1949
|
/**
|
|
2102
|
-
*
|
|
2103
|
-
* this instance.
|
|
1950
|
+
* Types a key sequence on the DOM element represented by this instance.
|
|
2104
1951
|
*
|
|
2105
1952
|
* Modifier keys (SHIFT, CONTROL, ALT, META) are stateful; once a modifier is
|
|
2106
1953
|
* processed in the key sequence, that key state is toggled until one of the
|
|
@@ -2147,97 +1994,80 @@ class WebElement {
|
|
|
2147
1994
|
* punctuation keys will be synthesized according to a standard QWERTY en-us
|
|
2148
1995
|
* keyboard layout.
|
|
2149
1996
|
*
|
|
2150
|
-
* @param {...(number|string|!IThenable<(number|string)>)}
|
|
1997
|
+
* @param {...(number|string|!IThenable<(number|string)>)} args The
|
|
2151
1998
|
* sequence of keys to type. Number keys may be referenced numerically or
|
|
2152
1999
|
* by string (1 or '1'). All arguments will be joined into a single
|
|
2153
2000
|
* sequence.
|
|
2154
|
-
* @return {!
|
|
2155
|
-
*
|
|
2156
|
-
*/
|
|
2157
|
-
sendKeys(
|
|
2158
|
-
let keys =
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
throw TypeError(
|
|
2167
|
-
'each key must be a number of string; got ' + type);
|
|
2168
|
-
}
|
|
2001
|
+
* @return {!Promise<void>} A promise that will be resolved when all keys
|
|
2002
|
+
* have been typed.
|
|
2003
|
+
*/
|
|
2004
|
+
async sendKeys(...args) {
|
|
2005
|
+
let keys = [];
|
|
2006
|
+
(await Promise.all(args)).forEach(key => {
|
|
2007
|
+
let type = typeof key;
|
|
2008
|
+
if (type === 'number') {
|
|
2009
|
+
key = String(key);
|
|
2010
|
+
} else if (type !== 'string') {
|
|
2011
|
+
throw TypeError('each key must be a number of string; got ' + type);
|
|
2012
|
+
}
|
|
2169
2013
|
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
return ret;
|
|
2175
|
-
});
|
|
2014
|
+
// The W3C protocol requires keys to be specified as an array where
|
|
2015
|
+
// each element is a single key.
|
|
2016
|
+
keys.push(...key.split(''));
|
|
2017
|
+
});
|
|
2176
2018
|
|
|
2177
2019
|
if (!this.driver_.fileDetector_) {
|
|
2178
|
-
return this.
|
|
2179
|
-
new command.Command(command.Name.SEND_KEYS_TO_ELEMENT)
|
|
2180
|
-
setParameter('text', keys.
|
|
2181
|
-
setParameter('value', keys)
|
|
2182
|
-
'WebElement.sendKeys()');
|
|
2020
|
+
return this.execute_(
|
|
2021
|
+
new command.Command(command.Name.SEND_KEYS_TO_ELEMENT)
|
|
2022
|
+
.setParameter('text', keys.join(''))
|
|
2023
|
+
.setParameter('value', keys));
|
|
2183
2024
|
}
|
|
2184
2025
|
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
.handleFile(element.driver_, keys.join(''));
|
|
2193
|
-
}).then(function(keys) {
|
|
2194
|
-
return element.schedule_(
|
|
2195
|
-
new command.Command(command.Name.SEND_KEYS_TO_ELEMENT).
|
|
2196
|
-
setParameter('text', keys).
|
|
2197
|
-
setParameter('value', keys.split('')),
|
|
2198
|
-
'WebElement.sendKeys()');
|
|
2199
|
-
});
|
|
2200
|
-
}, 'WebElement.sendKeys()');
|
|
2026
|
+
keys =
|
|
2027
|
+
await this.driver_.fileDetector_.handleFile(
|
|
2028
|
+
this.driver_, keys.join(''));
|
|
2029
|
+
return this.execute_(
|
|
2030
|
+
new command.Command(command.Name.SEND_KEYS_TO_ELEMENT)
|
|
2031
|
+
.setParameter('text', keys)
|
|
2032
|
+
.setParameter('value', keys.split('')));
|
|
2201
2033
|
}
|
|
2202
2034
|
|
|
2203
2035
|
/**
|
|
2204
|
-
*
|
|
2205
|
-
*
|
|
2206
|
-
*
|
|
2036
|
+
* Retrieves the element's tag name.
|
|
2037
|
+
*
|
|
2038
|
+
* @return {!Promise<string>} A promise that will be resolved with the
|
|
2039
|
+
* element's tag name.
|
|
2207
2040
|
*/
|
|
2208
2041
|
getTagName() {
|
|
2209
|
-
return this.
|
|
2210
|
-
new command.Command(command.Name.GET_ELEMENT_TAG_NAME)
|
|
2211
|
-
'WebElement.getTagName()');
|
|
2042
|
+
return this.execute_(
|
|
2043
|
+
new command.Command(command.Name.GET_ELEMENT_TAG_NAME));
|
|
2212
2044
|
}
|
|
2213
2045
|
|
|
2214
2046
|
/**
|
|
2215
|
-
*
|
|
2216
|
-
*
|
|
2217
|
-
*
|
|
2218
|
-
*
|
|
2219
|
-
* of rgb(0, 255, 0)).
|
|
2047
|
+
* Retrieves the value of a computed style property for this instance. If
|
|
2048
|
+
* the element inherits the named style from its parent, the parent will be
|
|
2049
|
+
* queried for its value. Where possible, color values will be converted to
|
|
2050
|
+
* their hex representation (e.g. #00ff00 instead of rgb(0, 255, 0)).
|
|
2220
2051
|
*
|
|
2221
2052
|
* _Warning:_ the value returned will be as the browser interprets it, so
|
|
2222
2053
|
* it may be tricky to form a proper assertion.
|
|
2223
2054
|
*
|
|
2224
2055
|
* @param {string} cssStyleProperty The name of the CSS style property to look
|
|
2225
2056
|
* up.
|
|
2226
|
-
* @return {!
|
|
2227
|
-
*
|
|
2057
|
+
* @return {!Promise<string>} A promise that will be resolved with the
|
|
2058
|
+
* requested CSS value.
|
|
2228
2059
|
*/
|
|
2229
2060
|
getCssValue(cssStyleProperty) {
|
|
2230
2061
|
var name = command.Name.GET_ELEMENT_VALUE_OF_CSS_PROPERTY;
|
|
2231
|
-
return this.
|
|
2062
|
+
return this.execute_(
|
|
2232
2063
|
new command.Command(name).
|
|
2233
|
-
setParameter('propertyName', cssStyleProperty)
|
|
2234
|
-
'WebElement.getCssValue(' + cssStyleProperty + ')');
|
|
2064
|
+
setParameter('propertyName', cssStyleProperty));
|
|
2235
2065
|
}
|
|
2236
2066
|
|
|
2237
2067
|
/**
|
|
2238
|
-
*
|
|
2239
|
-
*
|
|
2240
|
-
*
|
|
2068
|
+
* Retrieves the current value of the given attribute of this element.
|
|
2069
|
+
* Will return the current value, even if it has been modified after the page
|
|
2070
|
+
* has been loaded. More exactly, this method will return the value
|
|
2241
2071
|
* of the given attribute, unless that attribute is not present, in which case
|
|
2242
2072
|
* the value of the property with the same name is returned. If neither value
|
|
2243
2073
|
* is set, null is returned (for example, the "value" property of a textarea
|
|
@@ -2259,131 +2089,122 @@ class WebElement {
|
|
|
2259
2089
|
* - "readonly"
|
|
2260
2090
|
*
|
|
2261
2091
|
* @param {string} attributeName The name of the attribute to query.
|
|
2262
|
-
* @return {!
|
|
2092
|
+
* @return {!Promise<?string>} A promise that will be
|
|
2263
2093
|
* resolved with the attribute's value. The returned value will always be
|
|
2264
2094
|
* either a string or null.
|
|
2265
2095
|
*/
|
|
2266
2096
|
getAttribute(attributeName) {
|
|
2267
|
-
return this.
|
|
2097
|
+
return this.execute_(
|
|
2268
2098
|
new command.Command(command.Name.GET_ELEMENT_ATTRIBUTE).
|
|
2269
|
-
setParameter('name', attributeName)
|
|
2270
|
-
'WebElement.getAttribute(' + attributeName + ')');
|
|
2099
|
+
setParameter('name', attributeName));
|
|
2271
2100
|
}
|
|
2272
2101
|
|
|
2273
2102
|
/**
|
|
2274
2103
|
* Get the visible (i.e. not hidden by CSS) innerText of this element,
|
|
2275
2104
|
* including sub-elements, without any leading or trailing whitespace.
|
|
2276
2105
|
*
|
|
2277
|
-
* @return {!
|
|
2106
|
+
* @return {!Promise<string>} A promise that will be
|
|
2278
2107
|
* resolved with the element's visible text.
|
|
2279
2108
|
*/
|
|
2280
2109
|
getText() {
|
|
2281
|
-
return this.
|
|
2282
|
-
new command.Command(command.Name.GET_ELEMENT_TEXT),
|
|
2283
|
-
'WebElement.getText()');
|
|
2110
|
+
return this.execute_(new command.Command(command.Name.GET_ELEMENT_TEXT));
|
|
2284
2111
|
}
|
|
2285
2112
|
|
|
2286
2113
|
/**
|
|
2287
|
-
*
|
|
2288
|
-
* pixels.
|
|
2289
|
-
*
|
|
2290
|
-
*
|
|
2291
|
-
*
|
|
2292
|
-
*/
|
|
2293
|
-
getSize() {
|
|
2294
|
-
return this.schedule_(
|
|
2295
|
-
new command.Command(command.Name.GET_ELEMENT_SIZE),
|
|
2296
|
-
'WebElement.getSize()');
|
|
2297
|
-
}
|
|
2298
|
-
|
|
2299
|
-
/**
|
|
2300
|
-
* Schedules a command to compute the location of this element in page space.
|
|
2301
|
-
* @return {!promise.Thenable<{x: number, y: number}>} A promise that
|
|
2302
|
-
* will be resolved to the element's location as a
|
|
2303
|
-
* {@code {x:number, y:number}} object.
|
|
2114
|
+
* Returns an object describing an element's location, in pixels relative to
|
|
2115
|
+
* the document element, and the element's size in pixels.
|
|
2116
|
+
*
|
|
2117
|
+
* @return {!Promise<{width: number, height: number, x: number, y: number}>}
|
|
2118
|
+
* A promise that will resolve with the element's rect.
|
|
2304
2119
|
*/
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2120
|
+
async getRect() {
|
|
2121
|
+
try {
|
|
2122
|
+
return await this.execute_(
|
|
2123
|
+
new command.Command(command.Name.GET_ELEMENT_RECT));
|
|
2124
|
+
} catch (err) {
|
|
2125
|
+
if (err instanceof error.UnknownCommandError) {
|
|
2126
|
+
const {width, height} =
|
|
2127
|
+
await this.execute_(
|
|
2128
|
+
new command.Command(command.Name.GET_ELEMENT_SIZE));
|
|
2129
|
+
const {x, y} =
|
|
2130
|
+
await this.execute_(
|
|
2131
|
+
new command.Command(command.Name.GET_ELEMENT_LOCATION));
|
|
2132
|
+
return {x, y, width, height};
|
|
2133
|
+
}
|
|
2134
|
+
}
|
|
2309
2135
|
}
|
|
2310
2136
|
|
|
2311
2137
|
/**
|
|
2312
|
-
*
|
|
2313
|
-
*
|
|
2314
|
-
*
|
|
2138
|
+
* Tests whether this element is enabled, as dictated by the `disabled`
|
|
2139
|
+
* attribute.
|
|
2140
|
+
*
|
|
2141
|
+
* @return {!Promise<boolean>} A promise that will be
|
|
2315
2142
|
* resolved with whether this element is currently enabled.
|
|
2316
2143
|
*/
|
|
2317
2144
|
isEnabled() {
|
|
2318
|
-
return this.
|
|
2319
|
-
new command.Command(command.Name.IS_ELEMENT_ENABLED),
|
|
2320
|
-
'WebElement.isEnabled()');
|
|
2145
|
+
return this.execute_(new command.Command(command.Name.IS_ELEMENT_ENABLED));
|
|
2321
2146
|
}
|
|
2322
2147
|
|
|
2323
2148
|
/**
|
|
2324
|
-
*
|
|
2325
|
-
*
|
|
2149
|
+
* Tests whether this element is selected.
|
|
2150
|
+
*
|
|
2151
|
+
* @return {!Promise<boolean>} A promise that will be
|
|
2326
2152
|
* resolved with whether this element is currently selected.
|
|
2327
2153
|
*/
|
|
2328
2154
|
isSelected() {
|
|
2329
|
-
return this.
|
|
2330
|
-
new command.Command(command.Name.IS_ELEMENT_SELECTED)
|
|
2331
|
-
'WebElement.isSelected()');
|
|
2155
|
+
return this.execute_(
|
|
2156
|
+
new command.Command(command.Name.IS_ELEMENT_SELECTED));
|
|
2332
2157
|
}
|
|
2333
2158
|
|
|
2334
2159
|
/**
|
|
2335
|
-
*
|
|
2336
|
-
*
|
|
2337
|
-
*
|
|
2338
|
-
*
|
|
2160
|
+
* Submits the form containing this element (or this element if it is itself
|
|
2161
|
+
* a FORM element). his command is a no-op if the element is not contained in
|
|
2162
|
+
* a form.
|
|
2163
|
+
*
|
|
2164
|
+
* @return {!Promise<void>} A promise that will be resolved
|
|
2339
2165
|
* when the form has been submitted.
|
|
2340
2166
|
*/
|
|
2341
2167
|
submit() {
|
|
2342
|
-
return this.
|
|
2343
|
-
new command.Command(command.Name.SUBMIT_ELEMENT),
|
|
2344
|
-
'WebElement.submit()');
|
|
2168
|
+
return this.execute_(new command.Command(command.Name.SUBMIT_ELEMENT));
|
|
2345
2169
|
}
|
|
2346
2170
|
|
|
2347
2171
|
/**
|
|
2348
|
-
*
|
|
2349
|
-
*
|
|
2350
|
-
*
|
|
2351
|
-
*
|
|
2172
|
+
* Clear the `value` of this element. This command has no effect if the
|
|
2173
|
+
* underlying DOM element is neither a text INPUT element nor a TEXTAREA
|
|
2174
|
+
* element.
|
|
2175
|
+
*
|
|
2176
|
+
* @return {!Promise<void>} A promise that will be resolved
|
|
2352
2177
|
* when the element has been cleared.
|
|
2353
2178
|
*/
|
|
2354
2179
|
clear() {
|
|
2355
|
-
return this.
|
|
2356
|
-
new command.Command(command.Name.CLEAR_ELEMENT),
|
|
2357
|
-
'WebElement.clear()');
|
|
2180
|
+
return this.execute_(new command.Command(command.Name.CLEAR_ELEMENT));
|
|
2358
2181
|
}
|
|
2359
2182
|
|
|
2360
2183
|
/**
|
|
2361
|
-
*
|
|
2362
|
-
*
|
|
2184
|
+
* Test whether this element is currently displayed.
|
|
2185
|
+
*
|
|
2186
|
+
* @return {!Promise<boolean>} A promise that will be
|
|
2363
2187
|
* resolved with whether this element is currently visible on the page.
|
|
2364
2188
|
*/
|
|
2365
2189
|
isDisplayed() {
|
|
2366
|
-
return this.
|
|
2367
|
-
new command.Command(command.Name.IS_ELEMENT_DISPLAYED)
|
|
2368
|
-
'WebElement.isDisplayed()');
|
|
2190
|
+
return this.execute_(
|
|
2191
|
+
new command.Command(command.Name.IS_ELEMENT_DISPLAYED));
|
|
2369
2192
|
}
|
|
2370
2193
|
|
|
2371
2194
|
/**
|
|
2372
2195
|
* Take a screenshot of the visible region encompassed by this element's
|
|
2373
2196
|
* bounding rectangle.
|
|
2374
2197
|
*
|
|
2375
|
-
* @param {boolean=}
|
|
2198
|
+
* @param {boolean=} scroll Optional argument that indicates whether the
|
|
2376
2199
|
* element should be scrolled into view before taking a screenshot.
|
|
2377
2200
|
* Defaults to false.
|
|
2378
|
-
* @return {!
|
|
2201
|
+
* @return {!Promise<string>} A promise that will be
|
|
2379
2202
|
* resolved to the screenshot as a base-64 encoded PNG.
|
|
2380
2203
|
*/
|
|
2381
|
-
takeScreenshot(
|
|
2382
|
-
|
|
2383
|
-
return this.schedule_(
|
|
2204
|
+
takeScreenshot(scroll = false) {
|
|
2205
|
+
return this.execute_(
|
|
2384
2206
|
new command.Command(command.Name.TAKE_ELEMENT_SCREENSHOT)
|
|
2385
|
-
.setParameter('scroll', scroll)
|
|
2386
|
-
'WebElement.takeScreenshot(' + scroll + ')');
|
|
2207
|
+
.setParameter('scroll', scroll));
|
|
2387
2208
|
}
|
|
2388
2209
|
}
|
|
2389
2210
|
|
|
@@ -2400,31 +2221,19 @@ class WebElement {
|
|
|
2400
2221
|
* return el.click();
|
|
2401
2222
|
* });
|
|
2402
2223
|
*
|
|
2403
|
-
* @implements {
|
|
2224
|
+
* @implements {IThenable<!WebElement>}
|
|
2404
2225
|
* @final
|
|
2405
2226
|
*/
|
|
2406
2227
|
class WebElementPromise extends WebElement {
|
|
2407
2228
|
/**
|
|
2408
2229
|
* @param {!WebDriver} driver The parent WebDriver instance for this
|
|
2409
2230
|
* element.
|
|
2410
|
-
* @param {!
|
|
2231
|
+
* @param {!Promise<!WebElement>} el A promise
|
|
2411
2232
|
* that will resolve to the promised element.
|
|
2412
2233
|
*/
|
|
2413
2234
|
constructor(driver, el) {
|
|
2414
2235
|
super(driver, 'unused');
|
|
2415
2236
|
|
|
2416
|
-
/**
|
|
2417
|
-
* Cancel operation is only supported if the wrapped thenable is also
|
|
2418
|
-
* cancellable.
|
|
2419
|
-
* @param {(string|Error)=} opt_reason
|
|
2420
|
-
* @override
|
|
2421
|
-
*/
|
|
2422
|
-
this.cancel = function(opt_reason) {
|
|
2423
|
-
if (promise.CancellableThenable.isImplementation(el)) {
|
|
2424
|
-
/** @type {!promise.CancellableThenable} */(el).cancel(opt_reason);
|
|
2425
|
-
}
|
|
2426
|
-
};
|
|
2427
|
-
|
|
2428
2237
|
/** @override */
|
|
2429
2238
|
this.then = el.then.bind(el);
|
|
2430
2239
|
|
|
@@ -2443,7 +2252,6 @@ class WebElementPromise extends WebElement {
|
|
|
2443
2252
|
};
|
|
2444
2253
|
}
|
|
2445
2254
|
}
|
|
2446
|
-
promise.CancellableThenable.addImplementation(WebElementPromise);
|
|
2447
2255
|
|
|
2448
2256
|
|
|
2449
2257
|
//////////////////////////////////////////////////////////////////////////////
|
|
@@ -2469,60 +2277,41 @@ class Alert {
|
|
|
2469
2277
|
/** @private {!WebDriver} */
|
|
2470
2278
|
this.driver_ = driver;
|
|
2471
2279
|
|
|
2472
|
-
/** @private {!
|
|
2473
|
-
this.text_ =
|
|
2280
|
+
/** @private {!Promise<string>} */
|
|
2281
|
+
this.text_ = Promise.resolve(text);
|
|
2474
2282
|
}
|
|
2475
2283
|
|
|
2476
2284
|
/**
|
|
2477
2285
|
* Retrieves the message text displayed with this alert. For instance, if the
|
|
2478
2286
|
* alert were opened with alert("hello"), then this would return "hello".
|
|
2479
2287
|
*
|
|
2480
|
-
* @return {!
|
|
2288
|
+
* @return {!Promise<string>} A promise that will be
|
|
2481
2289
|
* resolved to the text displayed with this alert.
|
|
2482
2290
|
*/
|
|
2483
2291
|
getText() {
|
|
2484
2292
|
return this.text_;
|
|
2485
2293
|
}
|
|
2486
2294
|
|
|
2487
|
-
/**
|
|
2488
|
-
* Sets the username and password in an alert prompting for credentials (such
|
|
2489
|
-
* as a Basic HTTP Auth prompt). This method will implicitly
|
|
2490
|
-
* {@linkplain #accept() submit} the dialog.
|
|
2491
|
-
*
|
|
2492
|
-
* @param {string} username The username to send.
|
|
2493
|
-
* @param {string} password The password to send.
|
|
2494
|
-
* @return {!promise.Thenable<void>} A promise that will be resolved when this
|
|
2495
|
-
* command has completed.
|
|
2496
|
-
*/
|
|
2497
|
-
authenticateAs(username, password) {
|
|
2498
|
-
return this.driver_.schedule(
|
|
2499
|
-
new command.Command(command.Name.SET_ALERT_CREDENTIALS),
|
|
2500
|
-
'WebDriver.switchTo().alert()'
|
|
2501
|
-
+ `.authenticateAs("${username}", "${password}")`);
|
|
2502
|
-
}
|
|
2503
|
-
|
|
2504
2295
|
/**
|
|
2505
2296
|
* Accepts this alert.
|
|
2506
2297
|
*
|
|
2507
|
-
* @return {!
|
|
2298
|
+
* @return {!Promise<void>} A promise that will be resolved
|
|
2508
2299
|
* when this command has completed.
|
|
2509
2300
|
*/
|
|
2510
2301
|
accept() {
|
|
2511
|
-
return this.driver_.
|
|
2512
|
-
new command.Command(command.Name.ACCEPT_ALERT)
|
|
2513
|
-
'WebDriver.switchTo().alert().accept()');
|
|
2302
|
+
return this.driver_.execute(
|
|
2303
|
+
new command.Command(command.Name.ACCEPT_ALERT));
|
|
2514
2304
|
}
|
|
2515
2305
|
|
|
2516
2306
|
/**
|
|
2517
2307
|
* Dismisses this alert.
|
|
2518
2308
|
*
|
|
2519
|
-
* @return {!
|
|
2309
|
+
* @return {!Promise<void>} A promise that will be resolved
|
|
2520
2310
|
* when this command has completed.
|
|
2521
2311
|
*/
|
|
2522
2312
|
dismiss() {
|
|
2523
|
-
return this.driver_.
|
|
2524
|
-
new command.Command(command.Name.DISMISS_ALERT)
|
|
2525
|
-
'WebDriver.switchTo().alert().dismiss()');
|
|
2313
|
+
return this.driver_.execute(
|
|
2314
|
+
new command.Command(command.Name.DISMISS_ALERT));
|
|
2526
2315
|
}
|
|
2527
2316
|
|
|
2528
2317
|
/**
|
|
@@ -2531,14 +2320,13 @@ class Alert {
|
|
|
2531
2320
|
* window.confirm).
|
|
2532
2321
|
*
|
|
2533
2322
|
* @param {string} text The text to set.
|
|
2534
|
-
* @return {!
|
|
2323
|
+
* @return {!Promise<void>} A promise that will be resolved
|
|
2535
2324
|
* when this command has completed.
|
|
2536
2325
|
*/
|
|
2537
2326
|
sendKeys(text) {
|
|
2538
|
-
return this.driver_.
|
|
2327
|
+
return this.driver_.execute(
|
|
2539
2328
|
new command.Command(command.Name.SET_ALERT_TEXT).
|
|
2540
|
-
setParameter('text', text)
|
|
2541
|
-
'WebDriver.switchTo().alert().sendKeys(' + text + ')');
|
|
2329
|
+
setParameter('text', text));
|
|
2542
2330
|
}
|
|
2543
2331
|
}
|
|
2544
2332
|
|
|
@@ -2554,31 +2342,19 @@ class Alert {
|
|
|
2554
2342
|
* return alert.dismiss();
|
|
2555
2343
|
* });
|
|
2556
2344
|
*
|
|
2557
|
-
* @implements {
|
|
2345
|
+
* @implements {IThenable<!Alert>}
|
|
2558
2346
|
* @final
|
|
2559
2347
|
*/
|
|
2560
2348
|
class AlertPromise extends Alert {
|
|
2561
2349
|
/**
|
|
2562
2350
|
* @param {!WebDriver} driver The driver controlling the browser this
|
|
2563
2351
|
* alert is attached to.
|
|
2564
|
-
* @param {!
|
|
2352
|
+
* @param {!Promise<!Alert>} alert A thenable
|
|
2565
2353
|
* that will be fulfilled with the promised alert.
|
|
2566
2354
|
*/
|
|
2567
2355
|
constructor(driver, alert) {
|
|
2568
2356
|
super(driver, 'unused');
|
|
2569
2357
|
|
|
2570
|
-
/**
|
|
2571
|
-
* Cancel operation is only supported if the wrapped thenable is also
|
|
2572
|
-
* cancellable.
|
|
2573
|
-
* @param {(string|Error)=} opt_reason
|
|
2574
|
-
* @override
|
|
2575
|
-
*/
|
|
2576
|
-
this.cancel = function(opt_reason) {
|
|
2577
|
-
if (promise.CancellableThenable.isImplementation(alert)) {
|
|
2578
|
-
/** @type {!promise.CancellableThenable} */(alert).cancel(opt_reason);
|
|
2579
|
-
}
|
|
2580
|
-
};
|
|
2581
|
-
|
|
2582
2358
|
/** @override */
|
|
2583
2359
|
this.then = alert.then.bind(alert);
|
|
2584
2360
|
|
|
@@ -2595,16 +2371,6 @@ class AlertPromise extends Alert {
|
|
|
2595
2371
|
});
|
|
2596
2372
|
};
|
|
2597
2373
|
|
|
2598
|
-
/**
|
|
2599
|
-
* Defers action until the alert has been located.
|
|
2600
|
-
* @override
|
|
2601
|
-
*/
|
|
2602
|
-
this.authenticateAs = function(username, password) {
|
|
2603
|
-
return alert.then(function(alert) {
|
|
2604
|
-
return alert.authenticateAs(username, password);
|
|
2605
|
-
});
|
|
2606
|
-
};
|
|
2607
|
-
|
|
2608
2374
|
/**
|
|
2609
2375
|
* Defers action until the alert has been located.
|
|
2610
2376
|
* @override
|
|
@@ -2636,25 +2402,23 @@ class AlertPromise extends Alert {
|
|
|
2636
2402
|
};
|
|
2637
2403
|
}
|
|
2638
2404
|
}
|
|
2639
|
-
promise.CancellableThenable.addImplementation(AlertPromise);
|
|
2640
2405
|
|
|
2641
2406
|
|
|
2642
2407
|
// PUBLIC API
|
|
2643
2408
|
|
|
2644
2409
|
|
|
2645
2410
|
module.exports = {
|
|
2646
|
-
Alert
|
|
2647
|
-
AlertPromise
|
|
2648
|
-
Condition
|
|
2649
|
-
Logs
|
|
2650
|
-
Navigation
|
|
2651
|
-
Options
|
|
2652
|
-
TargetLocator
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
Window: Window
|
|
2411
|
+
Alert,
|
|
2412
|
+
AlertPromise,
|
|
2413
|
+
Condition,
|
|
2414
|
+
Logs,
|
|
2415
|
+
Navigation,
|
|
2416
|
+
Options,
|
|
2417
|
+
TargetLocator,
|
|
2418
|
+
IWebDriver,
|
|
2419
|
+
WebDriver,
|
|
2420
|
+
WebElement,
|
|
2421
|
+
WebElementCondition,
|
|
2422
|
+
WebElementPromise,
|
|
2423
|
+
Window
|
|
2660
2424
|
};
|