Unreviewed. Update W3C WebDriver imported tests.
authorbburg@apple.com <bburg@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 11 May 2018 23:03:36 +0000 (23:03 +0000)
committerbburg@apple.com <bburg@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 11 May 2018 23:03:36 +0000 (23:03 +0000)
This includes upstream PR #10968, which has a fix for XSSAuditor
blocking scripts loaded via inline.py. Test expectations for
webkitgtkdriver may need to be updated with progressions and new tests.

* imported/w3c/importer.json:
* imported/w3c/tools/webdriver/webdriver/client.py:
* imported/w3c/tools/wptrunner/requirements_chrome.txt:
* imported/w3c/tools/wptrunner/requirements_chrome_android.txt: Copied from WebDriverTests/imported/w3c/tools/wptrunner/requirements_opera.txt.
* imported/w3c/tools/wptrunner/requirements_edge.txt:
* imported/w3c/tools/wptrunner/requirements_firefox.txt:
* imported/w3c/tools/wptrunner/requirements_ie.txt:
* imported/w3c/tools/wptrunner/requirements_opera.txt:
* imported/w3c/tools/wptrunner/requirements_safari.txt:
* imported/w3c/tools/wptrunner/requirements_sauce.txt:
* imported/w3c/tools/wptrunner/wptrunner/browsers/firefox.py:
* imported/w3c/tools/wptrunner/wptrunner/browsers/sauce.py:
* imported/w3c/tools/wptrunner/wptrunner/environment.py:
* imported/w3c/tools/wptrunner/wptrunner/executors/base.py:
* imported/w3c/tools/wptrunner/wptrunner/executors/executormarionette.py:
* imported/w3c/tools/wptrunner/wptrunner/formatters.py:
* imported/w3c/tools/wptrunner/wptrunner/reduce.py:
* imported/w3c/tools/wptrunner/wptrunner/testrunner.py:
* imported/w3c/tools/wptrunner/wptrunner/tests/browsers/test_sauce.py: Added.
* imported/w3c/tools/wptrunner/wptrunner/tests/test_products.py:
* imported/w3c/tools/wptrunner/wptrunner/wptcommandline.py:
* imported/w3c/tools/wptrunner/wptrunner/wptrunner.py:
* imported/w3c/tools/wptrunner/wptrunner/wpttest.py:
* imported/w3c/webdriver/tests/accept_alert/__init__.py: Added.
* imported/w3c/webdriver/tests/accept_alert/accept.py: Added.
* imported/w3c/webdriver/tests/add_cookie/__init__.py: Added.
* imported/w3c/webdriver/tests/add_cookie/add.py: Added.
* imported/w3c/webdriver/tests/close_window/__init__.py: Added.
* imported/w3c/webdriver/tests/close_window/close.py: Added.
* imported/w3c/webdriver/tests/close_window/user_prompts.py: Added.
* imported/w3c/webdriver/tests/delete_cookie/__init__.py: Added.
* imported/w3c/webdriver/tests/delete_cookie/delete.py: Added.
* imported/w3c/webdriver/tests/delete_cookie/user_prompts.py: Added.
* imported/w3c/webdriver/tests/dismiss_alert/__init__.py: Added.
* imported/w3c/webdriver/tests/dismiss_alert/dismiss.py: Added.
* imported/w3c/webdriver/tests/element_clear/__init__.py: Added.
* imported/w3c/webdriver/tests/element_clear/clear.py: Added.
* imported/w3c/webdriver/tests/element_click/bubbling.py:
* imported/w3c/webdriver/tests/element_click/stale.py:
* imported/w3c/webdriver/tests/element_send_keys/content_editable.py: Added.
* imported/w3c/webdriver/tests/element_send_keys/form_controls.py:
* imported/w3c/webdriver/tests/element_send_keys/interactability.py:
* imported/w3c/webdriver/tests/element_send_keys/scroll_into_view.py:
* imported/w3c/webdriver/tests/execute_async_script/collections.py:
* imported/w3c/webdriver/tests/execute_async_script/user_prompts.py:
* imported/w3c/webdriver/tests/execute_script/collections.py:
* imported/w3c/webdriver/tests/execute_script/cyclic.py:
* imported/w3c/webdriver/tests/execute_script/json_serialize_windowproxy.py: Added.
* imported/w3c/webdriver/tests/execute_script/user_prompts.py:
* imported/w3c/webdriver/tests/find_element/__init__.py: Added.
* imported/w3c/webdriver/tests/find_element/find.py: Added.
* imported/w3c/webdriver/tests/find_element_from_element/__init__.py: Added.
* imported/w3c/webdriver/tests/find_element_from_element/find.py: Added.
* imported/w3c/webdriver/tests/find_elements/__init__.py: Added.
* imported/w3c/webdriver/tests/find_elements/find.py: Added.
* imported/w3c/webdriver/tests/find_elements_from_element/__init__.py: Added.
* imported/w3c/webdriver/tests/find_elements_from_element/find.py: Added.
* imported/w3c/webdriver/tests/fullscreen_window/__init__.py: Added.
* imported/w3c/webdriver/tests/fullscreen_window/fullscreen.py: Added.
* imported/w3c/webdriver/tests/fullscreen_window/user_prompts.py: Added.
* imported/w3c/webdriver/tests/get_active_element/__init__.py: Added.
* imported/w3c/webdriver/tests/get_active_element/get.py: Added.
* imported/w3c/webdriver/tests/get_alert_text/__init__.py: Added.
* imported/w3c/webdriver/tests/get_alert_text/get.py: Added.
* imported/w3c/webdriver/tests/get_current_url/__init__.py: Added.
* imported/w3c/webdriver/tests/get_current_url/get.py: Added.
* imported/w3c/webdriver/tests/get_current_url/user_prompts.py: Added.
* imported/w3c/webdriver/tests/get_element_attribute/get.py: Added.
* imported/w3c/webdriver/tests/get_element_property/__init__.py: Added.
* imported/w3c/webdriver/tests/get_element_property/get.py: Added.
* imported/w3c/webdriver/tests/get_element_property/user_prompts.py: Added.
* imported/w3c/webdriver/tests/get_element_tag_name/__init__.py: Added.
* imported/w3c/webdriver/tests/get_element_tag_name/get.py: Added.
* imported/w3c/webdriver/tests/get_element_tag_name/user_prompts.py: Added.
* imported/w3c/webdriver/tests/get_element_text/__init__.py: Added.
* imported/w3c/webdriver/tests/get_element_text/get.py: Added.
* imported/w3c/webdriver/tests/get_named_cookie/__init__.py: Added.
* imported/w3c/webdriver/tests/get_named_cookie/get.py: Added.
* imported/w3c/webdriver/tests/get_timeouts/__init__.py: Added.
* imported/w3c/webdriver/tests/get_timeouts/get.py: Added.
* imported/w3c/webdriver/tests/get_title/__init__.py: Added.
* imported/w3c/webdriver/tests/get_title/get.py: Added.
* imported/w3c/webdriver/tests/get_title/user_prompts.py: Added.
* imported/w3c/webdriver/tests/get_window_rect/__init__.py: Added.
* imported/w3c/webdriver/tests/get_window_rect/get.py: Added.
* imported/w3c/webdriver/tests/get_window_rect/user_prompts.py: Added.
* imported/w3c/webdriver/tests/is_element_selected/__init__.py: Added.
* imported/w3c/webdriver/tests/is_element_selected/selected.py: Added.
* imported/w3c/webdriver/tests/is_element_selected/user_prompts.py: Added.
* imported/w3c/webdriver/tests/maximize_window/__init__.py: Added.
* imported/w3c/webdriver/tests/maximize_window/maximize.py: Added.
* imported/w3c/webdriver/tests/maximize_window/user_prompts.py: Added.
* imported/w3c/webdriver/tests/minimize_window/__init__.py: Added.
* imported/w3c/webdriver/tests/minimize_window/minimize.py: Added.
* imported/w3c/webdriver/tests/minimize_window/user_prompts.py: Added.
* imported/w3c/webdriver/tests/new_session/__init__.py: Added.
* imported/w3c/webdriver/tests/new_session/conftest.py: Added.
* imported/w3c/webdriver/tests/new_session/create_alwaysMatch.py: Added.
* imported/w3c/webdriver/tests/new_session/create_firstMatch.py: Added.
* imported/w3c/webdriver/tests/new_session/default_values.py: Added.
* imported/w3c/webdriver/tests/new_session/invalid_capabilities.py: Added.
* imported/w3c/webdriver/tests/new_session/merge.py: Added.
* imported/w3c/webdriver/tests/new_session/response.py: Added.
* imported/w3c/webdriver/tests/new_session/support/__init__.py: Added.
* imported/w3c/webdriver/tests/new_session/support/create.py: Added.
* imported/w3c/webdriver/tests/page_source/__init__.py: Added.
* imported/w3c/webdriver/tests/page_source/source.py: Added.
* imported/w3c/webdriver/tests/send_alert_text/__init__.py: Added.
* imported/w3c/webdriver/tests/send_alert_text/send.py: Added.
* imported/w3c/webdriver/tests/set_window_rect/__init__.py: Added.
* imported/w3c/webdriver/tests/set_window_rect/resizing_and_positioning.py: Added.
* imported/w3c/webdriver/tests/set_window_rect/set.py: Added.
* imported/w3c/webdriver/tests/set_window_rect/user_prompts.py: Added.
* imported/w3c/webdriver/tests/status/__init__.py: Added.
* imported/w3c/webdriver/tests/status/status.py: Added.
* imported/w3c/webdriver/tests/support/fixtures.py:
* imported/w3c/webdriver/tests/support/inline.py:
* imported/w3c/webdriver/tests/switch_to_parent_frame/__init__.py: Added.
* imported/w3c/webdriver/tests/switch_to_parent_frame/switch.py: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@231727 268f45cc-cd09-0410-ab3c-d52691b4dbfc

120 files changed:
WebDriverTests/ChangeLog
WebDriverTests/imported/w3c/importer.json
WebDriverTests/imported/w3c/tools/webdriver/webdriver/client.py
WebDriverTests/imported/w3c/tools/wptrunner/requirements_chrome.txt
WebDriverTests/imported/w3c/tools/wptrunner/requirements_chrome_android.txt [new file with mode: 0644]
WebDriverTests/imported/w3c/tools/wptrunner/requirements_edge.txt
WebDriverTests/imported/w3c/tools/wptrunner/requirements_firefox.txt
WebDriverTests/imported/w3c/tools/wptrunner/requirements_ie.txt
WebDriverTests/imported/w3c/tools/wptrunner/requirements_opera.txt
WebDriverTests/imported/w3c/tools/wptrunner/requirements_safari.txt
WebDriverTests/imported/w3c/tools/wptrunner/requirements_sauce.txt
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/browsers/firefox.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/browsers/sauce.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/environment.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/executors/base.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/executors/executormarionette.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/formatters.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/reduce.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/testrunner.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/tests/browsers/test_sauce.py [new file with mode: 0644]
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/tests/test_products.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/wptcommandline.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/wptrunner.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/wpttest.py
WebDriverTests/imported/w3c/webdriver/tests/accept_alert/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/accept_alert/accept.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/add_cookie/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/add_cookie/add.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/close_window/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/close_window/close.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/close_window/user_prompts.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/delete_cookie/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/delete_cookie/delete.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/delete_cookie/user_prompts.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/dismiss_alert/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/dismiss_alert/dismiss.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/element_clear/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/element_clear/clear.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/element_click/bubbling.py
WebDriverTests/imported/w3c/webdriver/tests/element_click/stale.py
WebDriverTests/imported/w3c/webdriver/tests/element_send_keys/content_editable.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/element_send_keys/form_controls.py
WebDriverTests/imported/w3c/webdriver/tests/element_send_keys/interactability.py
WebDriverTests/imported/w3c/webdriver/tests/element_send_keys/scroll_into_view.py
WebDriverTests/imported/w3c/webdriver/tests/execute_async_script/collections.py
WebDriverTests/imported/w3c/webdriver/tests/execute_async_script/user_prompts.py
WebDriverTests/imported/w3c/webdriver/tests/execute_script/collections.py
WebDriverTests/imported/w3c/webdriver/tests/execute_script/cyclic.py
WebDriverTests/imported/w3c/webdriver/tests/execute_script/json_serialize_windowproxy.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/execute_script/user_prompts.py
WebDriverTests/imported/w3c/webdriver/tests/find_element/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/find_element/find.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/find_element_from_element/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/find_element_from_element/find.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/find_elements/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/find_elements/find.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/find_elements_from_element/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/find_elements_from_element/find.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/fullscreen_window/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/fullscreen_window/fullscreen.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/fullscreen_window/user_prompts.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_active_element/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_active_element/get.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_alert_text/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_alert_text/get.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_current_url/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_current_url/get.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_current_url/user_prompts.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_element_attribute/get.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_element_property/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_element_property/get.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_element_property/user_prompts.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_element_tag_name/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_element_tag_name/get.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_element_tag_name/user_prompts.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_element_text/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_element_text/get.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_named_cookie/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_named_cookie/get.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_timeouts/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_timeouts/get.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_title/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_title/get.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_title/user_prompts.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_window_rect/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_window_rect/get.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/get_window_rect/user_prompts.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/is_element_selected/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/is_element_selected/selected.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/is_element_selected/user_prompts.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/maximize_window/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/maximize_window/maximize.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/maximize_window/user_prompts.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/minimize_window/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/minimize_window/minimize.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/minimize_window/user_prompts.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/new_session/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/new_session/conftest.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/new_session/create_alwaysMatch.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/new_session/create_firstMatch.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/new_session/default_values.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/new_session/invalid_capabilities.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/new_session/merge.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/new_session/response.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/new_session/support/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/new_session/support/create.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/page_source/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/page_source/source.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/send_alert_text/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/send_alert_text/send.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/set_window_rect/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/set_window_rect/resizing_and_positioning.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/set_window_rect/set.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/set_window_rect/user_prompts.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/status/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/status/status.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/support/fixtures.py
WebDriverTests/imported/w3c/webdriver/tests/support/inline.py
WebDriverTests/imported/w3c/webdriver/tests/switch_to_parent_frame/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/switch_to_parent_frame/switch.py [new file with mode: 0644]

index 72d8897..245de7e 100644 (file)
@@ -1,3 +1,131 @@
+2018-05-11  Brian Burg  <bburg@apple.com>
+
+        Unreviewed. Update W3C WebDriver imported tests.
+
+        This includes upstream PR #10968, which has a fix for XSSAuditor
+        blocking scripts loaded via inline.py. Test expectations for
+        webkitgtkdriver may need to be updated with progressions and new tests.
+
+        * imported/w3c/importer.json:
+        * imported/w3c/tools/webdriver/webdriver/client.py:
+        * imported/w3c/tools/wptrunner/requirements_chrome.txt:
+        * imported/w3c/tools/wptrunner/requirements_chrome_android.txt: Copied from WebDriverTests/imported/w3c/tools/wptrunner/requirements_opera.txt.
+        * imported/w3c/tools/wptrunner/requirements_edge.txt:
+        * imported/w3c/tools/wptrunner/requirements_firefox.txt:
+        * imported/w3c/tools/wptrunner/requirements_ie.txt:
+        * imported/w3c/tools/wptrunner/requirements_opera.txt:
+        * imported/w3c/tools/wptrunner/requirements_safari.txt:
+        * imported/w3c/tools/wptrunner/requirements_sauce.txt:
+        * imported/w3c/tools/wptrunner/wptrunner/browsers/firefox.py:
+        * imported/w3c/tools/wptrunner/wptrunner/browsers/sauce.py:
+        * imported/w3c/tools/wptrunner/wptrunner/environment.py:
+        * imported/w3c/tools/wptrunner/wptrunner/executors/base.py:
+        * imported/w3c/tools/wptrunner/wptrunner/executors/executormarionette.py:
+        * imported/w3c/tools/wptrunner/wptrunner/formatters.py:
+        * imported/w3c/tools/wptrunner/wptrunner/reduce.py:
+        * imported/w3c/tools/wptrunner/wptrunner/testrunner.py:
+        * imported/w3c/tools/wptrunner/wptrunner/tests/browsers/test_sauce.py: Added.
+        * imported/w3c/tools/wptrunner/wptrunner/tests/test_products.py:
+        * imported/w3c/tools/wptrunner/wptrunner/wptcommandline.py:
+        * imported/w3c/tools/wptrunner/wptrunner/wptrunner.py:
+        * imported/w3c/tools/wptrunner/wptrunner/wpttest.py:
+        * imported/w3c/webdriver/tests/accept_alert/__init__.py: Added.
+        * imported/w3c/webdriver/tests/accept_alert/accept.py: Added.
+        * imported/w3c/webdriver/tests/add_cookie/__init__.py: Added.
+        * imported/w3c/webdriver/tests/add_cookie/add.py: Added.
+        * imported/w3c/webdriver/tests/close_window/__init__.py: Added.
+        * imported/w3c/webdriver/tests/close_window/close.py: Added.
+        * imported/w3c/webdriver/tests/close_window/user_prompts.py: Added.
+        * imported/w3c/webdriver/tests/delete_cookie/__init__.py: Added.
+        * imported/w3c/webdriver/tests/delete_cookie/delete.py: Added.
+        * imported/w3c/webdriver/tests/delete_cookie/user_prompts.py: Added.
+        * imported/w3c/webdriver/tests/dismiss_alert/__init__.py: Added.
+        * imported/w3c/webdriver/tests/dismiss_alert/dismiss.py: Added.
+        * imported/w3c/webdriver/tests/element_clear/__init__.py: Added.
+        * imported/w3c/webdriver/tests/element_clear/clear.py: Added.
+        * imported/w3c/webdriver/tests/element_click/bubbling.py:
+        * imported/w3c/webdriver/tests/element_click/stale.py:
+        * imported/w3c/webdriver/tests/element_send_keys/content_editable.py: Added.
+        * imported/w3c/webdriver/tests/element_send_keys/form_controls.py:
+        * imported/w3c/webdriver/tests/element_send_keys/interactability.py:
+        * imported/w3c/webdriver/tests/element_send_keys/scroll_into_view.py:
+        * imported/w3c/webdriver/tests/execute_async_script/collections.py:
+        * imported/w3c/webdriver/tests/execute_async_script/user_prompts.py:
+        * imported/w3c/webdriver/tests/execute_script/collections.py:
+        * imported/w3c/webdriver/tests/execute_script/cyclic.py:
+        * imported/w3c/webdriver/tests/execute_script/json_serialize_windowproxy.py: Added.
+        * imported/w3c/webdriver/tests/execute_script/user_prompts.py:
+        * imported/w3c/webdriver/tests/find_element/__init__.py: Added.
+        * imported/w3c/webdriver/tests/find_element/find.py: Added.
+        * imported/w3c/webdriver/tests/find_element_from_element/__init__.py: Added.
+        * imported/w3c/webdriver/tests/find_element_from_element/find.py: Added.
+        * imported/w3c/webdriver/tests/find_elements/__init__.py: Added.
+        * imported/w3c/webdriver/tests/find_elements/find.py: Added.
+        * imported/w3c/webdriver/tests/find_elements_from_element/__init__.py: Added.
+        * imported/w3c/webdriver/tests/find_elements_from_element/find.py: Added.
+        * imported/w3c/webdriver/tests/fullscreen_window/__init__.py: Added.
+        * imported/w3c/webdriver/tests/fullscreen_window/fullscreen.py: Added.
+        * imported/w3c/webdriver/tests/fullscreen_window/user_prompts.py: Added.
+        * imported/w3c/webdriver/tests/get_active_element/__init__.py: Added.
+        * imported/w3c/webdriver/tests/get_active_element/get.py: Added.
+        * imported/w3c/webdriver/tests/get_alert_text/__init__.py: Added.
+        * imported/w3c/webdriver/tests/get_alert_text/get.py: Added.
+        * imported/w3c/webdriver/tests/get_current_url/__init__.py: Added.
+        * imported/w3c/webdriver/tests/get_current_url/get.py: Added.
+        * imported/w3c/webdriver/tests/get_current_url/user_prompts.py: Added.
+        * imported/w3c/webdriver/tests/get_element_attribute/get.py: Added.
+        * imported/w3c/webdriver/tests/get_element_property/__init__.py: Added.
+        * imported/w3c/webdriver/tests/get_element_property/get.py: Added.
+        * imported/w3c/webdriver/tests/get_element_property/user_prompts.py: Added.
+        * imported/w3c/webdriver/tests/get_element_tag_name/__init__.py: Added.
+        * imported/w3c/webdriver/tests/get_element_tag_name/get.py: Added.
+        * imported/w3c/webdriver/tests/get_element_tag_name/user_prompts.py: Added.
+        * imported/w3c/webdriver/tests/get_element_text/__init__.py: Added.
+        * imported/w3c/webdriver/tests/get_element_text/get.py: Added.
+        * imported/w3c/webdriver/tests/get_named_cookie/__init__.py: Added.
+        * imported/w3c/webdriver/tests/get_named_cookie/get.py: Added.
+        * imported/w3c/webdriver/tests/get_timeouts/__init__.py: Added.
+        * imported/w3c/webdriver/tests/get_timeouts/get.py: Added.
+        * imported/w3c/webdriver/tests/get_title/__init__.py: Added.
+        * imported/w3c/webdriver/tests/get_title/get.py: Added.
+        * imported/w3c/webdriver/tests/get_title/user_prompts.py: Added.
+        * imported/w3c/webdriver/tests/get_window_rect/__init__.py: Added.
+        * imported/w3c/webdriver/tests/get_window_rect/get.py: Added.
+        * imported/w3c/webdriver/tests/get_window_rect/user_prompts.py: Added.
+        * imported/w3c/webdriver/tests/is_element_selected/__init__.py: Added.
+        * imported/w3c/webdriver/tests/is_element_selected/selected.py: Added.
+        * imported/w3c/webdriver/tests/is_element_selected/user_prompts.py: Added.
+        * imported/w3c/webdriver/tests/maximize_window/__init__.py: Added.
+        * imported/w3c/webdriver/tests/maximize_window/maximize.py: Added.
+        * imported/w3c/webdriver/tests/maximize_window/user_prompts.py: Added.
+        * imported/w3c/webdriver/tests/minimize_window/__init__.py: Added.
+        * imported/w3c/webdriver/tests/minimize_window/minimize.py: Added.
+        * imported/w3c/webdriver/tests/minimize_window/user_prompts.py: Added.
+        * imported/w3c/webdriver/tests/new_session/__init__.py: Added.
+        * imported/w3c/webdriver/tests/new_session/conftest.py: Added.
+        * imported/w3c/webdriver/tests/new_session/create_alwaysMatch.py: Added.
+        * imported/w3c/webdriver/tests/new_session/create_firstMatch.py: Added.
+        * imported/w3c/webdriver/tests/new_session/default_values.py: Added.
+        * imported/w3c/webdriver/tests/new_session/invalid_capabilities.py: Added.
+        * imported/w3c/webdriver/tests/new_session/merge.py: Added.
+        * imported/w3c/webdriver/tests/new_session/response.py: Added.
+        * imported/w3c/webdriver/tests/new_session/support/__init__.py: Added.
+        * imported/w3c/webdriver/tests/new_session/support/create.py: Added.
+        * imported/w3c/webdriver/tests/page_source/__init__.py: Added.
+        * imported/w3c/webdriver/tests/page_source/source.py: Added.
+        * imported/w3c/webdriver/tests/send_alert_text/__init__.py: Added.
+        * imported/w3c/webdriver/tests/send_alert_text/send.py: Added.
+        * imported/w3c/webdriver/tests/set_window_rect/__init__.py: Added.
+        * imported/w3c/webdriver/tests/set_window_rect/resizing_and_positioning.py: Added.
+        * imported/w3c/webdriver/tests/set_window_rect/set.py: Added.
+        * imported/w3c/webdriver/tests/set_window_rect/user_prompts.py: Added.
+        * imported/w3c/webdriver/tests/status/__init__.py: Added.
+        * imported/w3c/webdriver/tests/status/status.py: Added.
+        * imported/w3c/webdriver/tests/support/fixtures.py:
+        * imported/w3c/webdriver/tests/support/inline.py:
+        * imported/w3c/webdriver/tests/switch_to_parent_frame/__init__.py: Added.
+        * imported/w3c/webdriver/tests/switch_to_parent_frame/switch.py: Added.
+
 2018-05-09  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         WebDriver: implement advance user interactions
index 572547c..e9b4d04 100644 (file)
@@ -1,6 +1,6 @@
 {
     "repository": "https://github.com/w3c/web-platform-tests.git",
-    "revision": "564cfb3a6bd13e949d5c49ad6e5f2cb3752173f3",
+    "revision": "389b958c00a4d6b897bfce284c0c88bf451fb6b8",
     "paths_to_import": [
         "tools/webdriver",
         "tools/wptrunner",
index 8da14a0..a8abda0 100644 (file)
@@ -536,7 +536,12 @@ class Session(object):
 
     @command
     def close(self):
-        return self.send_session_command("DELETE", "window")
+        handles = self.send_session_command("DELETE", "window")
+        if len(handles) == 0:
+            # With no more open top-level browsing contexts, the session is closed.
+            self.session_id = None
+
+        return handles
 
     @property
     @command
@@ -557,17 +562,23 @@ class Session(object):
         return self.send_session_command("GET", url, {})
 
     @command
-    def set_cookie(self, name, value, path=None, domain=None, secure=None, expiry=None):
-        body = {"name": name,
-                "value": value}
-        if path is not None:
-            body["path"] = path
+    def set_cookie(self, name, value, path=None, domain=None,
+            secure=None, expiry=None, http_only=None):
+        body = {
+            "name": name,
+            "value": value,
+        }
+
         if domain is not None:
             body["domain"] = domain
-        if secure is not None:
-            body["secure"] = secure
         if expiry is not None:
             body["expiry"] = expiry
+        if http_only is not None:
+            body["httpOnly"] = http_only
+        if path is not None:
+            body["path"] = path
+        if secure is not None:
+            body["secure"] = secure
         self.send_session_command("POST", "cookie", {"cookie": body})
 
     def delete_cookie(self, name=None):
diff --git a/WebDriverTests/imported/w3c/tools/wptrunner/requirements_chrome_android.txt b/WebDriverTests/imported/w3c/tools/wptrunner/requirements_chrome_android.txt
new file mode 100644 (file)
index 0000000..f10d718
--- /dev/null
@@ -0,0 +1,2 @@
+mozprocess == 0.26
+selenium==3.12.0
index 79fde78..0eb26e7 100644 (file)
@@ -1,8 +1,8 @@
 marionette_driver==2.6.0
-mozprofile==1.0.0
+mozprofile==1.1.0
 mozprocess == 0.26
 mozcrash == 1.0
-mozrunner==6.15
+mozrunner == 7.0.0
 mozleak == 0.1
 mozinstall == 1.15
 mozdownload == 1.23
index 0a0ca7e..68017ab 100644 (file)
@@ -1,3 +1,4 @@
+import json
 import os
 import platform
 import signal
@@ -102,7 +103,7 @@ def executor_kwargs(test_type, server_config, cache_manager, run_info_data,
         if kwargs["binary_args"]:
             options["args"] = kwargs["binary_args"]
         options["prefs"] = {
-            "network.dns.localDomains": ",".join(server_config.domains.itervalues())
+            "network.dns.localDomains": ",".join(server_config.domains_set)
         }
         capabilities["moz:firefoxOptions"] = options
     if kwargs["certutil_binary"] is None:
@@ -198,7 +199,7 @@ class FirefoxBrowser(Browser):
         self.profile = FirefoxProfile(preferences=preferences)
         self.profile.set_preferences({"marionette.port": self.marionette_port,
                                       "dom.disable_open_during_load": False,
-                                      "network.dns.localDomains": ",".join(self.config.domains.itervalues()),
+                                      "network.dns.localDomains": ",".join(self.config.domains_set),
                                       "network.proxy.type": 0,
                                       "places.history.enabled": False,
                                       "dom.send_after_paint_to_content": True,
@@ -245,11 +246,23 @@ class FirefoxBrowser(Browser):
     def load_prefs(self):
         prefs = Preferences()
 
-        prefs_path = os.path.join(self.prefs_root, "prefs_general.js")
-        if os.path.exists(prefs_path):
-            prefs.add(Preferences.read_prefs(prefs_path))
-        else:
-            self.logger.warning("Failed to find base prefs file in %s" % prefs_path)
+        pref_paths = []
+        prefs_general = os.path.join(self.prefs_root, 'prefs_general.js')
+        if os.path.isfile(prefs_general):
+            # Old preference file used in Firefox 60 and earlier (remove when no longer supported)
+            pref_paths.append(prefs_general)
+
+        profiles = os.path.join(self.prefs_root, 'profiles.json')
+        if os.path.isfile(profiles):
+            with open(profiles, 'r') as fh:
+                for name in json.load(fh)['web-platform-tests']:
+                    pref_paths.append(os.path.join(self.prefs_root, name, 'user.js'))
+
+        for path in pref_paths:
+            if os.path.exists(path):
+                prefs.add(Preferences.read_prefs(path))
+            else:
+                self.logger.warning("Failed to find base prefs file in %s" % path)
 
         # Add any custom preferences
         prefs.add(self.extra_prefs, cast=True)
index 9ae2f7e..709af41 100644 (file)
@@ -166,7 +166,7 @@ class SauceConnect():
             "--metrics-address=0.0.0.0:9876",
             "--readyfile=./sauce_is_ready",
             "--tunnel-domains",
-            ",".join(self.env_config['domains'].values())
+            ",".join(self.env_config.domains_set)
         ])
 
         # Timeout config vars
index c5e31b7..309174c 100644 (file)
@@ -10,12 +10,12 @@ from mozlog import get_default_logger, handlers, proxy
 
 from wptlogging import LogLevelRewriter
 from wptserve.handlers import StringHandler
+from wptserve import sslutils
 
 here = os.path.split(__file__)[0]
 repo_root = os.path.abspath(os.path.join(here, os.pardir, os.pardir, os.pardir))
 
 serve = None
-sslutils = None
 
 
 def do_delayed_imports(logger, test_paths):
@@ -31,11 +31,6 @@ def do_delayed_imports(logger, test_paths):
     except ImportError:
         failed.append("serve")
 
-    try:
-        import sslutils
-    except ImportError:
-        failed.append("sslutils")
-
     if failed:
         logger.critical(
             "Failed to import %s. Ensure that tests path %s contains web-platform-tests" %
@@ -134,18 +129,15 @@ class TestEnvironment(object):
         signal.signal(signal.SIGINT, signal.SIG_DFL)
 
     def load_config(self):
-        default_config_path = os.path.join(serve_path(self.test_paths), "config.default.json")
         override_path = os.path.join(serve_path(self.test_paths), "config.json")
 
-        with open(default_config_path) as f:
-            default_config = json.load(f)
-
-        config = serve.Config(override_ssl_env=self.ssl_env, **default_config)
+        config = serve.Config(override_ssl_env=self.ssl_env)
 
         config.ports = {
             "http": [8000, 8001],
             "https": [8443],
-            "ws": [8888]
+            "ws": [8888],
+            "wss": [8889],
         }
 
         if os.path.exists(override_path):
@@ -221,7 +213,7 @@ class TestEnvironment(object):
 
     def ensure_started(self):
         # Pause for a while to ensure that the server has a chance to start
-        for _ in xrange(20):
+        for _ in xrange(60):
             failed = self.test_servers()
             if not failed:
                 return
index 0942bc6..08030b3 100644 (file)
@@ -104,6 +104,7 @@ class TestExecutor(object):
     test_type = None
     convert_result = None
     supports_testdriver = False
+    supports_jsshell = False
 
     def __init__(self, browser, server_config, timeout_multiplier=1,
                  debug_info=None, **kwargs):
@@ -153,10 +154,10 @@ class TestExecutor(object):
         :param test: The test to run"""
         if test.environment != self.last_environment:
             self.on_environment_change(test.environment)
-
         try:
             result = self.do_test(test)
         except Exception as e:
+            self.logger.warning(traceback.format_exc(e))
             result = self.result_from_exception(test, e)
 
         if result is Stop:
@@ -547,6 +548,7 @@ class CallbackHandler(object):
     def _send_message(self, message_type, status, message=None):
         self.protocol.testdriver.send_message(message_type, status, message=message)
 
+
 class ClickAction(object):
     def __init__(self, logger, protocol):
         self.logger = logger
@@ -562,6 +564,7 @@ class ClickAction(object):
         self.logger.debug("Clicking element: %s" % selector)
         self.protocol.click.element(elements[0])
 
+
 class SendKeysAction(object):
     def __init__(self, logger, protocol):
         self.logger = logger
index d06ee3c..bff509c 100644 (file)
@@ -60,7 +60,7 @@ class MarionetteBaseProtocolPart(BaseProtocolPart):
 
     def execute_script(self, script, async=False):
         method = self.marionette.execute_async_script if async else self.marionette.execute_script
-        return method(script, new_sandbox=False)
+        return method(script, new_sandbox=False, sandbox=None)
 
     def set_timeout(self, timeout):
         """Set the Marionette script timeout.
@@ -119,7 +119,7 @@ class MarionetteTestharnessProtocolPart(TestharnessProtocolPart):
 
     def load_runner(self, url_protocol):
         # Check if we previously had a test window open, and if we did make sure it's closed
-        self.marionette.execute_script("if (window.win) {window.win.close()}")
+        self.parent.base.execute_script("if (window.win) {window.win.close()}")
         url = urlparse.urljoin(self.parent.executor.server_url(url_protocol),
                                "/testharness_runner.html")
         self.logger.debug("Loading %s" % url)
@@ -133,7 +133,7 @@ class MarionetteTestharnessProtocolPart(TestharnessProtocolPart):
                 "that your firewall rules or network setup does not "
                 "prevent access.\e%s" % (url, traceback.format_exc(e)))
             raise
-        self.marionette.execute_script(
+        self.parent.base.execute_script(
             "document.title = '%s'" % threading.current_thread().name.replace("'", '"'))
 
     def close_old_windows(self, url_protocol):
@@ -183,7 +183,7 @@ class MarionetteTestharnessProtocolPart(TestharnessProtocolPart):
         if window_id:
             try:
                 # Try this, it's in Level 1 but nothing supports it yet
-                win_s = self.marionette.execute_script("return window['%s'];" % self.window_id)
+                win_s = self.parent.base.execute_script("return window['%s'];" % self.window_id)
                 win_obj = json.loads(win_s)
                 test_window = win_obj["window-fcc6-11e5-b4f8-330a88ab9d7f"]
             except Exception:
@@ -326,7 +326,7 @@ class MarionetteTestDriverProtocolPart(TestDriverProtocolPart):
         }
         if message:
             obj["message"] = str(message)
-        self.marionette.execute_script("window.postMessage(%s, '*')" % json.dumps(obj))
+        self.parent.base.execute_script("window.postMessage(%s, '*')" % json.dumps(obj))
 
 
 class MarionetteProtocol(Protocol):
@@ -475,7 +475,8 @@ class ExecuteAsyncScriptRun(object):
             if message:
                 message += "\n"
             message += traceback.format_exc(e)
-            self.result = False, ("INTERNAL-ERROR", e)
+            self.logger.warning(message)
+            self.result = False, ("INTERNAL-ERROR", None)
 
         finally:
             self.result_flag.set()
@@ -493,8 +494,8 @@ class MarionetteTestharnessExecutor(TestharnessExecutor):
                                      debug_info=debug_info)
 
         self.protocol = MarionetteProtocol(self, browser, capabilities, timeout_multiplier)
-        self.script = open(os.path.join(here, "testharness_marionette.js")).read()
-        self.script_resume = open(os.path.join(here, "testharness_marionette_resume.js")).read()
+        self.script = open(os.path.join(here, "testharness_webdriver.js")).read()
+        self.script_resume = open(os.path.join(here, "testharness_webdriver_resume.js")).read()
         self.close_after_done = close_after_done
         self.window_id = str(uuid.uuid4())
 
@@ -551,6 +552,9 @@ class MarionetteTestharnessExecutor(TestharnessExecutor):
         while True:
             result = protocol.base.execute_script(
                 self.script_resume % format_map, async=True)
+            if result is None:
+                # This can happen if we get an content process crash
+                return None
             done, rv = handler(result)
             if done:
                 break
@@ -639,12 +643,12 @@ class MarionetteRefTestExecutor(RefTestExecutor):
                                      test_url,
                                      timeout).run()
 
-    def _screenshot(self, marionette, url, timeout):
-        marionette.navigate(url)
+    def _screenshot(self, protocol, url, timeout):
+        protocol.marionette.navigate(url)
 
-        marionette.execute_async_script(self.wait_script)
+        protocol.base.execute_script(self.wait_script, async=True)
 
-        screenshot = marionette.screenshot(full=False)
+        screenshot = protocol.marionette.screenshot(full=False)
         # strip off the data:img/png, part of the url
         if screenshot.startswith("data:image/png;base64,"):
             screenshot = screenshot.split(",", 1)[1]
index 0e888ce..24d0653 100644 (file)
@@ -8,15 +8,20 @@ class WptreportFormatter(BaseFormatter):
 
     def __init__(self):
         self.raw_results = {}
+        self.results = {}
+
+    def suite_start(self, data):
+        self.results['run_info'] = data['run_info']
+        self.results['time_start'] = data['time']
 
     def suite_end(self, data):
-        results = {}
-        results["results"] = []
+        self.results['time_end'] = data['time']
+        self.results["results"] = []
         for test_name in self.raw_results:
             result = {"test": test_name}
             result.update(self.raw_results[test_name])
-            results["results"].append(result)
-        return json.dumps(results)
+            self.results["results"].append(result)
+        return json.dumps(self.results)
 
     def find_or_create_test(self, data):
         test_name = data["test"]
index d245ee3..f5c60bf 100644 (file)
@@ -47,6 +47,7 @@ class Reducer(object):
         self.test_type = kwargs["test_types"][0]
         run_info = wpttest.get_run_info(kwargs["metadata_root"],
                                         kwargs["product"],
+                                        browser_version=kwargs.get("browser_version"),
                                         debug=False)
         test_filter = wptrunner.TestFilter(include=kwargs["include"])
         self.test_loader = wptrunner.TestLoader(kwargs["tests_root"],
index e83bff8..257e789 100644 (file)
@@ -594,7 +594,8 @@ class TestRunnerManager(threading.Thread):
                                ((subtest_unexpected or is_unexpected) and
                                 self.restart_on_unexpected))
 
-        if (self.pause_after_test or
+        if (not file_result.status == "CRASH" and
+            self.pause_after_test or
             (self.pause_on_unexpected and (subtest_unexpected or is_unexpected))):
             self.logger.info("Pausing until the browser exits")
             self.send_message("wait")
diff --git a/WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/tests/browsers/test_sauce.py b/WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/tests/browsers/test_sauce.py
new file mode 100644 (file)
index 0000000..db0de8f
--- /dev/null
@@ -0,0 +1,132 @@
+import sys
+from os.path import join, dirname
+
+import mock
+import pytest
+
+sys.path.insert(0, join(dirname(__file__), "..", "..", ".."))
+
+sauce = pytest.importorskip("wptrunner.browsers.sauce")
+
+from wptserve.config import Config
+
+
+def test_sauceconnect_success():
+    with mock.patch.object(sauce.SauceConnect, "upload_prerun_exec"),\
+            mock.patch.object(sauce.subprocess, "Popen") as Popen,\
+            mock.patch.object(sauce.os.path, "exists") as exists:
+        # Act as if it's still running
+        Popen.return_value.poll.return_value = None
+        Popen.return_value.returncode = None
+        # Act as if file created
+        exists.return_value = True
+
+        sauce_connect = sauce.SauceConnect(
+            sauce_user="aaa",
+            sauce_key="bbb",
+            sauce_tunnel_id="ccc",
+            sauce_connect_binary="ddd")
+
+        env_config = Config(browser_host="example.net")
+        sauce_connect(None, env_config)
+        with sauce_connect:
+            pass
+
+
+@pytest.mark.parametrize("readyfile,returncode", [
+    (True, 0),
+    (True, 1),
+    (True, 2),
+    (False, 0),
+    (False, 1),
+    (False, 2),
+])
+def test_sauceconnect_failure_exit(readyfile, returncode):
+    with mock.patch.object(sauce.SauceConnect, "upload_prerun_exec"),\
+            mock.patch.object(sauce.subprocess, "Popen") as Popen,\
+            mock.patch.object(sauce.os.path, "exists") as exists,\
+            mock.patch.object(sauce.time, "sleep") as sleep:
+        Popen.return_value.poll.return_value = returncode
+        Popen.return_value.returncode = returncode
+        exists.return_value = readyfile
+
+        sauce_connect = sauce.SauceConnect(
+            sauce_user="aaa",
+            sauce_key="bbb",
+            sauce_tunnel_id="ccc",
+            sauce_connect_binary="ddd")
+
+        env_config = Config(browser_host="example.net")
+        sauce_connect(None, env_config)
+        with pytest.raises(sauce.SauceException):
+            with sauce_connect:
+                pass
+
+        # Given we appear to exit immediately with these mocks, sleep shouldn't be called
+        sleep.assert_not_called()
+
+
+def test_sauceconnect_failure_never_ready():
+    with mock.patch.object(sauce.SauceConnect, "upload_prerun_exec"),\
+            mock.patch.object(sauce.subprocess, "Popen") as Popen,\
+            mock.patch.object(sauce.os.path, "exists") as exists,\
+            mock.patch.object(sauce.time, "sleep") as sleep:
+        Popen.return_value.poll.return_value = None
+        Popen.return_value.returncode = None
+        exists.return_value = False
+
+        sauce_connect = sauce.SauceConnect(
+            sauce_user="aaa",
+            sauce_key="bbb",
+            sauce_tunnel_id="ccc",
+            sauce_connect_binary="ddd")
+
+        env_config = Config(browser_host="example.net")
+        sauce_connect(None, env_config)
+        with pytest.raises(sauce.SauceException):
+            with sauce_connect:
+                pass
+
+        # We should sleep while waiting for it to create the readyfile
+        sleep.assert_called()
+
+        # Check we actually kill it after termination fails
+        Popen.return_value.terminate.assert_called()
+        Popen.return_value.kill.assert_called()
+
+
+def test_sauceconnect_tunnel_domains():
+    with mock.patch.object(sauce.SauceConnect, "upload_prerun_exec"),\
+            mock.patch.object(sauce.subprocess, "Popen") as Popen,\
+            mock.patch.object(sauce.os.path, "exists") as exists:
+        Popen.return_value.poll.return_value = None
+        Popen.return_value.returncode = None
+        exists.return_value = True
+
+        sauce_connect = sauce.SauceConnect(
+            sauce_user="aaa",
+            sauce_key="bbb",
+            sauce_tunnel_id="ccc",
+            sauce_connect_binary="ddd")
+
+        env_config = Config(browser_host="example.net",
+                            alternate_hosts={"alt": "example.org"},
+                            subdomains={"a", "b"},
+                            not_subdomains={"x", "y"})
+        sauce_connect(None, env_config)
+        with sauce_connect:
+            Popen.assert_called_once()
+            args, kwargs = Popen.call_args
+            cmd = args[0]
+            assert "--tunnel-domains" in cmd
+            i = cmd.index("--tunnel-domains")
+            rest = cmd[i+1:]
+            assert len(rest) >= 1
+            if len(rest) > 1:
+                assert rest[1].startswith("-"), "--tunnel-domains takes a comma separated list (not a space separated list)"
+            assert set(rest[0].split(",")) == {'example.net',
+                                               'a.example.net',
+                                               'b.example.net',
+                                               'example.org',
+                                               'a.example.org',
+                                               'b.example.org'}
index c7109c5..8ece29b 100644 (file)
@@ -9,10 +9,8 @@ import pytest
 from .base import all_products, active_products
 
 sys.path.insert(0, join(dirname(__file__), "..", "..", "..", ".."))  # repo root
-
 from tools import localpaths
-
-import sslutils
+from wptserve import sslutils
 
 from wptrunner import environment
 from wptrunner import products
index 8361ca1..c4a0193 100644 (file)
@@ -66,6 +66,10 @@ scheme host and port.""")
 
     parser.add_argument("--no-capture-stdio", action="store_true", default=False,
                         help="Don't capture stdio and write to logging")
+    parser.add_argument("--no-fail-on-unexpected", action="store_false",
+                        default=True,
+                        dest="fail_on_unexpected",
+                        help="Exit with status code 0 when test expectations are violated")
 
     mode_group = parser.add_argument_group("Mode")
     mode_group.add_argument("--list-test-groups", action="store_true",
index 40863d8..bd2b3ad 100644 (file)
@@ -43,7 +43,9 @@ def get_loader(test_paths, product, ssl_env, debug=None, run_info_extras=None, *
     if run_info_extras is None:
         run_info_extras = {}
 
-    run_info = wpttest.get_run_info(kwargs["run_info"], product, debug=debug,
+    run_info = wpttest.get_run_info(kwargs["run_info"], product,
+                                    browser_version=kwargs.get("browser_version"),
+                                    debug=debug,
                                     extras=run_info_extras)
 
     test_manifests = testloader.ManifestLoader(test_paths, force_manifest_update=kwargs["manifest_update"],
@@ -153,7 +155,9 @@ def run_tests(config, test_paths, product, **kwargs):
             ))
 
         if "test_loader" in kwargs:
-            run_info = wpttest.get_run_info(kwargs["run_info"], product, debug=None,
+            run_info = wpttest.get_run_info(kwargs["run_info"], product,
+                                            browser_version=kwargs.get("browser_version"),
+                                            debug=None,
                                             extras=run_info_extras(**kwargs))
             test_loader = kwargs["test_loader"]
         else:
@@ -245,6 +249,12 @@ def run_tests(config, test_paths, product, **kwargs):
                             if test.testdriver and not executor_cls.supports_testdriver:
                                 logger.test_start(test.id)
                                 logger.test_end(test.id, status="SKIP")
+                            elif test.jsshell and not executor_cls.supports_jsshell:
+                                # We expect that tests for JavaScript shells
+                                # will not be run along with tests that run in
+                                # a full web browser, so we silently skip them
+                                # here.
+                                pass
                             else:
                                 run_tests["testharness"].append(test)
                     else:
@@ -283,6 +293,10 @@ def run_tests(config, test_paths, product, **kwargs):
         logger.error("No tests ran")
         return False
 
+    if unexpected_total and not kwargs["fail_on_unexpected"]:
+        logger.info("Tolerating %s unexpected results" % unexpected_total)
+        return True
+
     return unexpected_total == 0
 
 
index 0fb1bdd..cdff0b7 100644 (file)
@@ -65,7 +65,7 @@ def get_run_info(metadata_root, product, **kwargs):
 
 
 class RunInfo(dict):
-    def __init__(self, metadata_root, product, debug, extras=None):
+    def __init__(self, metadata_root, product, debug, browser_version=None, extras=None):
         import mozinfo
 
         self._update_mozinfo(metadata_root)
@@ -82,6 +82,8 @@ class RunInfo(dict):
             self["stylo"] = True
         if "STYLO_FORCE_DISABLED" in os.environ:
             self["stylo"] = False
+        if browser_version:
+            self["browser_version"] = browser_version
         if extras is not None:
             self.update(extras)
 
@@ -244,17 +246,20 @@ class TestharnessTest(Test):
     test_type = "testharness"
 
     def __init__(self, tests_root, url, inherit_metadata, test_metadata,
-                 timeout=None, path=None, protocol="http", testdriver=False):
+                 timeout=None, path=None, protocol="http", testdriver=False,
+                 jsshell=False):
         Test.__init__(self, tests_root, url, inherit_metadata, test_metadata, timeout,
                       path, protocol)
 
         self.testdriver = testdriver
+        self.jsshell = jsshell
 
     @classmethod
     def from_manifest(cls, manifest_item, inherit_metadata, test_metadata):
         timeout = cls.long_timeout if manifest_item.timeout == "long" else cls.default_timeout
         protocol = "https" if hasattr(manifest_item, "https") and manifest_item.https else "http"
         testdriver = manifest_item.testdriver if hasattr(manifest_item, "testdriver") else False
+        jsshell = manifest_item.jsshell if hasattr(manifest_item, "jsshell") else False
         return cls(manifest_item.source_file.tests_root,
                    manifest_item.url,
                    inherit_metadata,
@@ -262,7 +267,8 @@ class TestharnessTest(Test):
                    timeout=timeout,
                    path=manifest_item.source_file.path,
                    protocol=protocol,
-                   testdriver=testdriver)
+                   testdriver=testdriver,
+                   jsshell=jsshell)
 
     @property
     def id(self):
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/accept_alert/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/accept_alert/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/accept_alert/accept.py b/WebDriverTests/imported/w3c/webdriver/tests/accept_alert/accept.py
new file mode 100644 (file)
index 0000000..efcbf3f
--- /dev/null
@@ -0,0 +1,47 @@
+from tests.support.asserts import assert_error, assert_success
+from tests.support.inline import inline
+
+
+def accept_alert(session):
+    return session.transport.send(
+        "POST", "session/{session_id}/alert/accept".format(**vars(session)))
+
+
+# 18.2 Accept Alert
+
+def test_no_browsing_context(session, create_window):
+    # 18.2 step 1
+    session.window_handle = create_window()
+    session.close()
+
+    response = accept_alert(session)
+    assert_error(response, "no such window")
+
+
+def test_no_user_prompt(session):
+    # 18.2 step 2
+    response = accept_alert(session)
+    assert_error(response, "no such alert")
+
+
+def test_accept_alert(session):
+    # 18.2 step 3
+    session.url = inline("<script>window.alert('Hello');</script>")
+    response = accept_alert(session)
+    assert_success(response)
+
+
+def test_accept_confirm(session):
+    # 18.2 step 3
+    session.url = inline("<script>window.result = window.confirm('Hello');</script>")
+    response = accept_alert(session)
+    assert_success(response)
+    assert session.execute_script("return window.result") is True
+
+
+def test_accept_prompt(session):
+    # 18.2 step 3
+    session.url = inline("<script>window.result = window.prompt('Enter Your Name: ', 'Federer');</script>")
+    response = accept_alert(session)
+    assert_success(response)
+    assert session.execute_script("return window.result") == "Federer"
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/add_cookie/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/add_cookie/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/add_cookie/add.py b/WebDriverTests/imported/w3c/webdriver/tests/add_cookie/add.py
new file mode 100644 (file)
index 0000000..f865a08
--- /dev/null
@@ -0,0 +1,149 @@
+from datetime import datetime, timedelta
+
+from tests.support.asserts import assert_success
+from tests.support.fixtures import clear_all_cookies
+
+
+def add_cookie(session, cookie):
+    return session.transport.send(
+        "POST", "session/{session_id}/cookie".format(**vars(session)),
+        {"cookie": cookie})
+
+
+def test_add_domain_cookie(session, url, server_config):
+    new_cookie = {
+        "name": "hello",
+        "value": "world",
+        "domain": server_config["browser_host"],
+        "path": "/",
+        "httpOnly": False,
+        "secure": False
+    }
+
+    session.url = url("/common/blank.html")
+    clear_all_cookies(session)
+
+    result = add_cookie(session, new_cookie)
+    assert_success(result)
+
+    cookie = session.cookies("hello")
+    assert "domain" in cookie
+    assert isinstance(cookie["domain"], basestring)
+    assert "name" in cookie
+    assert isinstance(cookie["name"], basestring)
+    assert "value" in cookie
+    assert isinstance(cookie["value"], basestring)
+
+    assert cookie["name"] == "hello"
+    assert cookie["value"] == "world"
+    assert cookie["domain"] == server_config["browser_host"] or \
+        cookie["domain"] == ".%s" % server_config["browser_host"]
+
+
+def test_add_cookie_for_ip(session, url, server_config, configuration):
+    new_cookie = {
+        "name": "hello",
+        "value": "world",
+        "domain": "127.0.0.1",
+        "path": "/",
+        "httpOnly": False,
+        "secure": False
+    }
+
+    session.url = "http://127.0.0.1:%s/common/blank.html" % (server_config["ports"]["http"][0])
+    clear_all_cookies(session)
+
+    result = add_cookie(session, new_cookie)
+    assert_success(result)
+
+    cookie = session.cookies("hello")
+    assert "name" in cookie
+    assert isinstance(cookie["name"], basestring)
+    assert "value" in cookie
+    assert isinstance(cookie["value"], basestring)
+    assert "domain" in cookie
+    assert isinstance(cookie["domain"], basestring)
+
+    assert cookie["name"] == "hello"
+    assert cookie["value"] == "world"
+    assert cookie["domain"] == "127.0.0.1"
+
+
+def test_add_non_session_cookie(session, url):
+    a_year_from_now = int(
+        (datetime.utcnow() + timedelta(days=365) - datetime.utcfromtimestamp(0)).total_seconds())
+
+    new_cookie = {
+        "name": "hello",
+        "value": "world",
+        "expiry": a_year_from_now
+    }
+
+    session.url = url("/common/blank.html")
+    clear_all_cookies(session)
+
+    result = add_cookie(session, new_cookie)
+    assert_success(result)
+
+    cookie = session.cookies("hello")
+    assert "name" in cookie
+    assert isinstance(cookie["name"], basestring)
+    assert "value" in cookie
+    assert isinstance(cookie["value"], basestring)
+    assert "expiry" in cookie
+    assert isinstance(cookie["expiry"], int)
+
+    assert cookie["name"] == "hello"
+    assert cookie["value"] == "world"
+    assert cookie["expiry"] == a_year_from_now
+
+
+def test_add_session_cookie(session, url):
+    new_cookie = {
+        "name": "hello",
+        "value": "world"
+    }
+
+    session.url = url("/common/blank.html")
+    clear_all_cookies(session)
+
+    result = add_cookie(session, new_cookie)
+    assert_success(result)
+
+    cookie = session.cookies("hello")
+    assert "name" in cookie
+    assert isinstance(cookie["name"], basestring)
+    assert "value" in cookie
+    assert isinstance(cookie["value"], basestring)
+    if "expiry" in cookie:
+        assert cookie.get("expiry") is None
+
+    assert cookie["name"] == "hello"
+    assert cookie["value"] == "world"
+
+
+def test_add_session_cookie_with_leading_dot_character_in_domain(session, url, server_config):
+    new_cookie = {
+        "name": "hello",
+        "value": "world",
+        "domain": ".%s" % server_config["browser_host"]
+    }
+
+    session.url = url("/common/blank.html")
+    clear_all_cookies(session)
+
+    result = add_cookie(session, new_cookie)
+    assert_success(result)
+
+    cookie = session.cookies("hello")
+    assert "name" in cookie
+    assert isinstance(cookie["name"], basestring)
+    assert "value" in cookie
+    assert isinstance(cookie["value"], basestring)
+    assert "domain" in cookie
+    assert isinstance(cookie["domain"], basestring)
+
+    assert cookie["name"] == "hello"
+    assert cookie["value"] == "world"
+    assert cookie["domain"] == server_config["browser_host"] or \
+        cookie["domain"] == ".%s" % server_config["browser_host"]
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/close_window/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/close_window/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/close_window/close.py b/WebDriverTests/imported/w3c/webdriver/tests/close_window/close.py
new file mode 100644 (file)
index 0000000..ba41b34
--- /dev/null
@@ -0,0 +1,39 @@
+from tests.support.asserts import assert_error, assert_success
+
+
+def close(session):
+    return session.transport.send(
+        "DELETE", "session/{session_id}/window".format(**vars(session)))
+
+
+def test_no_browsing_context(session, create_window):
+    new_handle = create_window()
+
+    session.window_handle = new_handle
+    session.close()
+    assert new_handle not in session.handles
+
+    response = close(session)
+    assert_error(response, "no such window")
+
+
+def test_close_browsing_context(session, create_window):
+    handles = session.handles
+
+    new_handle = create_window()
+    session.window_handle = new_handle
+
+    response = close(session)
+    value = assert_success(response, handles)
+    assert session.handles == handles
+    assert new_handle not in value
+
+
+def test_close_last_browsing_context(session):
+    assert len(session.handles) == 1
+    response = close(session)
+
+    assert_success(response, [])
+
+    # With no more open top-level browsing contexts, the session is closed.
+    session.session_id = None
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/close_window/user_prompts.py b/WebDriverTests/imported/w3c/webdriver/tests/close_window/user_prompts.py
new file mode 100644 (file)
index 0000000..0ab480c
--- /dev/null
@@ -0,0 +1,69 @@
+# META: timeout=long
+
+from tests.support.asserts import assert_error, assert_dialog_handled
+from tests.support.fixtures import create_dialog, create_window
+from tests.support.inline import inline
+
+
+def close(session):
+    return session.transport.send(
+        "DELETE", "session/{session_id}/window".format(**vars(session)))
+
+
+def test_handle_prompt_dismiss_and_notify():
+    """TODO"""
+
+
+def test_handle_prompt_accept_and_notify():
+    """TODO"""
+
+
+def test_handle_prompt_ignore():
+    """TODO"""
+
+
+def test_handle_prompt_accept(new_session, add_browser_capabilites):
+    _, session = new_session({"capabilities": {
+        "alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "accept"})}})
+    session.window_handle = create_window(session)()
+
+    session.url = inline("<title>WD doc title</title>")
+
+    create_dialog(session)("alert", text="dismiss #1", result_var="dismiss1")
+    response = close(session)
+    assert response.status == 200
+    assert_dialog_handled(session, "dismiss #1")
+
+    create_dialog(session)("confirm", text="dismiss #2", result_var="dismiss2")
+    response = close(session)
+    assert response.status == 200
+    assert_dialog_handled(session, "dismiss #2")
+
+    create_dialog(session)("prompt", text="dismiss #3", result_var="dismiss3")
+    response = close(session)
+    assert response.status == 200
+    assert_dialog_handled(session, "dismiss #3")
+
+
+def test_handle_prompt_missing_value(session, create_dialog, create_window):
+    session.window_handle = create_window()
+
+    session.url = inline("<title>WD doc title</title>")
+    create_dialog("alert", text="dismiss #1", result_var="dismiss1")
+
+    response = close(session)
+
+    assert_error(response, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #1")
+
+    create_dialog("confirm", text="dismiss #2", result_var="dismiss2")
+
+    response = close(session)
+    assert_error(response, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #2")
+
+    create_dialog("prompt", text="dismiss #3", result_var="dismiss3")
+
+    response = close(session)
+    assert_error(response, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #3")
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/delete_cookie/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/delete_cookie/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/delete_cookie/delete.py b/WebDriverTests/imported/w3c/webdriver/tests/delete_cookie/delete.py
new file mode 100644 (file)
index 0000000..ee53dc3
--- /dev/null
@@ -0,0 +1,21 @@
+from tests.support.asserts import assert_error, assert_success
+
+
+def delete_cookie(session, name):
+    return session.transport.send(
+        "DELETE", "/session/{session_id}/cookie/{name}".format(
+            session_id=session.session_id,
+            name=name))
+
+
+def test_no_browsing_context(session, create_window):
+    session.window_handle = create_window()
+    session.close()
+
+    response = delete_cookie(session, "foo")
+    assert_error(response, "no such window")
+
+
+def test_unknown_cookie(session):
+    response = delete_cookie(session, "stilton")
+    assert_success(response)
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/delete_cookie/user_prompts.py b/WebDriverTests/imported/w3c/webdriver/tests/delete_cookie/user_prompts.py
new file mode 100644 (file)
index 0000000..46bc375
--- /dev/null
@@ -0,0 +1,101 @@
+from tests.support.asserts import assert_error, assert_dialog_handled
+from tests.support.fixtures import create_dialog
+from tests.support.inline import inline
+
+
+def delete_cookie(session, name):
+    return session.transport.send("DELETE", "/session/%s/cookie/%s" % (session.session_id, name))
+
+
+def test_handle_prompt_dismiss_and_notify():
+    """TODO"""
+
+
+def test_handle_prompt_accept_and_notify():
+    """TODO"""
+
+
+def test_handle_prompt_ignore():
+    """TODO"""
+
+
+def test_handle_prompt_accept(new_session, add_browser_capabilites):
+    """
+    2. Handle any user prompts and return its value if it is an error.
+
+    [...]
+
+    In order to handle any user prompts a remote end must take the
+    following steps:
+
+      [...]
+
+      2. Perform the following substeps based on the current session's
+      user prompt handler:
+
+        [...]
+
+        - accept state
+           Accept the current user prompt.
+
+    """
+    _, session = new_session({"capabilities": {
+        "alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "accept"})}})
+    session.url = inline("<title>WD doc title</title>")
+
+    create_dialog(session)("alert", text="dismiss #1", result_var="dismiss1")
+    response = delete_cookie(session, "foo")
+    assert response.status == 200
+    assert_dialog_handled(session, "dismiss #1")
+
+    create_dialog(session)("confirm", text="dismiss #2", result_var="dismiss2")
+    response = delete_cookie(session, "foo")
+    assert response.status == 200
+    assert_dialog_handled(session, "dismiss #2")
+
+    create_dialog(session)("prompt", text="dismiss #3", result_var="dismiss3")
+    response = delete_cookie(session, "foo")
+    assert response.status == 200
+    assert_dialog_handled(session, "dismiss #3")
+
+
+def test_handle_prompt_missing_value(session, create_dialog):
+    """
+    2. Handle any user prompts and return its value if it is an error.
+
+    [...]
+
+    In order to handle any user prompts a remote end must take the
+    following steps:
+
+      [...]
+
+      2. Perform the following substeps based on the current session's
+      user prompt handler:
+
+        [...]
+
+        - missing value default state
+           1. Dismiss the current user prompt.
+           2. Return error with error code unexpected alert open.
+
+    """
+    session.url = inline("<title>WD doc title</title>")
+    create_dialog("alert", text="dismiss #1", result_var="dismiss1")
+
+    response = delete_cookie(session, "foo")
+
+    assert_error(response, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #1")
+
+    create_dialog("confirm", text="dismiss #2", result_var="dismiss2")
+
+    response = delete_cookie(session, "foo")
+    assert_error(response, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #2")
+
+    create_dialog("prompt", text="dismiss #3", result_var="dismiss3")
+
+    response = delete_cookie(session, "foo")
+    assert_error(response, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #3")
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/dismiss_alert/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/dismiss_alert/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/dismiss_alert/dismiss.py b/WebDriverTests/imported/w3c/webdriver/tests/dismiss_alert/dismiss.py
new file mode 100644 (file)
index 0000000..6c06c43
--- /dev/null
@@ -0,0 +1,47 @@
+from tests.support.asserts import assert_error, assert_success
+from tests.support.inline import inline
+
+
+def dismiss_alert(session):
+    return session.transport.send(
+        "POST", "session/{session_id}/alert/dismiss".format(**vars(session)))
+
+
+# 18.1 Dismiss Alert
+
+def test_no_browsing_context(session, create_window):
+    # 18.1 step 1
+    session.window_handle = create_window()
+    session.close()
+
+    response = dismiss_alert(session)
+    assert_error(response, "no such window")
+
+
+def test_no_user_prompt(session):
+    # 18.1 step 2
+    response = dismiss_alert(session)
+    assert_error(response, "no such alert")
+
+
+def test_dismiss_alert(session):
+    # 18.1 step 3
+    session.url = inline("<script>window.alert('Hello');</script>")
+    response = dismiss_alert(session)
+    assert_success(response)
+
+
+def test_dismiss_confirm(session):
+    # 18.1 step 3
+    session.url = inline("<script>window.result = window.confirm('Hello');</script>")
+    response = dismiss_alert(session)
+    assert_success(response)
+    assert session.execute_script("return window.result;") is False
+
+
+def test_dismiss_prompt(session):
+    # 18.1 step 3
+    session.url = inline("<script>window.result = window.prompt('Enter Your Name: ', 'Federer');</script>")
+    response = dismiss_alert(session)
+    assert_success(response)
+    assert session.execute_script("return window.result") is None
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/element_clear/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/element_clear/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/element_clear/clear.py b/WebDriverTests/imported/w3c/webdriver/tests/element_clear/clear.py
new file mode 100644 (file)
index 0000000..ddf37ee
--- /dev/null
@@ -0,0 +1,400 @@
+# META: timeout=long
+
+import pytest
+
+from tests.support.asserts import (
+    assert_element_has_focus,
+    assert_error,
+    assert_success,
+)
+from tests.support.inline import inline
+
+
+def element_clear(session, element):
+    return session.transport.send(
+        "POST", "/session/{session_id}/element/{element_id}/clear".format(
+            session_id=session.session_id,
+            element_id=element.id))
+
+
+def add_event_listeners(element):
+    element.session.execute_script("""
+        var target = arguments[0];
+        window.events = [];
+        var expectedEvents = ["focus", "blur", "change"];
+        for (var i = 0; i < expectedEvents.length; i++) {
+          target.addEventListener(expectedEvents[i], function (eventObject) {
+            window.events.push(eventObject.type)
+          });
+        }
+        """, args=(element,))
+
+
+def get_events(session):
+    return session.execute_script("return window.events")
+
+
+@pytest.fixture(scope="session")
+def text_file(tmpdir_factory):
+    fh = tmpdir_factory.mktemp("tmp").join("hello.txt")
+    fh.write("hello")
+    return fh
+
+
+def test_closed_context(session, create_window):
+    new_window = create_window()
+    session.window_handle = new_window
+    session.url = inline("<input>")
+    element = session.find.css("input", all=False)
+    session.close()
+
+    response = element_clear(session, element)
+    assert_error(response, "no such window")
+
+
+def test_connected_element(session):
+    session.url = inline("<input>")
+    element = session.find.css("input", all=False)
+
+    session.url = inline("<input>")
+    response = element_clear(session, element)
+    assert_error(response, "stale element reference")
+
+
+def test_pointer_interactable(session):
+    session.url = inline("<input style='margin-left: -1000px' value=foobar>")
+    element = session.find.css("input", all=False)
+
+    response = element_clear(session, element)
+    assert_error(response, "element not interactable")
+
+
+def test_keyboard_interactable(session):
+    session.url = inline("""
+        <input value=foobar>
+        <div></div>
+
+        <style>
+        div {
+          position: absolute;
+          background: blue;
+          top: 0;
+        }
+        </style>
+        """)
+    element = session.find.css("input", all=False)
+    assert element.property("value") == "foobar"
+
+    response = element_clear(session, element)
+    assert_success(response)
+    assert element.property("value") == ""
+
+
+@pytest.mark.parametrize("type,value,default",
+                         [("number", "42", ""),
+                          ("range", "42", "50"),
+                          ("email", "foo@example.com", ""),
+                          ("password", "password", ""),
+                          ("search", "search", ""),
+                          ("tel", "999", ""),
+                          ("text", "text", ""),
+                          ("url", "https://example.com/", ""),
+                          ("color", "#ff0000", "#000000"),
+                          ("date", "2017-12-26", ""),
+                          ("datetime", "2017-12-26T19:48", ""),
+                          ("datetime-local", "2017-12-26T19:48", ""),
+                          ("time", "19:48", ""),
+                          ("month", "2017-11", ""),
+                          ("week", "2017-W52", "")])
+def test_input(session, type, value, default):
+    session.url = inline("<input type=%s value='%s'>" % (type, value))
+    element = session.find.css("input", all=False)
+    add_event_listeners(element)
+    assert element.property("value") == value
+
+    response = element_clear(session, element)
+    assert_success(response)
+    assert element.property("value") == default
+    events = get_events(session)
+    assert "focus" in events
+    assert "change" in events
+    assert "blur" in events
+    assert_element_has_focus(session.execute_script("return document.body"))
+
+
+@pytest.mark.parametrize("type",
+                         ["number",
+                          "range",
+                          "email",
+                          "password",
+                          "search",
+                          "tel",
+                          "text",
+                          "url",
+                          "color",
+                          "date",
+                          "datetime",
+                          "datetime-local",
+                          "time",
+                          "month",
+                          "week",
+                          "file"])
+def test_input_disabled(session, type):
+    session.url = inline("<input type=%s disabled>" % type)
+    element = session.find.css("input", all=False)
+
+    response = element_clear(session, element)
+    assert_error(response, "invalid element state")
+
+
+@pytest.mark.parametrize("type",
+                         ["number",
+                          "range",
+                          "email",
+                          "password",
+                          "search",
+                          "tel",
+                          "text",
+                          "url",
+                          "color",
+                          "date",
+                          "datetime",
+                          "datetime-local",
+                          "time",
+                          "month",
+                          "week",
+                          "file"])
+def test_input_readonly(session, type):
+    session.url = inline("<input type=%s readonly>" % type)
+    element = session.find.css("input", all=False)
+
+    response = element_clear(session, element)
+    assert_error(response, "invalid element state")
+
+
+def test_textarea(session):
+    session.url = inline("<textarea>foobar</textarea>")
+    element = session.find.css("textarea", all=False)
+    add_event_listeners(element)
+    assert element.property("value") == "foobar"
+
+    response = element_clear(session, element)
+    assert_success(response)
+    assert element.property("value") == ""
+    events = get_events(session)
+    assert "focus" in events
+    assert "change" in events
+    assert "blur" in events
+
+
+def test_textarea_disabled(session):
+    session.url = inline("<textarea disabled></textarea>")
+    element = session.find.css("textarea", all=False)
+
+    response = element_clear(session, element)
+    assert_error(response, "invalid element state")
+
+
+def test_textarea_readonly(session):
+    session.url = inline("<textarea readonly></textarea>")
+    element = session.find.css("textarea", all=False)
+
+    response = element_clear(session, element)
+    assert_error(response, "invalid element state")
+
+
+def test_input_file(session, text_file):
+    session.url = inline("<input type=file>")
+    element = session.find.css("input", all=False)
+    element.send_keys(str(text_file))
+
+    response = element_clear(session, element)
+    assert_success(response)
+    assert element.property("value") == ""
+
+
+def test_input_file_multiple(session, text_file):
+    session.url = inline("<input type=file multiple>")
+    element = session.find.css("input", all=False)
+    element.send_keys(str(text_file))
+    element.send_keys(str(text_file))
+
+    response = element_clear(session, element)
+    assert_success(response)
+    assert element.property("value") == ""
+
+
+def test_select(session):
+    session.url = inline("""
+        <select>
+          <option>foo
+        </select>
+        """)
+    select = session.find.css("select", all=False)
+    option = session.find.css("option", all=False)
+
+    response = element_clear(session, select)
+    assert_error(response, "invalid element state")
+    response = element_clear(session, option)
+    assert_error(response, "invalid element state")
+
+
+def test_button(session):
+    session.url = inline("<button></button>")
+    button = session.find.css("button", all=False)
+
+    response = element_clear(session, button)
+    assert_error(response, "invalid element state")
+
+
+def test_button_with_subtree(session):
+    """
+    Whilst an <input> is normally editable, the focusable area
+    where it is placed will default to the <button>.  I.e. if you
+    try to click <input> to focus it, you will hit the <button>.
+    """
+    session.url = inline("""
+        <button>
+          <input value=foobar>
+        </button>
+        """)
+    text_field = session.find.css("input", all=False)
+
+    response = element_clear(session, text_field)
+    assert_error(response, "element not interactable")
+
+
+def test_contenteditable(session):
+    session.url = inline("<p contenteditable>foobar</p>")
+    element = session.find.css("p", all=False)
+    add_event_listeners(element)
+    assert element.property("innerHTML") == "foobar"
+
+    response = element_clear(session, element)
+    assert_success(response)
+    assert element.property("innerHTML") == ""
+    assert get_events(session) == ["focus", "change", "blur"]
+    assert_element_has_focus(session.execute_script("return document.body"))
+
+
+def test_designmode(session):
+    session.url = inline("foobar")
+    element = session.find.css("body", all=False)
+    assert element.property("innerHTML") == "foobar"
+    session.execute_script("document.designMode = 'on'")
+
+    response = element_clear(session, element)
+    assert_success(response)
+    assert element.property("innerHTML") == "<br>"
+    assert_element_has_focus(session.execute_script("return document.body"))
+
+
+def test_resettable_element_focus_when_empty(session):
+    session.url = inline("<input>")
+    element = session.find.css("input", all=False)
+    add_event_listeners(element)
+    assert element.property("value") == ""
+
+    response = element_clear(session, element)
+    assert_success(response)
+    assert element.property("value") == ""
+    assert get_events(session) == []
+
+
+@pytest.mark.parametrize("type,invalid_value",
+                         [("number", "foo"),
+                          ("range", "foo"),
+                          ("email", "foo"),
+                          ("url", "foo"),
+                          ("color", "foo"),
+                          ("date", "foo"),
+                          ("datetime", "foo"),
+                          ("datetime-local", "foo"),
+                          ("time", "foo"),
+                          ("month", "foo"),
+                          ("week", "foo")])
+def test_resettable_element_does_not_satisfy_validation_constraints(session, type, invalid_value):
+    """
+    Some UAs allow invalid input to certain types of constrained
+    form controls.  For example, Gecko allows non-valid characters
+    to be typed into <input type=number> but Chrome does not.
+    Since we want to test that Element Clear works for clearing the
+    invalid characters in these UAs, it is fine to skip this test
+    where UAs do not allow the element to not satisfy its constraints.
+    """
+    session.url = inline("<input type=%s>" % type)
+    element = session.find.css("input", all=False)
+
+    def is_valid(element):
+        return session.execute_script("""
+            var input = arguments[0];
+            return input.validity.valid;
+            """, args=(element,))
+
+    # value property does not get updated if the input is invalid
+    element.send_keys(invalid_value)
+
+    # UA does not allow invalid input for this form control type
+    if is_valid(element):
+        return
+
+    response = element_clear(session, element)
+    assert_success(response)
+    assert is_valid(element)
+
+
+@pytest.mark.parametrize("type",
+                         ["checkbox",
+                          "radio",
+                          "hidden",
+                          "submit",
+                          "button",
+                          "image"])
+def test_non_editable_inputs(session, type):
+    session.url = inline("<input type=%s>" % type)
+    element = session.find.css("input", all=False)
+
+    response = element_clear(session, element)
+    assert_error(response, "invalid element state")
+
+
+def test_scroll_into_view(session):
+    session.url = inline("""
+        <input value=foobar>
+        <div style='height: 200vh; width: 5000vh'>
+        """)
+    element = session.find.css("input", all=False)
+    assert element.property("value") == "foobar"
+    assert session.execute_script("return window.pageYOffset") == 0
+
+    # scroll to the bottom right of the page
+    session.execute_script("""
+        var body = document.body;
+        window.scrollTo(body.scrollWidth, body.scrollHeight);
+        """)
+
+    # clear and scroll back to the top of the page
+    response = element_clear(session, element)
+    assert_success(response)
+    assert element.property("value") == ""
+
+    # check if element cleared is scrolled into view
+    rect = session.execute_script("""
+        var input = arguments[0];
+        var rect = input.getBoundingClientRect();
+        return {"top": rect.top,
+                "left": rect.left,
+                "height": rect.height,
+                "width": rect.width};
+        """, args=(element,))
+    window = session.execute_script("""
+        return {"innerHeight": window.innerHeight,
+                "innerWidth": window.innerWidth,
+                "pageXOffset": window.pageXOffset,
+                "pageYOffset": window.pageYOffset};
+        """)
+
+    assert rect["top"] < (window["innerHeight"] + window["pageYOffset"]) and \
+           rect["left"] < (window["innerWidth"] + window["pageXOffset"]) and \
+           (rect["top"] + element.rect["height"]) > window["pageYOffset"] and \
+           (rect["left"] + element.rect["width"]) > window["pageXOffset"]
index 7bf405c..2b08be1 100644 (file)
@@ -1,7 +1,8 @@
 from tests.support.asserts import assert_success
 from tests.support.inline import inline
 
-def click(session, element):
+
+def element_click(session, element):
     return session.transport.send(
         "POST", "/session/{session_id}/element/{element_id}/click".format(
             session_id=session.session_id,
@@ -135,7 +136,8 @@ def test_element_disappears_during_click(session):
 
         function logEvent({type, target, currentTarget}) {
           log.innerHTML += "<p></p>";
-          log.lastElementChild.textContent = `${type} in ${target.id} (handled by ${currentTarget.id})`;
+          log.lastElementChild.textContent =
+              `${type} in ${target.id} (handled by ${currentTarget.id})`;
         }
 
         for (let ev of ["click", "mousedown", "mouseup"]) {
@@ -144,11 +146,13 @@ def test_element_disappears_during_click(session):
           body.addEventListener(ev, logEvent);
         }
 
-        over.addEventListener("mousedown", () => over.style.display = "none");
+        over.addEventListener("mousedown", function(mousedownEvent) {
+          over.style.display = "none";
+        });
         </script>
         """)
     over = session.find.css("#over", all=False)
 
     # should not time out
-    response = click(session, over)
+    response = element_click(session, over)
     assert_success(response)
index d39e3a3..cd24dd7 100644 (file)
@@ -1,16 +1,12 @@
-import pytest
-import webdriver
-
 from tests.support.asserts import assert_error
 from tests.support.inline import inline
 
 
-def click_element(session, element):
+def element_click(session, element):
     return session.transport.send(
-        "POST", "/session/{session_id}/element/{element_id}/click".format(**{
-            "session_id": session.session_id,
-            "element_id": element.id,
-        }))
+        "POST", "/session/{session_id}/element/{element_id}/click".format(
+            session_id=session.session_id,
+            element_id=element.id))
 
 
 def test_is_stale(session):
@@ -18,5 +14,5 @@ def test_is_stale(session):
     button = session.find.css("button", all=False)
     session.url = inline("<button>bar</button>")
 
-    response = click_element(session, button)
+    response = element_click(session, button)
     assert_error(response, "stale element reference")
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/element_send_keys/content_editable.py b/WebDriverTests/imported/w3c/webdriver/tests/element_send_keys/content_editable.py
new file mode 100644 (file)
index 0000000..16ebc2d
--- /dev/null
@@ -0,0 +1,23 @@
+import pytest
+
+from tests.support.inline import inline
+
+
+def test_sets_insertion_point_to_end(session):
+    session.url = inline('<div contenteditable=true>Hello,</div>')
+    input = session.find.css("div", all=False)
+    input.send_keys(' world!')
+    text = session.execute_script('return arguments[0].innerText', args=[input])
+    assert "Hello, world!" == text.strip()
+
+
+# 12. Let current text length be the element's length.
+#
+# 13. Set the text insertion caret using set selection range using current
+#     text length for both the start and end parameters.
+def test_sets_insertion_point_to_after_last_text_node(session):
+    session.url = inline('<div contenteditable=true>Hel<span>lo</span>,</div>')
+    input = session.find.css("div", all=False)
+    input.send_keys(" world!")
+    text = session.execute_script("return arguments[0].innerText", args=[input])
+    assert "Hello, world!" == text.strip()
index 28df05f..a3ff688 100644 (file)
@@ -9,10 +9,9 @@ from tests.support.asserts import (
 from tests.support.inline import inline
 
 
-def element_send_keys(session, element, text):
+def send_keys_to_element(session, element, text):
     return session.transport.send(
-        "POST",
-        "/session/{session_id}/element/{element_id}/value".format(
+        "POST", "/session/{session_id}/element/{element_id}/value".format(
             session_id=session.session_id,
             element_id=element.id),
         {"text": text})
@@ -37,7 +36,7 @@ def test_input(session):
     element = session.find.css("input", all=False)
     assert element.property("value") == ""
 
-    element_send_keys(session, element, "foo")
+    send_keys_to_element(session, element, "foo")
     assert element.property("value") == "foo"
     assert_element_has_focus(element)
 
@@ -47,7 +46,7 @@ def test_textarea(session):
     element = session.find.css("textarea", all=False)
     assert element.property("value") == ""
 
-    element_send_keys(session, element, "foo")
+    send_keys_to_element(session, element, "foo")
     assert element.property("value") == "foo"
     assert_element_has_focus(element)
 
@@ -57,10 +56,10 @@ def test_input_append(session):
     element = session.find.css("input", all=False)
     assert element.property("value") == "a"
 
-    element_send_keys(session, element, "b")
+    send_keys_to_element(session, element, "b")
     assert element.property("value") == "ab"
 
-    element_send_keys(session, element, "c")
+    send_keys_to_element(session, element, "c")
     assert element.property("value") == "abc"
 
 
@@ -69,10 +68,10 @@ def test_textarea_append(session):
     element = session.find.css("textarea", all=False)
     assert element.property("value") == "a"
 
-    element_send_keys(session, element, "b")
+    send_keys_to_element(session, element, "b")
     assert element.property("value") == "ab"
 
-    element_send_keys(session, element, "c")
+    send_keys_to_element(session, element, "c")
     assert element.property("value") == "abc"
 
 
@@ -82,7 +81,7 @@ def test_events(session, tag):
     element = session.find.css(tag, all=False)
     add_event_listeners(element)
 
-    element_send_keys(session, element, "foo")
+    send_keys_to_element(session, element, "foo")
     assert element.property("value") == "foo"
     assert get_events(session) == ["focus",
                                    "keydown",
@@ -104,5 +103,5 @@ def test_not_blurred(session, tag):
     session.url = inline("<%s>" % tag)
     element = session.find.css(tag, all=False)
 
-    element_send_keys(session, element, "")
+    send_keys_to_element(session, element, "")
     assert_element_has_focus(element)
index f0746e4..3a809aa 100644 (file)
@@ -2,10 +2,9 @@ from tests.support.asserts import assert_error, assert_success
 from tests.support.inline import iframe, inline
 
 
-def send_keys_to_element(session, element, text):
+def element_send_keys(session, element, text):
     return session.transport.send(
-        "POST",
-        "/session/{session_id}/element/{element_id}/value".format(
+        "POST", "/session/{session_id}/element/{element_id}/value".format(
             session_id=session.session_id,
             element_id=element.id),
         {"text": text})
@@ -24,7 +23,7 @@ def test_body_is_interactable(session):
     # By default body is the active element
     assert session.active_element is element
 
-    response = send_keys_to_element(session, element, "foo")
+    response = element_send_keys(session, element, "foo")
     assert_success(response)
     assert session.active_element is element
     assert result.property("value") == "foo"
@@ -44,7 +43,7 @@ def test_document_element_is_interactable(session):
     # By default body is the active element
     assert session.active_element is body
 
-    response = send_keys_to_element(session, element, "foo")
+    response = element_send_keys(session, element, "foo")
     assert_success(response)
     assert session.active_element is element
     assert result.property("value") == "foo"
@@ -63,7 +62,7 @@ def test_iframe_is_interactable(session):
     # By default the body has the focus
     assert session.active_element is body
 
-    response = send_keys_to_element(session, frame, "foo")
+    response = element_send_keys(session, frame, "foo")
     assert_success(response)
     assert session.active_element is frame
 
@@ -78,7 +77,7 @@ def test_transparent_element(session):
     session.url = inline("""<input style="opacity: 0">""")
     element = session.find.css("input", all=False)
 
-    response = send_keys_to_element(session, element, "foo")
+    response = element_send_keys(session, element, "foo")
     assert_success(response)
     assert element.property("value") == "foo"
 
@@ -87,7 +86,7 @@ def test_readonly_element(session):
     session.url = inline("<input readonly>")
     element = session.find.css("input", all=False)
 
-    response = send_keys_to_element(session, element, "foo")
+    response = element_send_keys(session, element, "foo")
     assert_success(response)
     assert element.property("value") == ""
 
@@ -99,7 +98,7 @@ def test_obscured_element(session):
     """)
     element = session.find.css("input", all=False)
 
-    response = send_keys_to_element(session, element, "foo")
+    response = element_send_keys(session, element, "foo")
     assert_success(response)
     assert element.property("value") == "foo"
 
@@ -108,7 +107,7 @@ def test_not_a_focusable_element(session):
     session.url = inline("<div>foo</div>")
     element = session.find.css("div", all=False)
 
-    response = send_keys_to_element(session, element, "foo")
+    response = element_send_keys(session, element, "foo")
     assert_error(response, "element not interactable")
 
 
@@ -116,7 +115,7 @@ def test_not_displayed_element(session):
     session.url = inline("""<input style="display: none">""")
     element = session.find.css("input", all=False)
 
-    response = send_keys_to_element(session, element, "foo")
+    response = element_send_keys(session, element, "foo")
     assert_error(response, "element not interactable")
 
 
@@ -124,7 +123,7 @@ def test_hidden_element(session):
     session.url = inline("""<input style="visibility: hidden">""")
     element = session.find.css("input", all=False)
 
-    response = send_keys_to_element(session, element, "foo")
+    response = element_send_keys(session, element, "foo")
     assert_error(response, "element not interactable")
 
 
@@ -132,5 +131,5 @@ def test_disabled_element(session):
     session.url = inline("""<input disabled>""")
     element = session.find.css("input", all=False)
 
-    response = send_keys_to_element(session, element, "foo")
+    response = element_send_keys(session, element, "foo")
     assert_error(response, "element not interactable")
index a1d454d..9ff0a9e 100644 (file)
@@ -3,10 +3,9 @@ from tests.support.fixtures import is_element_in_viewport
 from tests.support.inline import inline
 
 
-def send_keys_to_element(session, element, text):
+def element_send_keys(session, element, text):
     return session.transport.send(
-        "POST",
-        "/session/{session_id}/element/{element_id}/value".format(
+        "POST", "/session/{session_id}/element/{element_id}/value".format(
             session_id=session.session_id,
             element_id=element.id),
         {"text": text})
@@ -16,7 +15,7 @@ def test_element_outside_of_not_scrollable_viewport(session):
     session.url = inline("<input style=\"position: relative; left: -9999px;\">")
     element = session.find.css("input", all=False)
 
-    response = send_keys_to_element(session, element, "foo")
+    response = element_send_keys(session, element, "foo")
     assert_success(response)
 
     assert not is_element_in_viewport(session, element)
@@ -26,7 +25,7 @@ def test_element_outside_of_scrollable_viewport(session):
     session.url = inline("<input style=\"margin-top: 102vh;\">")
     element = session.find.css("input", all=False)
 
-    response = send_keys_to_element(session, element, "foo")
+    response = element_send_keys(session, element, "foo")
     assert_success(response)
 
     assert is_element_in_viewport(session, element)
@@ -42,7 +41,7 @@ def test_option_select_container_outside_of_scrollable_viewport(session):
     element = session.find.css("option#bar", all=False)
     select = session.find.css("select", all=False)
 
-    response = send_keys_to_element(session, element, "bar")
+    response = element_send_keys(session, element, "bar")
     assert_success(response)
 
     assert is_element_in_viewport(session, select)
@@ -60,7 +59,7 @@ def test_option_stays_outside_of_scrollable_viewport(session):
     option_foo = session.find.css("option#foo", all=False)
     option_bar = session.find.css("option#bar", all=False)
 
-    response = send_keys_to_element(session, option_bar, "bar")
+    response = element_send_keys(session, option_bar, "bar")
     assert_success(response)
 
     assert is_element_in_viewport(session, select)
@@ -72,7 +71,7 @@ def test_contenteditable_element_outside_of_scrollable_viewport(session):
     session.url = inline("<div contenteditable style=\"margin-top: 102vh;\"></div>")
     element = session.find.css("div", all=False)
 
-    response = send_keys_to_element(session, element, "foo")
+    response = element_send_keys(session, element, "foo")
     assert_success(response)
 
     assert is_element_in_viewport(session, element)
index 5affdc9..b8602af 100644 (file)
@@ -8,9 +8,9 @@ def execute_async_script(session, script, args=None):
     if args is None:
         args = []
     body = {"script": script, "args": args}
+
     return session.transport.send(
-        "POST",
-        "/session/{session_id}/execute/async".format(**vars(session)),
+        "POST", "/session/{session_id}/execute/async".format(**vars(session)),
         body)
 
 
index 67f5512..7daf2a9 100644 (file)
@@ -2,70 +2,94 @@ import pytest
 
 from webdriver import error
 
+from tests.support.asserts import assert_success
+
+
+def execute_async_script(session, script, args=None):
+    if args is None:
+        args = []
+    body = {"script": script, "args": args}
+
+    return session.transport.send(
+        "POST", "/session/{session_id}/execute/async".format(**vars(session)),
+        body)
 
-# 15.2 Executing Script
 
 def test_handle_prompt_accept(new_session, add_browser_capabilites):
     _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "accept"})}})
-    value = session.execute_async_script("window.alert('Hello');")
-    assert value is None
-    title = session.title
+
+    response = execute_async_script(session, "window.alert('Hello');")
+    assert_success(response, None)
+
+    session.title
     with pytest.raises(error.NoSuchAlertException):
         session.alert.accept()
 
 
 def test_handle_prompt_dismiss(new_session, add_browser_capabilites):
     _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "dismiss"})}})
-    value = session.execute_async_script("window.alert('Hello');")
-    assert value is None
-    title = session.title
+
+    response = execute_async_script(session, "window.alert('Hello');")
+    assert_success(response, None)
+
+    session.title
     with pytest.raises(error.NoSuchAlertException):
         session.alert.dismiss()
 
 
 def test_handle_prompt_dismiss_and_notify(new_session, add_browser_capabilites):
     _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "dismiss and notify"})}})
-    value = session.execute_async_script("window.alert('Hello');")
-    assert value is None
+
+    response = execute_async_script(session, "window.alert('Hello');")
+    assert_success(response, None)
+
     with pytest.raises(error.UnexpectedAlertOpenException):
-        title = session.title
+        session.title
     with pytest.raises(error.NoSuchAlertException):
         session.alert.dismiss()
 
 
 def test_handle_prompt_accept_and_notify(new_session, add_browser_capabilites):
     _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "accept and notify"})}})
-    value = session.execute_async_script("window.alert('Hello');")
-    assert value is None
+
+    response = execute_async_script(session, "window.alert('Hello');")
+    assert_success(response, None)
+
     with pytest.raises(error.UnexpectedAlertOpenException):
-        title = session.title
+        session.title
     with pytest.raises(error.NoSuchAlertException):
         session.alert.accept()
 
 
 def test_handle_prompt_ignore(new_session, add_browser_capabilites):
     _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "ignore"})}})
-    value = session.execute_async_script("window.alert('Hello');")
-    assert value is None
+
+    response = execute_async_script(session, "window.alert('Hello');")
+    assert_success(response, None)
+
     with pytest.raises(error.UnexpectedAlertOpenException):
-        title = session.title
+        session.title
     session.alert.dismiss()
 
 
 def test_handle_prompt_default(new_session, add_browser_capabilites):
     _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({})}})
-    value = session.execute_async_script("window.alert('Hello');")
-    assert value is None
+
+    response = execute_async_script(session, "window.alert('Hello');")
+    assert_success(response, None)
+
     with pytest.raises(error.UnexpectedAlertOpenException):
-        title = session.title
+        session.title
     with pytest.raises(error.NoSuchAlertException):
         session.alert.dismiss()
 
 
 def test_handle_prompt_twice(new_session, add_browser_capabilites):
     _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "accept"})}})
-    value = session.execute_async_script("window.alert('Hello');window.alert('Bye');")
-    assert value is None
+
+    response = execute_async_script(session, "window.alert('Hello');window.alert('Bye');")
+    assert_success(response, None)
+
     session.alert.dismiss()
     # The first alert has been accepted by the user prompt handler, the second one remains.
     # FIXME: this is how browsers currently work, but the spec should clarify if this is the
index d96c7fe..edee1e5 100644 (file)
@@ -8,9 +8,9 @@ def execute_script(session, script, args=None):
     if args is None:
         args = []
     body = {"script": script, "args": args}
+
     return session.transport.send(
-        "POST",
-        "/session/{session_id}/execute/sync".format(**vars(session)),
+        "POST", "/session/{session_id}/execute/sync".format(**vars(session)),
         body)
 
 
index 4df9c41..bc52b47 100644 (file)
@@ -5,9 +5,9 @@ def execute_script(session, script, args=None):
     if args is None:
         args = []
     body = {"script": script, "args": args}
+
     return session.transport.send(
-        "POST",
-        "/session/{session_id}/execute/sync".format(
+        "POST", "/session/{session_id}/execute/sync".format(
             session_id=session.session_id),
         body)
 
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/execute_script/json_serialize_windowproxy.py b/WebDriverTests/imported/w3c/webdriver/tests/execute_script/json_serialize_windowproxy.py
new file mode 100644 (file)
index 0000000..9864227
--- /dev/null
@@ -0,0 +1,61 @@
+import json
+
+from tests.support.asserts import assert_success
+
+
+_window_id = "window-fcc6-11e5-b4f8-330a88ab9d7f"
+_frame_id = "frame-075b-4da1-b6ba-e579c2d3230a"
+
+
+def execute_script(session, script, args=None):
+    if args is None:
+        args = []
+    body = {"script": script, "args": args}
+
+    return session.transport.send(
+        "POST", "/session/{session_id}/execute/sync".format(**vars(session)),
+        body)
+
+
+def test_initial_window(session):
+    # non-auxiliary top-level browsing context
+    response = execute_script(session, "return window;")
+    raw_json = assert_success(response)
+
+    obj = json.loads(raw_json)
+    assert len(obj) == 1
+    assert _window_id in obj
+    handle = obj[_window_id]
+    assert handle in session.window_handles
+
+
+def test_window_open(session):
+    # auxiliary browsing context
+    session.execute_script("window.foo = window.open()")
+
+    response = execute_script(session, "return window.foo;")
+    raw_json = assert_success(response)
+
+    obj = json.loads(raw_json)
+    assert len(obj) == 1
+    assert _window_id in obj
+    handle = obj[_window_id]
+    assert handle in session.window_handles
+
+
+def test_frame(session):
+    # nested browsing context
+    append = """
+        window.frame = document.createElement('iframe');
+        document.body.appendChild(frame);
+    """
+    session.execute_script(append)
+
+    response = execute_script(session, "return frame.contentWindow;")
+    raw_json = assert_success(response)
+
+    obj = json.loads(raw_json)
+    assert len(obj) == 1
+    assert _frame_id in obj
+    handle = obj[_frame_id]
+    assert handle not in session.window_handles
index befa8d8..a4cc680 100644 (file)
@@ -2,70 +2,95 @@ import pytest
 
 from webdriver import error
 
+from tests.support.asserts import assert_success
+
+
+def execute_script(session, script, args=None):
+    if args is None:
+        args = []
+    body = {"script": script, "args": args}
+
+    return session.transport.send(
+        "POST", "/session/{session_id}/execute/sync".format(
+            session_id=session.session_id),
+        body)
 
-# 15.2 Executing Script
 
 def test_handle_prompt_accept(new_session, add_browser_capabilites):
     _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "accept"})}})
-    value = session.execute_script("window.alert('Hello');")
-    assert value is None
-    title = session.title
+
+    response = execute_script(session, "window.alert('Hello');")
+    assert_success(response, None)
+
+    session.title
     with pytest.raises(error.NoSuchAlertException):
         session.alert.accept()
 
 
 def test_handle_prompt_dismiss(new_session, add_browser_capabilites):
     _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "dismiss"})}})
-    value = session.execute_script("window.alert('Hello');")
-    assert value is None
-    title = session.title
+
+    response = execute_script(session, "window.alert('Hello');")
+    assert_success(response, None)
+
+    session.title
     with pytest.raises(error.NoSuchAlertException):
         session.alert.dismiss()
 
 
 def test_handle_prompt_dismiss_and_notify(new_session, add_browser_capabilites):
     _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "dismiss and notify"})}})
-    value = session.execute_script("window.alert('Hello');")
-    assert value is None
+
+    response = execute_script(session, "window.alert('Hello');")
+    assert_success(response, None)
+
     with pytest.raises(error.UnexpectedAlertOpenException):
-        title = session.title
+        session.title
     with pytest.raises(error.NoSuchAlertException):
         session.alert.dismiss()
 
 
 def test_handle_prompt_accept_and_notify(new_session, add_browser_capabilites):
     _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "accept and notify"})}})
-    value = session.execute_script("window.alert('Hello');")
-    assert value is None
+
+    response = execute_script(session, "window.alert('Hello');")
+    assert_success(response, None)
+
     with pytest.raises(error.UnexpectedAlertOpenException):
-        title = session.title
+        session.title
     with pytest.raises(error.NoSuchAlertException):
         session.alert.accept()
 
 
 def test_handle_prompt_ignore(new_session, add_browser_capabilites):
     _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "ignore"})}})
-    value = session.execute_script("window.alert('Hello');")
-    assert value is None
+
+    response = execute_script(session, "window.alert('Hello');")
+    assert_success(response, None)
+
     with pytest.raises(error.UnexpectedAlertOpenException):
-        title = session.title
+        session.title
     session.alert.dismiss()
 
 
 def test_handle_prompt_default(new_session, add_browser_capabilites):
     _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({})}})
-    value = session.execute_script("window.alert('Hello');")
-    assert value is None
+
+    response = execute_script(session, "window.alert('Hello');")
+    assert_success(response, None)
+
     with pytest.raises(error.UnexpectedAlertOpenException):
-        title = session.title
+        session.title
     with pytest.raises(error.NoSuchAlertException):
         session.alert.dismiss()
 
 
 def test_handle_prompt_twice(new_session, add_browser_capabilites):
     _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "accept"})}})
-    value = session.execute_script("window.alert('Hello');window.alert('Bye');")
-    assert value is None
+
+    response = execute_script(session, "window.alert('Hello');window.alert('Bye');")
+    assert_success(response, None)
+
     session.alert.dismiss()
     # The first alert has been accepted by the user prompt handler, the second one remains.
     # FIXME: this is how browsers currently work, but the spec should clarify if this is the
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/find_element/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/find_element/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/find_element/find.py b/WebDriverTests/imported/w3c/webdriver/tests/find_element/find.py
new file mode 100644 (file)
index 0000000..7563179
--- /dev/null
@@ -0,0 +1,117 @@
+import pytest
+
+from tests.support.asserts import assert_error, assert_same_element, assert_success
+from tests.support.inline import inline
+
+
+def find_element(session, using, value):
+    return session.transport.send(
+        "POST", "session/{session_id}/element".format(**vars(session)),
+        {"using": using, "value": value})
+
+
+# 12.2 Find Element
+
+@pytest.mark.parametrize("using", ["a", True, None, 1, [], {}])
+def test_invalid_using_argument(session, using):
+    # Step 1 - 2
+    response = find_element(session, using, "value")
+    assert_error(response, "invalid argument")
+
+
+@pytest.mark.parametrize("value", [None, [], {}])
+def test_invalid_selector_argument(session, value):
+    # Step 3 - 4
+    response = find_element(session, "css selector", value)
+    assert_error(response, "invalid argument")
+
+
+def test_closed_context(session, create_window):
+    # Step 5
+    new_window = create_window()
+    session.window_handle = new_window
+    session.close()
+
+    response = find_element(session, "css selector", "foo")
+
+    assert_error(response, "no such window")
+
+
+@pytest.mark.parametrize("using,value",
+                         [("css selector", "#linkText"),
+                          ("link text", "full link text"),
+                          ("partial link text", "link text"),
+                          ("tag name", "a"),
+                          ("xpath", "//a")])
+def test_find_element(session, using, value):
+    # Step 8 - 9
+    session.url = inline("<a href=# id=linkText>full link text</a>")
+
+    response = find_element(session, using, value)
+    assert_success(response)
+
+
+@pytest.mark.parametrize("document,value", [
+    ("<a href=#>link text</a>", "link text"),
+    ("<a href=#>&nbsp;link text&nbsp;</a>", "link text"),
+    ("<a href=#>link<br>text</a>", "link\ntext"),
+    ("<a href=#>link&amp;text</a>", "link&text"),
+    ("<a href=#>LINK TEXT</a>", "LINK TEXT"),
+    ("<a href=# style='text-transform: uppercase'>link text</a>", "LINK TEXT"),
+])
+def test_find_element_link_text(session, document, value):
+    # Step 8 - 9
+    session.url = inline(document)
+
+    response = find_element(session, "link text", value)
+    assert_success(response)
+
+
+@pytest.mark.parametrize("document,value", [
+    ("<a href=#>partial link text</a>", "link"),
+    ("<a href=#>&nbsp;partial link text&nbsp;</a>", "link"),
+    ("<a href=#>partial link text</a>", "k t"),
+    ("<a href=#>partial link<br>text</a>", "k\nt"),
+    ("<a href=#>partial link&amp;text</a>", "k&t"),
+    ("<a href=#>PARTIAL LINK TEXT</a>", "LINK"),
+    ("<a href=# style='text-transform: uppercase'>partial link text</a>", "LINK"),
+])
+def test_find_element_partial_link_text(session, document, value):
+    # Step 8 - 9
+    session.url = inline(document)
+
+    response = find_element(session, "partial link text", value)
+    assert_success(response)
+
+
+@pytest.mark.parametrize("using,value", [("css selector", "#wontExist")])
+def test_no_element(session, using, value):
+    # Step 8 - 9
+    response = find_element(session, using, value)
+    assert_error(response, "no such element")
+
+
+@pytest.mark.parametrize("using,value",
+                         [("css selector", "#linkText"),
+                          ("link text", "full link text"),
+                          ("partial link text", "link text"),
+                          ("tag name", "a"),
+                          ("xpath", "//*[name()='a']")])
+def test_xhtml_namespace(session, using, value):
+    session.url = inline("""<a href="#" id="linkText">full link text</a>""",
+                         doctype="xhtml")
+    expected = session.execute_script("return document.links[0]")
+
+    response = find_element(session, using, value)
+    value = assert_success(response)
+    assert_same_element(session, value, expected)
+
+
+@pytest.mark.parametrize("using,value",
+                         [("css selector", ":root"),
+                          ("tag name", "html"),
+                          ("xpath", "/html")])
+def test_htmldocument(session, using, value):
+    session.url = inline("")
+    response = find_element(session, using, value)
+    assert_success(response)
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/find_element_from_element/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/find_element_from_element/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/find_element_from_element/find.py b/WebDriverTests/imported/w3c/webdriver/tests/find_element_from_element/find.py
new file mode 100644 (file)
index 0000000..d5713b3
--- /dev/null
@@ -0,0 +1,129 @@
+import pytest
+
+from tests.support.asserts import assert_error, assert_same_element, assert_success
+from tests.support.inline import inline
+
+
+def find_element(session, element_id, using, value):
+    return session.transport.send(
+        "POST", "session/{session_id}/element/{element_id}/element".format(
+            session_id=session.session_id,
+            element_id=element_id),
+        {"using": using, "value": value})
+
+
+@pytest.mark.parametrize("using", ["a", True, None, 1, [], {}])
+def test_invalid_using_argument(session, using):
+    # Step 1 - 2
+    response = find_element(session, "notReal", using, "value")
+    assert_error(response, "invalid argument")
+
+
+@pytest.mark.parametrize("value", [None, [], {}])
+def test_invalid_selector_argument(session, value):
+    # Step 3 - 4
+    response = find_element(session, "notReal", "css selector", value)
+    assert_error(response, "invalid argument")
+
+
+def test_closed_context(session, create_window):
+    # Step 5
+    new_window = create_window()
+    session.window_handle = new_window
+    session.close()
+
+    response = find_element(session, "notReal", "css selector", "foo")
+    assert_error(response, "no such window")
+
+
+@pytest.mark.parametrize("using,value",
+                         [("css selector", "#linkText"),
+                          ("link text", "full link text"),
+                          ("partial link text", "link text"),
+                          ("tag name", "a"),
+                          ("xpath", "//a")])
+def test_find_element(session, using, value):
+    # Step 8 - 9
+    session.url = inline("<div><a href=# id=linkText>full link text</a></div>")
+    element = session.find.css("div", all=False)
+    response = find_element(session, element.id, using, value)
+    assert_success(response)
+
+
+@pytest.mark.parametrize("document,value", [
+    ("<a href=#>link text</a>", "link text"),
+    ("<a href=#>&nbsp;link text&nbsp;</a>", "link text"),
+    ("<a href=#>link<br>text</a>", "link\ntext"),
+    ("<a href=#>link&amp;text</a>", "link&text"),
+    ("<a href=#>LINK TEXT</a>", "LINK TEXT"),
+    ("<a href=# style='text-transform: uppercase'>link text</a>", "LINK TEXT"),
+])
+def test_find_element_link_text(session, document, value):
+    # Step 8 - 9
+    session.url = inline("<div>{0}</div>".format(document))
+    element = session.find.css("div", all=False)
+
+    response = find_element(session, element.id, "link text", value)
+    assert_success(response)
+
+
+@pytest.mark.parametrize("document,value", [
+    ("<a href=#>partial link text</a>", "link"),
+    ("<a href=#>&nbsp;partial link text&nbsp;</a>", "link"),
+    ("<a href=#>partial link text</a>", "k t"),
+    ("<a href=#>partial link<br>text</a>", "k\nt"),
+    ("<a href=#>partial link&amp;text</a>", "k&t"),
+    ("<a href=#>PARTIAL LINK TEXT</a>", "LINK"),
+    ("<a href=# style='text-transform: uppercase'>partial link text</a>", "LINK"),
+])
+def test_find_element_partial_link_text(session, document, value):
+    # Step 8 - 9
+    session.url = inline("<div>{0}</div>".format(document))
+    element = session.find.css("div", all=False)
+
+    response = find_element(session, element.id, "partial link text", value)
+    assert_success(response)
+
+
+@pytest.mark.parametrize("using,value",[("css selector", "#wontExist")])
+def test_no_element(session, using, value):
+    # Step 8 - 9
+    session.url = inline("<div></div>")
+    element = session.find.css("div", all=False)
+    response = find_element(session, element.id, using, value)
+    assert_error(response, "no such element")
+
+
+@pytest.mark.parametrize("using,value",
+                         [("css selector", "#linkText"),
+                          ("link text", "full link text"),
+                          ("partial link text", "link text"),
+                          ("tag name", "a"),
+                          ("xpath", "//*[name()='a']")])
+def test_xhtml_namespace(session, using, value):
+    session.url = inline("""<p><a href="#" id="linkText">full link text</a></p>""",
+                         doctype="xhtml")
+    from_element = session.execute_script("""return document.querySelector("p")""")
+    expected = session.execute_script("return document.links[0]")
+
+    response = find_element(session, from_element.id, using, value)
+    value = assert_success(response)
+    assert_same_element(session, value, expected)
+
+
+def test_parent_htmldocument(session):
+    session.url = inline("")
+    from_element = session.execute_script("""return document.querySelector("body")""")
+    expected = session.execute_script("return document.documentElement")
+
+    response = find_element(session, from_element.id, "xpath", "..")
+    value = assert_success(response)
+    assert_same_element(session, value, expected)
+
+
+def test_parent_of_document_node_errors(session):
+    session.url = inline("")
+    from_element = session.execute_script("return document.documentElement")
+
+    response = find_element(session, from_element.id, "xpath", "..")
+    assert_error(response, "invalid selector")
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/find_elements/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/find_elements/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/find_elements/find.py b/WebDriverTests/imported/w3c/webdriver/tests/find_elements/find.py
new file mode 100644 (file)
index 0000000..1dac2a3
--- /dev/null
@@ -0,0 +1,134 @@
+import pytest
+
+from tests.support.asserts import assert_error, assert_same_element, assert_success
+from tests.support.inline import inline
+
+
+def find_elements(session, using, value):
+    return session.transport.send(
+        "POST", "session/{session_id}/elements".format(**vars(session)),
+        {"using": using, "value": value})
+
+
+@pytest.mark.parametrize("using", ["a", True, None, 1, [], {}])
+def test_invalid_using_argument(session, using):
+    # Step 1 - 2
+    response = find_elements(session, using, "value")
+    assert_error(response, "invalid argument")
+
+
+@pytest.mark.parametrize("value", [None, [], {}])
+def test_invalid_selector_argument(session, value):
+    # Step 3 - 4
+    response = find_elements(session, "css selector", value)
+    assert_error(response, "invalid argument")
+
+
+def test_closed_context(session, create_window):
+    # Step 5
+    new_window = create_window()
+    session.window_handle = new_window
+    session.close()
+
+    response = find_elements(session, "css selector", "foo")
+    assert_error(response, "no such window")
+
+
+@pytest.mark.parametrize("using,value",
+                         [("css selector", "#linkText"),
+                          ("link text", "full link text"),
+                          ("partial link text", "link text"),
+                          ("tag name", "a"),
+                          ("xpath", "//a")])
+def test_find_elements(session, using, value):
+    # Step 8 - 9
+    session.url = inline("<a href=# id=linkText>full link text</a>")
+
+    response = find_elements(session, using, value)
+    assert_success(response)
+    assert len(response.body["value"]) == 1
+
+
+@pytest.mark.parametrize("document,value", [
+    ("<a href=#>link text</a>", "link text"),
+    ("<a href=#>&nbsp;link text&nbsp;</a>", "link text"),
+    ("<a href=#>link<br>text</a>", "link\ntext"),
+    ("<a href=#>link&amp;text</a>", "link&text"),
+    ("<a href=#>LINK TEXT</a>", "LINK TEXT"),
+    ("<a href=# style='text-transform: uppercase'>link text</a>", "LINK TEXT"),
+])
+def test_find_elements_link_text(session, document, value):
+    # Step 8 - 9
+    session.url = inline("<a href=#>not wanted</a><br/>{0}".format(document))
+    expected = session.execute_script("return document.links[1];")
+
+    response = find_elements(session, "link text", value)
+    value = assert_success(response)
+    assert isinstance(value, list)
+    assert len(value) == 1
+
+    found_element = value[0]
+    assert_same_element(session, found_element, expected)
+
+
+@pytest.mark.parametrize("document,value", [
+    ("<a href=#>partial link text</a>", "link"),
+    ("<a href=#>&nbsp;partial link text&nbsp;</a>", "link"),
+    ("<a href=#>partial link text</a>", "k t"),
+    ("<a href=#>partial link<br>text</a>", "k\nt"),
+    ("<a href=#>partial link&amp;text</a>", "k&t"),
+    ("<a href=#>PARTIAL LINK TEXT</a>", "LINK"),
+    ("<a href=# style='text-transform: uppercase'>partial link text</a>", "LINK"),
+])
+def test_find_elements_partial_link_text(session, document, value):
+    # Step 8 - 9
+    session.url = inline("<a href=#>not wanted</a><br/>{0}".format(document))
+    expected = session.execute_script("return document.links[1];")
+
+    response = find_elements(session, "partial link text", value)
+    value = assert_success(response)
+    assert isinstance(value, list)
+    assert len(value) == 1
+
+    found_element = value[0]
+    assert_same_element(session, found_element, expected)
+
+
+@pytest.mark.parametrize("using,value", [("css selector", "#wontExist")])
+def test_no_element(session, using, value):
+    # Step 8 - 9
+    response = find_elements(session, using, value)
+    assert_success(response)
+    assert response.body["value"] == []
+
+
+@pytest.mark.parametrize("using,value",
+                         [("css selector", "#linkText"),
+                          ("link text", "full link text"),
+                          ("partial link text", "link text"),
+                          ("tag name", "a"),
+                          ("xpath", "//*[name()='a']")])
+def test_xhtml_namespace(session, using, value):
+    session.url = inline("""<a href="#" id="linkText">full link text</a>""",
+                         doctype="xhtml")
+    expected = session.execute_script("return document.links[0];")
+
+    response = find_elements(session, using, value)
+    value = assert_success(response)
+    assert isinstance(value, list)
+    assert len(value) == 1
+
+    found_element = value[0]
+    assert_same_element(session, found_element, expected)
+
+
+@pytest.mark.parametrize("using,value",
+                         [("css selector", ":root"),
+                          ("tag name", "html"),
+                          ("xpath", "/html")])
+def test_htmldocument(session, using, value):
+    session.url = inline("")
+    response = find_elements(session, using, value)
+    value = assert_success(response)
+    assert isinstance(value, list)
+    assert len(value) == 1
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/find_elements_from_element/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/find_elements_from_element/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/find_elements_from_element/find.py b/WebDriverTests/imported/w3c/webdriver/tests/find_elements_from_element/find.py
new file mode 100644 (file)
index 0000000..d24d45a
--- /dev/null
@@ -0,0 +1,150 @@
+import pytest
+
+from tests.support.asserts import assert_error, assert_same_element, assert_success
+from tests.support.inline import inline
+
+
+def find_elements(session, element_id, using, value):
+    return session.transport.send(
+        "POST", "session/{session_id}/element/{element_id}/elements".format(
+            session_id=session.session_id,
+            element_id=element_id),
+        {"using": using, "value": value})
+
+
+@pytest.mark.parametrize("using", [("a"), (True), (None), (1), ([]), ({})])
+def test_invalid_using_argument(session, using):
+    # Step 1 - 2
+    response = find_elements(session, "notReal", using, "value")
+    assert_error(response, "invalid argument")
+
+
+@pytest.mark.parametrize("value", [None, [], {}])
+def test_invalid_selector_argument(session, value):
+    # Step 3 - 4
+    response = find_elements(session, "notReal", "css selector", value)
+    assert_error(response, "invalid argument")
+
+
+def test_closed_context(session, create_window):
+    # Step 5
+    new_window = create_window()
+    session.window_handle = new_window
+    session.close()
+
+    response = find_elements(session, "notReal", "css selector", "foo")
+
+    assert_error(response, "no such window")
+
+
+@pytest.mark.parametrize("using,value",
+                         [("css selector", "#linkText"),
+                          ("link text", "full link text"),
+                          ("partial link text", "link text"),
+                          ("tag name", "a"),
+                          ("xpath", "//a")])
+def test_find_elements(session, using, value):
+    # Step 8 - 9
+    session.url = inline("<div><a href=# id=linkText>full link text</a></div>")
+    element = session.find.css("div", all=False)
+    response = find_elements(session, element.id, using, value)
+    assert_success(response)
+
+
+@pytest.mark.parametrize("document,value", [
+    ("<a href=#>link text</a>", "link text"),
+    ("<a href=#>&nbsp;link text&nbsp;</a>", "link text"),
+    ("<a href=#>link<br>text</a>", "link\ntext"),
+    ("<a href=#>link&amp;text</a>", "link&text"),
+    ("<a href=#>LINK TEXT</a>", "LINK TEXT"),
+    ("<a href=# style='text-transform: uppercase'>link text</a>", "LINK TEXT"),
+])
+def test_find_elements_link_text(session, document, value):
+    # Step 8 - 9
+    session.url = inline("<div><a href=#>not wanted</a><br/>{0}</div>".format(document))
+    element = session.find.css("div", all=False)
+    expected = session.execute_script("return document.links[1];")
+
+    response = find_elements(session, element.id, "link text", value)
+    value = assert_success(response)
+    assert isinstance(value, list)
+    assert len(value) == 1
+
+    found_element = value[0]
+    assert_same_element(session, found_element, expected)
+
+
+@pytest.mark.parametrize("document,value", [
+    ("<a href=#>partial link text</a>", "link"),
+    ("<a href=#>&nbsp;partial link text&nbsp;</a>", "link"),
+    ("<a href=#>partial link text</a>", "k t"),
+    ("<a href=#>partial link<br>text</a>", "k\nt"),
+    ("<a href=#>partial link&amp;text</a>", "k&t"),
+    ("<a href=#>PARTIAL LINK TEXT</a>", "LINK"),
+    ("<a href=# style='text-transform: uppercase'>partial link text</a>", "LINK"),
+])
+def test_find_elements_partial_link_text(session, document, value):
+    # Step 8 - 9
+    session.url = inline("<div><a href=#>not wanted</a><br/>{0}</div>".format(document))
+    element = session.find.css("div", all=False)
+    expected = session.execute_script("return document.links[1];")
+
+    response = find_elements(session, element.id, "partial link text", value)
+    value = assert_success(response)
+    assert isinstance(value, list)
+    assert len(value) == 1
+
+    found_element = value[0]
+    assert_same_element(session, found_element, expected)
+
+
+@pytest.mark.parametrize("using,value", [("css selector", "#wontExist")])
+def test_no_element(session, using, value):
+    # Step 8 - 9
+    session.url = inline("<div></div>")
+    element = session.find.css("div", all=False)
+    response = find_elements(session, element.id, using, value)
+    assert response.body["value"] == []
+
+
+@pytest.mark.parametrize("using,value",
+                         [("css selector", "#linkText"),
+                          ("link text", "full link text"),
+                          ("partial link text", "link text"),
+                          ("tag name", "a"),
+                          ("xpath", "//*[name()='a']")])
+def test_xhtml_namespace(session, using, value):
+    session.url = inline("""<p><a href="#" id="linkText">full link text</a></p>""",
+                         doctype="xhtml")
+    from_element = session.execute_script("""return document.querySelector("p")""")
+    expected = session.execute_script("return document.links[0]")
+
+    response = find_elements(session, from_element.id, using, value)
+    value = assert_success(response)
+    assert isinstance(value, list)
+    assert len(value) == 1
+
+    found_element = value[0]
+    assert_same_element(session, found_element, expected)
+
+
+def test_parent_htmldocument(session):
+    session.url = inline("")
+    from_element = session.execute_script("""return document.querySelector("body")""")
+    expected = session.execute_script("return document.documentElement")
+
+    response = find_elements(session, from_element.id, "xpath", "..")
+    value = assert_success(response)
+    assert isinstance(value, list)
+    assert len(value) == 1
+
+    found_element = value[0]
+    assert_same_element(session, found_element, expected)
+
+
+def test_parent_of_document_node_errors(session):
+    session.url = inline("")
+    from_element = session.execute_script("return document.documentElement")
+
+    response = find_elements(session, from_element.id, "xpath", "..")
+    assert_error(response, "invalid selector")
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/fullscreen_window/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/fullscreen_window/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/fullscreen_window/fullscreen.py b/WebDriverTests/imported/w3c/webdriver/tests/fullscreen_window/fullscreen.py
new file mode 100644 (file)
index 0000000..de7d942
--- /dev/null
@@ -0,0 +1,96 @@
+from tests.support.asserts import assert_error, assert_success
+
+
+def fullscreen(session):
+    return session.transport.send(
+        "POST", "session/{session_id}/window/fullscreen".format(**vars(session)))
+
+
+def is_fullscreen(session):
+    # At the time of writing, WebKit does not conform to the Fullscreen API specification.
+    # Remove the prefixed fallback when https://bugs.webkit.org/show_bug.cgi?id=158125 is fixed.
+    return session.execute_script("return !!(window.fullScreen || document.webkitIsFullScreen)")
+
+
+# 10.7.5 Fullscreen Window
+
+
+def test_no_browsing_context(session, create_window):
+    """
+    1. If the current top-level browsing context is no longer open,
+    return error with error code no such window.
+
+    """
+    session.window_handle = create_window()
+    session.close()
+    response = fullscreen(session)
+    assert_error(response, "no such window")
+
+
+def test_fullscreen(session):
+    """
+    4. Call fullscreen an element with the current top-level browsing
+    context's active document's document element.
+
+    """
+    response = fullscreen(session)
+    assert_success(response)
+
+    assert is_fullscreen(session) is True
+
+
+def test_payload(session):
+    """
+    5. Return success with the JSON serialization of the current top-level
+    browsing context's window rect.
+
+    [...]
+
+    A top-level browsing context's window rect is defined as a
+    dictionary of the screenX, screenY, width and height attributes of
+    the WindowProxy. Its JSON representation is the following:
+
+    "x"
+        WindowProxy's screenX attribute.
+
+    "y"
+        WindowProxy's screenY attribute.
+
+    "width"
+        Width of the top-level browsing context's outer dimensions,
+        including any browser chrome and externally drawn window
+        decorations in CSS reference pixels.
+
+    "height"
+        Height of the top-level browsing context's outer dimensions,
+        including any browser chrome and externally drawn window
+        decorations in CSS reference pixels.
+
+    """
+    response = fullscreen(session)
+
+    # step 5
+    assert response.status == 200
+    assert isinstance(response.body["value"], dict)
+
+    value = response.body["value"]
+    assert "width" in value
+    assert "height" in value
+    assert "x" in value
+    assert "y" in value
+    assert isinstance(value["width"], int)
+    assert isinstance(value["height"], int)
+    assert isinstance(value["x"], int)
+    assert isinstance(value["y"], int)
+
+
+def test_fullscreen_twice_is_idempotent(session):
+    assert is_fullscreen(session) is False
+
+    first_response = fullscreen(session)
+    assert_success(first_response)
+    assert is_fullscreen(session) is True
+
+    second_response = fullscreen(session)
+    assert_success(second_response)
+    assert is_fullscreen(session) is True
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/fullscreen_window/user_prompts.py b/WebDriverTests/imported/w3c/webdriver/tests/fullscreen_window/user_prompts.py
new file mode 100644 (file)
index 0000000..421ce81
--- /dev/null
@@ -0,0 +1,116 @@
+from tests.support.asserts import assert_error, assert_dialog_handled
+from tests.support.fixtures import create_dialog
+from tests.support.inline import inline
+
+
+def read_global(session, name):
+    return session.execute_script("return %s;" % name)
+
+
+def fullscreen(session):
+    return session.transport.send("POST", "session/%s/window/fullscreen" % session.session_id)
+
+
+def test_handle_prompt_dismiss_and_notify():
+    """TODO"""
+
+
+def test_handle_prompt_accept_and_notify():
+    """TODO"""
+
+
+def test_handle_prompt_ignore():
+    """TODO"""
+
+
+def test_handle_prompt_accept(new_session, add_browser_capabilites):
+    """
+    2. Handle any user prompts and return its value if it is an error.
+
+    [...]
+
+    In order to handle any user prompts a remote end must take the
+    following steps:
+
+      [...]
+
+      2. Perform the following substeps based on the current session's
+      user prompt handler:
+
+        [...]
+
+        - accept state
+           Accept the current user prompt.
+
+    """
+    _, session = new_session({"capabilities": {
+        "alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "accept"})}})
+    session.url = inline("<title>WD doc title</title>")
+    create_dialog(session)("alert", text="accept #1", result_var="accept1")
+
+    fullscreen(session)
+
+    assert_dialog_handled(session, "accept #1")
+    assert read_global(session, "accept1") is None
+
+    read_global(session, "document.title")
+    create_dialog(session)("confirm", text="accept #2", result_var="accept2")
+
+    fullscreen(session)
+
+    assert_dialog_handled(session, "accept #2")
+    assert read_global(session, "accept2"), True
+
+    create_dialog(session)("prompt", text="accept #3", result_var="accept3")
+
+    fullscreen(session)
+
+    assert_dialog_handled(session, "accept #3")
+    assert read_global(session, "accept3") == "" or read_global(session, "accept3") == "undefined"
+
+
+def test_handle_prompt_missing_value(session, create_dialog):
+    """
+    2. Handle any user prompts and return its value if it is an error.
+
+    [...]
+
+    In order to handle any user prompts a remote end must take the
+    following steps:
+
+      [...]
+
+      2. Perform the following substeps based on the current session's
+      user prompt handler:
+
+        [...]
+
+        - missing value default state
+           1. Dismiss the current user prompt.
+           2. Return error with error code unexpected alert open.
+
+    """
+    session.url = inline("<title>WD doc title</title>")
+    create_dialog("alert", text="dismiss #1", result_var="dismiss1")
+
+    response = fullscreen(session)
+
+    assert_error(response, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #1")
+    assert read_global(session, "dismiss1") is None
+
+    create_dialog("confirm", text="dismiss #2", result_var="dismiss2")
+
+    response = fullscreen(session)
+
+    assert_error(response, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #2")
+    assert read_global(session, "dismiss2") is False
+
+    create_dialog("prompt", text="dismiss #3", result_var="dismiss3")
+
+    response = fullscreen(session)
+
+    assert_error(response, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #3")
+    assert read_global(session, "dismiss3") is None
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_active_element/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/get_active_element/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_active_element/get.py b/WebDriverTests/imported/w3c/webdriver/tests/get_active_element/get.py
new file mode 100644 (file)
index 0000000..d13effb
--- /dev/null
@@ -0,0 +1,149 @@
+from tests.support.asserts import assert_error, assert_same_element
+from tests.support.inline import inline
+
+
+def read_global(session, name):
+    return session.execute_script("return %s;" % name)
+
+
+def get_active_element(session):
+    return session.transport.send(
+        "GET", "session/{session_id}/element/active".format(**vars(session)))
+
+
+def assert_is_active_element(session, response):
+    """Ensure that the provided object is a successful WebDriver
+    response describing an element reference and that the referenced
+    element matches the element returned by the `activeElement`
+    attribute of the current browsing context's active document.
+
+    """
+    assert response.status == 200
+    assert "value" in response.body
+
+    from_js = session.execute_script("return document.activeElement")
+
+    if response.body["value"] is None:
+        assert from_js is None
+    else:
+        assert_same_element(session, response.body["value"], from_js)
+
+
+def test_closed_context(session, create_window):
+    """
+    > 1. If the current browsing context is no longer open, return error with
+    >    error code no such window.
+    """
+    new_window = create_window()
+    session.window_handle = new_window
+    session.close()
+
+    response = get_active_element(session)
+    assert_error(response, "no such window")
+
+
+def test_success_document(session):
+    """
+    > [...]
+    > 3. Let active element be the active element of the current browsing
+    >    context's document element.
+    > 4. Let active web element be the JSON Serialization of active element.
+    > 5. Return success with data active web element.
+    """
+    session.url = inline("""
+        <body>
+            <h1>Heading</h1>
+            <input />
+            <input />
+            <input style="opacity: 0" />
+            <p>Another element</p>
+        </body>""")
+    response = get_active_element(session)
+    assert_is_active_element(session, response)
+
+
+def test_sucess_input(session):
+    session.url = inline("""
+        <body>
+            <h1>Heading</h1>
+            <input autofocus />
+            <input style="opacity: 0" />
+            <p>Another element</p>
+        </body>""")
+    response = get_active_element(session)
+    assert_is_active_element(session, response)
+
+
+def test_sucess_input_non_interactable(session):
+    session.url = inline("""
+        <body>
+            <h1>Heading</h1>
+            <input />
+            <input style="opacity: 0" autofocus />
+            <p>Another element</p>
+        </body>""")
+    response = get_active_element(session)
+    assert_is_active_element(session, response)
+
+
+def test_success_explicit_focus(session):
+    session.url = inline("""
+        <body>
+            <h1>Heading</h1>
+            <input />
+            <iframe></iframe>
+        </body>""")
+
+    session.execute_script("document.body.getElementsByTagName('h1')[0].focus()")
+    response = get_active_element(session)
+    assert_is_active_element(session, response)
+
+    session.execute_script("document.body.getElementsByTagName('input')[0].focus()")
+    response = get_active_element(session)
+    assert_is_active_element(session, response)
+
+    session.execute_script("document.body.getElementsByTagName('iframe')[0].focus()")
+    response = get_active_element(session)
+    assert_is_active_element(session, response)
+
+    session.execute_script("document.body.getElementsByTagName('iframe')[0].focus();")
+    session.execute_script("""
+        var iframe = document.body.getElementsByTagName('iframe')[0];
+        if (iframe.remove) {
+          iframe.remove();
+        } else {
+          iframe.removeNode(true);
+        }""")
+    response = get_active_element(session)
+    assert_is_active_element(session, response)
+
+    session.execute_script("document.body.appendChild(document.createElement('textarea'))")
+    response = get_active_element(session)
+    assert_is_active_element(session, response)
+
+
+def test_success_iframe_content(session):
+    session.url = inline("<body></body>")
+    session.execute_script("""
+        let iframe = document.createElement('iframe');
+        document.body.appendChild(iframe);
+        let input = iframe.contentDocument.createElement('input');
+        iframe.contentDocument.body.appendChild(input);
+        input.focus();
+        """)
+
+    response = get_active_element(session)
+    assert_is_active_element(session, response)
+
+
+def test_missing_document_element(session):
+    session.url = inline("<body></body>")
+    session.execute_script("""
+        if (document.body.remove) {
+          document.body.remove();
+        } else {
+          document.body.removeNode(true);
+        }""")
+
+    response = get_active_element(session)
+    assert_error(response, "no such element")
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_alert_text/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/get_alert_text/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_alert_text/get.py b/WebDriverTests/imported/w3c/webdriver/tests/get_alert_text/get.py
new file mode 100644 (file)
index 0000000..28f8671
--- /dev/null
@@ -0,0 +1,60 @@
+from tests.support.asserts import assert_error, assert_success
+from tests.support.inline import inline
+
+
+def get_alert_text(session):
+    return session.transport.send(
+        "GET", "session/{session_id}/alert/text".format(**vars(session)))
+
+
+# 18.3 Get Alert Text
+
+def test_no_browsing_context(session, create_window):
+    # 18.3 step 1
+    session.window_handle = create_window()
+    session.close()
+
+    response = get_alert_text(session)
+    assert_error(response, "no such window")
+
+
+def test_no_user_prompt(session):
+    # 18.3 step 2
+    response = get_alert_text(session)
+    assert_error(response, "no such alert")
+
+
+def test_get_alert_text(session):
+    # 18.3 step 3
+    session.url = inline("<script>window.alert('Hello');</script>")
+    response = get_alert_text(session)
+    assert_success(response)
+    assert isinstance(response.body, dict)
+    assert "value" in response.body
+    alert_text = response.body["value"]
+    assert isinstance(alert_text, basestring)
+    assert alert_text == "Hello"
+
+
+def test_get_confirm_text(session):
+    # 18.3 step 3
+    session.url = inline("<script>window.confirm('Hello');</script>")
+    response = get_alert_text(session)
+    assert_success(response)
+    assert isinstance(response.body, dict)
+    assert "value" in response.body
+    confirm_text = response.body["value"]
+    assert isinstance(confirm_text, basestring)
+    assert confirm_text == "Hello"
+
+
+def test_get_prompt_text(session):
+    # 18.3 step 3
+    session.url = inline("<script>window.prompt('Enter Your Name: ', 'Federer');</script>")
+    response = get_alert_text(session)
+    assert_success(response)
+    assert isinstance(response.body, dict)
+    assert "value" in response.body
+    prompt_text = response.body["value"]
+    assert isinstance(prompt_text, basestring)
+    assert prompt_text == "Enter Your Name: "
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_current_url/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/get_current_url/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_current_url/get.py b/WebDriverTests/imported/w3c/webdriver/tests/get_current_url/get.py
new file mode 100644 (file)
index 0000000..2b7965f
--- /dev/null
@@ -0,0 +1,100 @@
+import json
+import pytest
+import types
+
+from tests.support.inline import inline
+from tests.support.asserts import assert_error, assert_success
+from tests.support.wait import wait
+
+alert_doc = inline("<script>window.alert()</script>")
+frame_doc = inline("<p>frame")
+one_frame_doc = inline("<iframe src='%s'></iframe>" % frame_doc)
+two_frames_doc = inline("<iframe src='%s'></iframe>" % one_frame_doc)
+
+
+def get_current_url(session):
+    return session.transport.send(
+        "GET", "session/{session_id}/url".format(**vars(session)))
+
+
+# TODO(ato): 7.1 Get
+
+
+def test_get_current_url_no_browsing_context(session, create_window):
+    # 7.2 step 1
+    session.window_handle = create_window()
+    session.close()
+
+    result = get_current_url(session)
+    assert_error(result, "no such window")
+
+def test_get_current_url_matches_location(session):
+    # 7.2 step 3
+    url = session.execute_script("return window.location.href")
+
+    result = get_current_url(session)
+    assert_success(result, url)
+
+def test_get_current_url_payload(session):
+    # 7.2 step 4-5
+    session.start()
+
+    result = get_current_url(session)
+    assert result.status == 200
+    assert isinstance(result.body["value"], basestring)
+
+def test_get_current_url_special_pages(session):
+    session.url = "about:blank"
+
+    result = get_current_url(session)
+    assert_success(result, "about:blank")
+
+# TODO(ato): This test requires modification to pass on Windows
+def test_get_current_url_file_protocol(session):
+    # tests that the browsing context remains the same
+    # when navigated privileged documents
+    session.url = "file:///"
+
+    result = get_current_url(session)
+    assert_success(result, "file:///")
+
+# TODO(ato): Test for http:// and https:// protocols.
+# We need to expose a fixture for accessing
+# documents served by wptserve in order to test this.
+
+def test_set_malformed_url(session):
+    result = session.transport.send("POST",
+                                    "session/%s/url" % session.session_id,
+                                    {"url": "foo"})
+
+    assert_error(result, "invalid argument")
+
+def test_get_current_url_after_modified_location(session):
+    start = get_current_url(session)
+    session.execute_script("window.location.href = 'about:blank#wd_test_modification'")
+    wait(session,
+         lambda _: get_current_url(session).body["value"] != start.body["value"],
+         "URL did not change")
+
+    result = get_current_url(session)
+    assert_success(result, "about:blank#wd_test_modification")
+
+def test_get_current_url_nested_browsing_context(session, create_frame):
+    session.url = "about:blank#wd_from_within_frame"
+    session.switch_frame(create_frame())
+
+    result = get_current_url(session)
+    assert_success(result, "about:blank#wd_from_within_frame")
+
+def test_get_current_url_nested_browsing_contexts(session):
+    session.url = two_frames_doc
+    top_level_url = session.url
+
+    outer_frame = session.find.css("iframe", all=False)
+    session.switch_frame(outer_frame)
+
+    inner_frame = session.find.css("iframe", all=False)
+    session.switch_frame(inner_frame)
+
+    result = get_current_url(session)
+    assert_success(result, top_level_url)
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_current_url/user_prompts.py b/WebDriverTests/imported/w3c/webdriver/tests/get_current_url/user_prompts.py
new file mode 100644 (file)
index 0000000..8bf2867
--- /dev/null
@@ -0,0 +1,77 @@
+from tests.support.asserts import assert_error, assert_dialog_handled
+from tests.support.fixtures import create_dialog
+from tests.support.inline import inline
+
+
+def read_global(session, name):
+    return session.execute_script("return %s;" % name)
+
+
+def get_current_url(session):
+    return session.transport.send("GET", "session/%s/url" % session.session_id)
+
+
+def test_handle_prompt_dismiss_and_notify():
+    """TODO"""
+
+
+def test_handle_prompt_accept_and_notify():
+    """TODO"""
+
+
+def test_handle_prompt_ignore():
+    """TODO"""
+
+
+def test_handle_prompt_accept(new_session, add_browser_capabilites):
+    _, session = new_session({"capabilities": {
+        "alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "accept"})}})
+    session.url = inline("<title>WD doc title</title>")
+    create_dialog(session)("alert", text="accept #1", result_var="accept1")
+
+    get_current_url(session)
+
+    assert_dialog_handled(session, "accept #1")
+    assert read_global(session, "accept1") is None
+
+    read_global(session, "document.title")
+    create_dialog(session)("confirm", text="accept #2", result_var="accept2")
+
+    get_current_url(session)
+
+    assert_dialog_handled(session, "accept #2")
+    assert read_global(session, "accept2"), True
+
+    create_dialog(session)("prompt", text="accept #3", result_var="accept3")
+
+    get_current_url(session)
+
+    assert_dialog_handled(session, "accept #3")
+    assert read_global(session, "accept3") == "" or read_global(session, "accept3") == "undefined"
+
+
+def test_handle_prompt_missing_value(session, create_dialog):
+    session.url = inline("<title>WD doc title</title>")
+    create_dialog("alert", text="dismiss #1", result_var="dismiss1")
+
+    response = get_current_url(session)
+
+    assert_error(response, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #1")
+    assert read_global(session, "dismiss1") is None
+
+    create_dialog("confirm", text="dismiss #2", result_var="dismiss2")
+
+    response = get_current_url(session)
+
+    assert_error(response, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #2")
+    assert read_global(session, "dismiss2") is False
+
+    create_dialog("prompt", text="dismiss #3", result_var="dismiss3")
+
+    response = get_current_url(session)
+
+    assert_error(response, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #3")
+    assert read_global(session, "dismiss3") is None
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_element_attribute/get.py b/WebDriverTests/imported/w3c/webdriver/tests/get_element_attribute/get.py
new file mode 100644 (file)
index 0000000..3fcc01a
--- /dev/null
@@ -0,0 +1,101 @@
+import pytest
+
+from tests.support.asserts import assert_error, assert_success
+from tests.support.inline import inline
+
+
+def get_element_attribute(session, element, attr):
+    return session.transport.send(
+        "GET", "session/{session_id}/element/{element_id}/attribute/{attr}".format(
+            session_id=session.session_id,
+            element_id=element,
+            attr=attr))
+
+
+def test_no_browsing_context(session, create_window):
+    session.window_handle = create_window()
+    session.close()
+
+    result = get_element_attribute(session, "foo", "id")
+    assert_error(result, "no such window")
+
+def test_element_not_found(session):
+    # 13.2 Step 3
+    result = get_element_attribute(session, "foo", "id")
+    assert_error(result, "no such element")
+
+
+def test_element_stale(session):
+    session.url = inline("<input id=foo>")
+    element = session.find.css("input", all=False)
+    session.refresh()
+    result = get_element_attribute(session, element.id, "id")
+    assert_error(result, "stale element reference")
+
+
+def test_normal(session):
+    # 13.2 Step 5
+    session.url = inline("<input type=checkbox>")
+    element = session.find.css("input", all=False)
+    result = get_element_attribute(session, element.id, "input")
+    assert_success(result, None)
+
+    # Check we are not returning the property which will have a different value
+    assert session.execute_script("return document.querySelector('input').checked") is False
+    element.click()
+    assert True == session.execute_script("return document.querySelector('input').checked")
+    result = get_element_attribute(session, element.id, "input")
+    assert_success(result, None)
+
+
+@pytest.mark.parametrize("tag,attrs", [
+    ("audio", ["autoplay", "controls", "loop", "muted"]),
+    ("button", ["autofocus", "disabled", "formnovalidate"]),
+    ("details", ["open"]),
+    ("dialog", ["open"]),
+    ("fieldset", ["disabled"]),
+    ("form", ["novalidate"]),
+    ("iframe", ["allowfullscreen"]),
+    ("img", ["ismap"]),
+    ("input", ["autofocus", "checked", "disabled", "formnovalidate", "multiple", "readonly", "required"]),
+    ("menuitem", ["checked", "default", "disabled"]),
+    ("object", ["typemustmatch"]),
+    ("ol", ["reversed"]),
+    ("optgroup", ["disabled"]),
+    ("option", ["disabled", "selected"]),
+    ("script", ["async", "defer"]),
+    ("select", ["autofocus", "disabled", "multiple", "required"]),
+    ("textarea", ["autofocus", "disabled", "readonly", "required"]),
+    ("track", ["default"]),
+    ("video", ["autoplay", "controls", "loop", "muted"])
+])
+def test_boolean_attribute(session, tag, attrs):
+    for attr in attrs:
+        session.url = inline("<{0} {1}>".format(tag, attr))
+        element = session.find.css(tag, all=False)
+        result = result = get_element_attribute(session, element.id, attr)
+        assert_success(result, "true")
+
+
+def test_global_boolean_attributes(session):
+    session.url = inline("<p hidden>foo")
+    element = session.find.css("p", all=False)
+    result = result = get_element_attribute(session, element.id, "hidden")
+
+    assert_success(result, "true")
+
+    session.url = inline("<p>foo")
+    element = session.find.css("p", all=False)
+    result = result = get_element_attribute(session, element.id, "hidden")
+    assert_success(result, None)
+
+    session.url = inline("<p itemscope>foo")
+    element = session.find.css("p", all=False)
+    result = result = get_element_attribute(session, element.id, "itemscope")
+
+    assert_success(result, "true")
+
+    session.url = inline("<p>foo")
+    element = session.find.css("p", all=False)
+    result = result = get_element_attribute(session, element.id, "itemscope")
+    assert_success(result, None)
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_element_property/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/get_element_property/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_element_property/get.py b/WebDriverTests/imported/w3c/webdriver/tests/get_element_property/get.py
new file mode 100644 (file)
index 0000000..f8df282
--- /dev/null
@@ -0,0 +1,55 @@
+from tests.support.asserts import assert_error, assert_success
+from tests.support.inline import inline
+
+_input = inline("<input id=i1>")
+
+
+def get_element_property(session, element_id, prop):
+    return session.transport.send(
+        "GET", "session/{session_id}/element/{element_id}/property/{prop}".format(
+            session_id=session.session_id,
+            element_id=element_id,
+            prop=prop))
+
+
+def test_no_browsing_context(session, create_window):
+    session.window_handle = create_window()
+    session.close()
+
+    result = get_element_property(session, "foo", "id")
+    assert_error(result, "no such window")
+
+
+def test_element_not_found(session):
+    # 13.3 Step 3
+    result = get_element_property(session, "foo", "id")
+    assert_error(result, "no such element")
+
+
+def test_element_stale(session):
+    session.url = _input
+    element = session.find.css("input", all=False)
+    session.refresh()
+
+    result = get_element_property(session, element.id, "id")
+    assert_error(result, "stale element reference")
+
+
+def test_property_non_existent(session):
+    session.url = _input
+    element = session.find.css("input", all=False)
+
+    result = get_element_property(session, element.id, "foo")
+    assert_success(result, None)
+
+    assert session.execute_script("return arguments[0].foo", args=[element]) is None
+
+
+def test_element(session):
+    session.url = inline("<input type=checkbox>")
+    element = session.find.css("input", all=False)
+    element.click()
+    assert session.execute_script("return arguments[0].hasAttribute('checked')", args=(element,)) is False
+
+    result = get_element_property(session, element.id, "checked")
+    assert_success(result, True)
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_element_property/user_prompts.py b/WebDriverTests/imported/w3c/webdriver/tests/get_element_property/user_prompts.py
new file mode 100644 (file)
index 0000000..8d46d02
--- /dev/null
@@ -0,0 +1,87 @@
+from tests.support.asserts import assert_error, assert_success, assert_dialog_handled
+from tests.support.fixtures import create_dialog
+from tests.support.inline import inline
+
+
+def read_global(session, name):
+    return session.execute_script("return %s;" % name)
+
+
+def get_property(session, element_id, name):
+    return session.transport.send(
+        "GET", "session/{session_id}/element/{element_id}/property/{name}".format(
+            session_id=session.session_id, element_id=element_id, name=name))
+
+
+def test_handle_prompt_dismiss(new_session, add_browser_capabilites):
+    # 13.3 step 2
+    _, session = new_session({"capabilities": {
+        "alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "dismiss"})}})
+    session.url = inline("<input id=foo>")
+    element = session.find.css("#foo", all=False)
+
+    create_dialog(session)("alert", text="dismiss #1", result_var="dismiss1")
+
+    result = get_property(session, element.id, "id")
+    assert_success(result, "foo")
+    assert_dialog_handled(session, "dismiss #1")
+
+    create_dialog(session)("confirm", text="dismiss #2", result_var="dismiss2")
+
+    result = get_property(session, element.id, "id")
+    assert_success(result, "foo")
+    assert_dialog_handled(session, "dismiss #2")
+
+    create_dialog(session)("prompt", text="dismiss #3", result_var="dismiss3")
+
+    result = get_property(session, element.id, "id")
+    assert_success(result, "foo")
+    assert_dialog_handled(session, "dismiss #3")
+
+
+def test_handle_prompt_accept(new_session, add_browser_capabilites):
+    _, session = new_session({"capabilities": {
+        "alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "accept"})}})
+    session.url = inline("<input id=foo>")
+    element = session.find.css("#foo", all=False)
+
+    create_dialog(session)("alert", text="dismiss #1", result_var="dismiss1")
+
+    result = get_property(session, element.id, "id")
+    assert_success(result, "foo")
+    assert_dialog_handled(session, "dismiss #1")
+
+    create_dialog(session)("confirm", text="dismiss #2", result_var="dismiss2")
+
+    result = get_property(session, element.id, "id")
+    assert_success(result, "foo")
+    assert_dialog_handled(session, "dismiss #2")
+
+    create_dialog(session)("prompt", text="dismiss #3", result_var="dismiss3")
+
+    result = get_property(session, element.id, "id")
+    assert_success(result, "foo")
+    assert_dialog_handled(session, "dismiss #3")
+
+
+def test_handle_prompt_missing_value(session):
+    session.url = inline("<input id=foo>")
+    element = session.find.css("#foo", all=False)
+
+    create_dialog(session)("alert", text="dismiss #1", result_var="dismiss1")
+
+    result = get_property(session, element.id, "id")
+    assert_error(result, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #1")
+
+    create_dialog(session)("confirm", text="dismiss #2", result_var="dismiss2")
+
+    result = get_property(session, element.id, "id")
+    assert_error(result, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #2")
+
+    create_dialog(session)("prompt", text="dismiss #3", result_var="dismiss3")
+
+    result = get_property(session, element.id, "id")
+    assert_error(result, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #3")
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_element_tag_name/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/get_element_tag_name/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_element_tag_name/get.py b/WebDriverTests/imported/w3c/webdriver/tests/get_element_tag_name/get.py
new file mode 100644 (file)
index 0000000..2b1663f
--- /dev/null
@@ -0,0 +1,43 @@
+from tests.support.asserts import assert_error, assert_success
+from tests.support.inline import inline
+
+
+def get_element_tag_name(session, element_id):
+    return session.transport.send(
+        "GET", "session/{session_id}/element/{element_id}/name".format(
+            session_id=session.session_id,
+            element_id=element_id))
+
+
+def test_no_browsing_context(session, create_window):
+    # 13.6 step 1
+    session.window_handle = create_window()
+    session.close()
+
+    result = get_element_tag_name(session, "foo")
+    assert_error(result, "no such window")
+
+
+def test_element_not_found(session):
+    # 13.6 Step 3
+    result = get_element_tag_name(session, "foo")
+    assert_error(result, "no such element")
+
+
+def test_element_stale(session):
+    # 13.6 step 4
+    session.url = inline("<input id=foo>")
+    element = session.find.css("input", all=False)
+    session.refresh()
+
+    result = get_element_tag_name(session, element.id)
+    assert_error(result, "stale element reference")
+
+
+def test_get_element_tag_name(session):
+    # 13.6 step 6
+    session.url = inline("<input id=foo>")
+    element = session.find.css("input", all=False)
+
+    result = get_element_tag_name(session, element.id)
+    assert_success(result, "input")
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_element_tag_name/user_prompts.py b/WebDriverTests/imported/w3c/webdriver/tests/get_element_tag_name/user_prompts.py
new file mode 100644 (file)
index 0000000..994a542
--- /dev/null
@@ -0,0 +1,85 @@
+from tests.support.asserts import assert_error, assert_success, assert_dialog_handled
+from tests.support.fixtures import create_dialog
+from tests.support.inline import inline
+
+
+def read_global(session, name):
+    return session.execute_script("return %s;" % name)
+
+
+def get_tag_name(session, element_id):
+    return session.transport.send("GET", "session/{session_id}/element/{element_id}/name".format(
+        session_id=session.session_id, element_id="foo"))
+
+
+def test_handle_prompt_dismiss(new_session, add_browser_capabilites):
+    _, session = new_session({"capabilities": {
+        "alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "dismiss"})}})
+    session.url = inline("<input id=foo>")
+    element = session.find.css("#foo", all=False)
+
+    create_dialog(session)("alert", text="dismiss #1", result_var="dismiss1")
+
+    result = get_tag_name(session, element.id)
+    assert_success(result, "input")
+    assert_dialog_handled(session, "dismiss #1")
+
+    create_dialog(session)("confirm", text="dismiss #2", result_var="dismiss2")
+
+    result = get_tag_name(session, element.id)
+    assert_success(result, "input")
+    assert_dialog_handled(session, "dismiss #2")
+
+    create_dialog(session)("prompt", text="dismiss #3", result_var="dismiss3")
+
+    result = get_tag_name(session, element.id)
+    assert_success(result, "input")
+    assert_dialog_handled(session, "dismiss #3")
+
+
+def test_handle_prompt_accept(new_session, add_browser_capabilites):
+    _, session = new_session({"capabilities": {
+        "alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "accept"})}})
+    session.url = inline("<input id=foo>")
+    element = session.find.css("#foo", all=False)
+
+    create_dialog(session)("alert", text="dismiss #1", result_var="dismiss1")
+
+    result = get_tag_name(session, element.id)
+    assert_success(result, "input")
+    assert_dialog_handled(session, "dismiss #1")
+
+    create_dialog(session)("confirm", text="dismiss #2", result_var="dismiss2")
+
+    result = get_tag_name(session, element.id)
+    assert_success(result, "input")
+    assert_dialog_handled(session, "dismiss #2")
+
+    create_dialog(session)("prompt", text="dismiss #3", result_var="dismiss3")
+
+    result = get_tag_name(session, element.id)
+    assert_success(result, "input")
+    assert_dialog_handled(session, "dismiss #3")
+
+
+def test_handle_prompt_missing_value(session):
+    session.url = inline("<input id=foo>")
+    element = session.find.css("#foo", all=False)
+
+    create_dialog(session)("alert", text="dismiss #1", result_var="dismiss1")
+
+    result = get_tag_name(session, element.id)
+    assert_error(result, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #1")
+
+    create_dialog(session)("confirm", text="dismiss #2", result_var="dismiss2")
+
+    result = get_tag_name(session, element.id)
+    assert_error(result, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #2")
+
+    create_dialog(session)("prompt", text="dismiss #3", result_var="dismiss3")
+
+    result = get_tag_name(session, element.id)
+    assert_error(result, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #3")
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_element_text/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/get_element_text/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_element_text/get.py b/WebDriverTests/imported/w3c/webdriver/tests/get_element_text/get.py
new file mode 100644 (file)
index 0000000..4d1eb18
--- /dev/null
@@ -0,0 +1,33 @@
+import pytest
+
+from tests.support.asserts import assert_error, assert_success
+from tests.support.inline import inline
+
+# For failing tests, the Get Element Text end-point is used
+# directly. In all other cases, the Element.text() function is used.
+
+
+def get_element_text(session, element_id):
+    return session.transport.send(
+        "GET", "session/{session_id}/element/{element_id}/text".format(
+            session_id=session.session_id,
+            element_id=element_id))
+
+
+def test_getting_text_of_a_non_existant_element_is_an_error(session):
+    session.url = inline("""<body>Hello world</body>""")
+
+    result = get_element_text(session, "foo")
+    assert_error(result, "no such element")
+
+
+def test_read_element_text(session):
+    session.url = inline("""
+        <body>
+          Noise before <span id='id'>This has an ID</span>. Noise after
+        </body>""")
+
+    element = session.find.css("#id", all=False)
+
+    result = get_element_text(session, element.id)
+    assert_success(result, "This has an ID")
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_named_cookie/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/get_named_cookie/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_named_cookie/get.py b/WebDriverTests/imported/w3c/webdriver/tests/get_named_cookie/get.py
new file mode 100644 (file)
index 0000000..cbf7195
--- /dev/null
@@ -0,0 +1,103 @@
+from datetime import datetime, timedelta
+
+from tests.support.asserts import assert_success
+from tests.support.fixtures import clear_all_cookies
+from tests.support.inline import inline
+
+
+def get_named_cookie(session, name):
+    return session.transport.send(
+        "GET", "session/{session_id}/cookie/{name}".format(
+            session_id=session.session_id,
+            name=name))
+
+
+def test_get_named_session_cookie(session, url):
+    session.url = url("/common/blank.html")
+    clear_all_cookies(session)
+    session.execute_script("document.cookie = 'foo=bar'")
+
+    result = get_named_cookie(session, "foo")
+    cookie = assert_success(result)
+    assert isinstance(cookie, dict)
+
+    # table for cookie conversion
+    # https://w3c.github.io/webdriver/webdriver-spec.html#dfn-table-for-cookie-conversion
+    assert "name" in cookie
+    assert isinstance(cookie["name"], basestring)
+    assert "value" in cookie
+    assert isinstance(cookie["value"], basestring)
+    assert "path" in cookie
+    assert isinstance(cookie["path"], basestring)
+    assert "domain" in cookie
+    assert isinstance(cookie["domain"], basestring)
+    assert "secure" in cookie
+    assert isinstance(cookie["secure"], bool)
+    assert "httpOnly" in cookie
+    assert isinstance(cookie["httpOnly"], bool)
+    if "expiry" in cookie:
+        assert cookie.get("expiry") is None
+
+    assert cookie["name"] == "foo"
+    assert cookie["value"] == "bar"
+
+
+def test_get_named_cookie(session, url):
+    session.url = url("/common/blank.html")
+    clear_all_cookies(session)
+
+    # same formatting as Date.toUTCString() in javascript
+    utc_string_format = "%a, %d %b %Y %H:%M:%S"
+    a_year_from_now = (datetime.utcnow() + timedelta(days=365)).strftime(utc_string_format)
+    session.execute_script("document.cookie = 'foo=bar;expires=%s'" % a_year_from_now)
+
+    result = get_named_cookie(session, "foo")
+    cookie = assert_success(result)
+    assert isinstance(cookie, dict)
+
+    assert "name" in cookie
+    assert isinstance(cookie["name"], basestring)
+    assert "value" in cookie
+    assert isinstance(cookie["value"], basestring)
+    assert "expiry" in cookie
+    assert isinstance(cookie["expiry"], (int, long))
+
+    assert cookie["name"] == "foo"
+    assert cookie["value"] == "bar"
+    # convert from seconds since epoch
+    assert datetime.utcfromtimestamp(
+        cookie["expiry"]).strftime(utc_string_format) == a_year_from_now
+
+
+def test_duplicated_cookie(session, url, server_config):
+    new_cookie = {
+        "name": "hello",
+        "value": "world",
+        "domain": server_config["browser_host"],
+        "path": "/",
+        "http_only": False,
+        "secure": False
+    }
+
+    session.url = url("/common/blank.html")
+    clear_all_cookies(session)
+
+    session.set_cookie(**new_cookie)
+    session.url = inline("""
+      <script>
+        document.cookie = '{name}=newworld; domain={domain}; path=/';
+      </script>""".format(
+        name=new_cookie["name"],
+        domain=server_config["browser_host"]))
+
+    result = get_named_cookie(session, new_cookie["name"])
+    cookie = assert_success(result)
+    assert isinstance(cookie, dict)
+
+    assert "name" in cookie
+    assert isinstance(cookie["name"], basestring)
+    assert "value" in cookie
+    assert isinstance(cookie["value"], basestring)
+
+    assert cookie["name"] == new_cookie["name"]
+    assert cookie["value"] == "newworld"
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_timeouts/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/get_timeouts/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_timeouts/get.py b/WebDriverTests/imported/w3c/webdriver/tests/get_timeouts/get.py
new file mode 100644 (file)
index 0000000..17f8dfd
--- /dev/null
@@ -0,0 +1,44 @@
+from tests.support.asserts import assert_success
+
+
+def get_timeouts(session):
+    return session.transport.send(
+        "GET", "session/{session_id}/timeouts".format(**vars(session)))
+
+
+def test_get_timeouts(session):
+    # 8.4 step 1
+    response = get_timeouts(session)
+
+    assert_success(response)
+    assert "value" in response.body
+    assert isinstance(response.body["value"], dict)
+
+    value = response.body["value"]
+    assert "script" in value
+    assert "implicit" in value
+    assert "pageLoad" in value
+
+    assert isinstance(value["script"], int)
+    assert isinstance(value["implicit"], int)
+    assert isinstance(value["pageLoad"], int)
+
+
+def test_get_default_timeouts(session):
+    response = get_timeouts(session)
+
+    assert_success(response)
+    assert response.body["value"]["script"] == 30000
+    assert response.body["value"]["implicit"] == 0
+    assert response.body["value"]["pageLoad"] == 300000
+
+
+def test_get_new_timeouts(session):
+    session.timeouts.script = 60
+    session.timeouts.implicit = 1
+    session.timeouts.page_load = 200
+    response = get_timeouts(session)
+    assert_success(response)
+    assert response.body["value"]["script"] == 60000
+    assert response.body["value"]["implicit"] == 1000
+    assert response.body["value"]["pageLoad"] == 200000
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_title/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/get_title/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_title/get.py b/WebDriverTests/imported/w3c/webdriver/tests/get_title/get.py
new file mode 100644 (file)
index 0000000..3b1673c
--- /dev/null
@@ -0,0 +1,69 @@
+from tests.support.asserts import assert_error, assert_success
+from tests.support.inline import inline
+from tests.support.wait import wait
+
+
+def read_global(session, name):
+    return session.execute_script("return %s;" % name)
+
+
+def get_title(session):
+    return session.transport.send(
+        "GET", "session/{session_id}/title".format(**vars(session)))
+
+
+def test_no_browsing_context(session, create_window):
+    new_window = create_window()
+    session.window_handle = new_window
+    session.close()
+
+    result = get_title(session)
+    assert_error(result, "no such window")
+
+
+def test_title_from_top_context(session):
+    session.url = inline("<title>Foobar</title><h2>Hello</h2>")
+
+    result = get_title(session)
+    assert_success(result, read_global(session, "document.title"))
+
+
+def test_title_with_duplicate_element(session):
+    session.url = inline("<title>First</title><title>Second</title>")
+
+    result = get_title(session)
+    assert_success(result, read_global(session, "document.title"))
+
+
+def test_title_without_element(session):
+    session.url = inline("<h2>Hello</h2>")
+
+    result = get_title(session)
+    assert_success(result, read_global(session, "document.title"))
+
+
+def test_title_after_modification(session):
+    session.url = inline("<title>Initial</title><h2>Hello</h2>")
+    session.execute_script("document.title = 'Updated'")
+
+    wait(session,
+         lambda s: assert_success(get_title(s)) == read_global(session, "document.title"),
+         "Document title doesn't match '{}'".format(read_global(session, "document.title")))
+
+
+def test_title_strip_and_collapse(session):
+    document = "<title>   a b\tc\nd\t \n e\t\n </title><h2>Hello</h2>"
+    session.url = inline(document)
+
+    result = get_title(session)
+    assert_success(result, read_global(session, "document.title"))
+
+
+def test_title_from_frame(session, create_frame):
+    session.url = inline("<title>Parent</title>parent")
+
+    session.switch_frame(create_frame())
+    session.switch_frame(create_frame())
+
+    result = get_title(session)
+    assert_success(result, "Parent")
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_title/user_prompts.py b/WebDriverTests/imported/w3c/webdriver/tests/get_title/user_prompts.py
new file mode 100644 (file)
index 0000000..39afeb5
--- /dev/null
@@ -0,0 +1,118 @@
+from tests.support.asserts import assert_error, assert_success, assert_dialog_handled
+from tests.support.fixtures import create_dialog
+from tests.support.inline import inline
+
+
+def read_global(session, name):
+    return session.execute_script("return %s;" % name)
+
+
+def get_title(session):
+    return session.transport.send(
+        "GET", "session/{session_id}/title".format(**vars(session)))
+
+
+def test_title_handle_prompt_dismiss(new_session, add_browser_capabilites):
+    _, session = new_session({"capabilities": {
+        "alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "dismiss"})}})
+    session.url = inline("<title>WD doc title</title>")
+
+    expected_title = read_global(session, "document.title")
+    create_dialog(session)("alert", text="dismiss #1", result_var="dismiss1")
+
+    result = get_title(session)
+    assert_success(result, expected_title)
+    assert_dialog_handled(session, "dismiss #1")
+    assert read_global(session, "dismiss1") is None
+
+    expected_title = read_global(session, "document.title")
+    create_dialog(session)("confirm", text="dismiss #2", result_var="dismiss2")
+
+    result = get_title(session)
+    assert_success(result, expected_title)
+    assert_dialog_handled(session, "dismiss #2")
+    assert read_global(session, "dismiss2") is False
+
+    expected_title = read_global(session, "document.title")
+    create_dialog(session)("prompt", text="dismiss #3", result_var="dismiss3")
+
+    result = get_title(session)
+    assert_success(result, expected_title)
+    assert_dialog_handled(session, "dismiss #3")
+    assert read_global(session, "dismiss3") is None
+
+
+def test_title_handle_prompt_accept(new_session, add_browser_capabilites):
+    _, session = new_session({"capabilities": {
+        "alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "accept"})}})
+    session.url = inline("<title>WD doc title</title>")
+    create_dialog(session)("alert", text="accept #1", result_var="accept1")
+
+    expected_title = read_global(session, "document.title")
+
+    result = get_title(session)
+    assert_success(result, expected_title)
+    assert_dialog_handled(session, "accept #1")
+    assert read_global(session, "accept1") is None
+
+    expected_title = read_global(session, "document.title")
+    create_dialog(session)("confirm", text="accept #2", result_var="accept2")
+
+    result = get_title(session)
+    assert_success(result, expected_title)
+    assert_dialog_handled(session, "accept #2")
+    assert read_global(session, "accept2") is True
+
+    expected_title = read_global(session, "document.title")
+    create_dialog(session)("prompt", text="accept #3", result_var="accept3")
+
+    result = get_title(session)
+    assert_success(result, expected_title)
+    assert_dialog_handled(session, "accept #3")
+    assert read_global(session, "accept3") == "" or read_global(session, "accept3") == "undefined"
+
+
+def test_title_handle_prompt_missing_value(session, create_dialog):
+    session.url = inline("<title>WD doc title</title>")
+    create_dialog("alert", text="dismiss #1", result_var="dismiss1")
+
+    result = get_title(session)
+    assert_error(result, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #1")
+    assert read_global(session, "dismiss1") is None
+
+    create_dialog("confirm", text="dismiss #2", result_var="dismiss2")
+
+    result = get_title(session)
+    assert_error(result, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #2")
+    assert read_global(session, "dismiss2") is False
+
+    create_dialog("prompt", text="dismiss #3", result_var="dismiss3")
+
+    result = get_title(session)
+    assert_error(result, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #3")
+    assert read_global(session, "dismiss3") is None
+
+
+# The behavior of the `window.print` function is platform-dependent and may not
+# trigger the creation of a dialog at all. Therefore, this test should only be
+# run in contexts that support the dialog (a condition that may not be
+# determined automatically).
+# def test_title_with_non_simple_dialog(session):
+#    document = "<title>With non-simple dialog</title><h2>Hello</h2>"
+#    spawn = """
+#        var done = arguments[0];
+#        setTimeout(function() {
+#            done();
+#        }, 0);
+#        setTimeout(function() {
+#            window['print']();
+#        }, 0);
+#    """
+#    session.url = inline(document)
+#    session.execute_async_script(spawn)
+#
+#    result = get_title(session)
+#    assert_error(result, "unexpected alert open")
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_window_rect/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/get_window_rect/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_window_rect/get.py b/WebDriverTests/imported/w3c/webdriver/tests/get_window_rect/get.py
new file mode 100644 (file)
index 0000000..ae493b7
--- /dev/null
@@ -0,0 +1,64 @@
+from tests.support.asserts import assert_error
+from tests.support.inline import inline
+
+
+alert_doc = inline("<script>window.alert()</script>")
+
+
+def get_window_rect(session):
+    return session.transport.send(
+        "GET", "session/{session_id}/window/rect".format(**vars(session)))
+
+
+def test_no_browsing_context(session, create_window):
+    """
+    1. If the current top-level browsing context is no longer open,
+    return error with error code no such window.
+
+    """
+    session.window_handle = create_window()
+    session.close()
+    response = get_window_rect(session)
+    assert_error(response, "no such window")
+
+
+def test_payload(session):
+    """
+    3. Return success with the JSON serialization of the current top-level
+    browsing context's window rect.
+
+    [...]
+
+    A top-level browsing context's window rect is defined as a
+    dictionary of the screenX, screenY, width and height attributes of
+    the WindowProxy. Its JSON representation is the following:
+
+    "x"
+        WindowProxy's screenX attribute.
+
+    "y"
+        WindowProxy's screenY attribute.
+
+    "width"
+        Width of the top-level browsing context's outer dimensions,
+        including any browser chrome and externally drawn window
+        decorations in CSS reference pixels.
+
+    "height"
+        Height of the top-level browsing context's outer dimensions,
+        including any browser chrome and externally drawn window
+        decorations in CSS reference pixels.
+
+    """
+    response = get_window_rect(session)
+
+    assert response.status == 200
+    assert isinstance(response.body["value"], dict)
+    value = response.body["value"]
+    expected = session.execute_script("""return {
+         x: window.screenX,
+         y: window.screenY,
+         width: window.outerWidth,
+         height: window.outerHeight
+    }""")
+    assert expected == value
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/get_window_rect/user_prompts.py b/WebDriverTests/imported/w3c/webdriver/tests/get_window_rect/user_prompts.py
new file mode 100644 (file)
index 0000000..f2e8ddd
--- /dev/null
@@ -0,0 +1,65 @@
+from tests.support.asserts import assert_error, assert_dialog_handled
+from tests.support.fixtures import create_dialog
+from tests.support.inline import inline
+
+
+alert_doc = inline("<script>window.alert()</script>")
+
+
+def get_window_rect(session):
+    return session.transport.send(
+        "GET", "session/{session_id}/window/rect".format(**vars(session)))
+
+
+def test_handle_prompt_dismiss_and_notify():
+    """TODO"""
+
+
+def test_handle_prompt_accept_and_notify():
+    """TODO"""
+
+
+def test_handle_prompt_ignore():
+    """TODO"""
+
+
+def test_handle_prompt_accept(new_session, add_browser_capabilites):
+    _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "accept"})}})
+    session.url = inline("<title>WD doc title</title>")
+
+    create_dialog(session)("alert", text="dismiss #1", result_var="dismiss1")
+    response = get_window_rect(session)
+    assert response.status == 200
+    assert_dialog_handled(session, "dismiss #1")
+
+    create_dialog(session)("confirm", text="dismiss #2", result_var="dismiss2")
+    response = get_window_rect(session)
+    assert response.status == 200
+    assert_dialog_handled(session, "dismiss #2")
+
+    create_dialog(session)("prompt", text="dismiss #3", result_var="dismiss3")
+    response = get_window_rect(session)
+    assert response.status == 200
+    assert_dialog_handled(session, "dismiss #3")
+
+
+def test_handle_prompt_missing_value(session, create_dialog):
+    session.url = inline("<title>WD doc title</title>")
+    create_dialog("alert", text="dismiss #1", result_var="dismiss1")
+
+    response = get_window_rect(session)
+
+    assert_error(response, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #1")
+
+    create_dialog("confirm", text="dismiss #2", result_var="dismiss2")
+
+    response = get_window_rect(session)
+    assert_error(response, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #2")
+
+    create_dialog("prompt", text="dismiss #3", result_var="dismiss3")
+
+    response = get_window_rect(session)
+    assert_error(response, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #3")
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/is_element_selected/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/is_element_selected/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/is_element_selected/selected.py b/WebDriverTests/imported/w3c/webdriver/tests/is_element_selected/selected.py
new file mode 100644 (file)
index 0000000..16939b5
--- /dev/null
@@ -0,0 +1,72 @@
+from tests.support.asserts import assert_error, assert_success
+from tests.support.inline import inline
+
+
+check_doc = inline("<input id=checked type=checkbox checked/><input id=notChecked type=checkbox/>")
+option_doc = inline("""<select>
+                        <option id=notSelected>r-</option>
+                        <option id=selected selected>r+</option>
+                       </select>
+                    """)
+
+
+def is_element_selected(session, element_id):
+    return session.transport.send(
+        "GET", "session/{session_id}/element/{element_id}/selected".format(
+            session_id=session.session_id,
+            element_id=element_id))
+
+
+def test_no_browsing_context(session, create_window):
+    # 13.1 step 1
+    session.window_handle = create_window()
+    session.close()
+
+    result = is_element_selected(session, "foo")
+    assert_error(result, "no such window")
+
+
+def test_element_stale(session):
+    # 13.1 step 4
+    session.url = check_doc
+    element = session.find.css("#checked", all=False)
+    session.refresh()
+
+    result = is_element_selected(session, element.id)
+    assert_error(result, "stale element reference")
+
+
+def test_element_checked(session):
+    # 13.1 step 5
+    session.url = check_doc
+    element = session.find.css("#checked", all=False)
+
+    result = is_element_selected(session, element.id)
+    assert_success(result, True)
+
+
+def test_checkbox_not_selected(session):
+    # 13.1 step 5
+    session.url = check_doc
+    element = session.find.css("#notChecked", all=False)
+
+    result = is_element_selected(session, element.id)
+    assert_success(result, False)
+
+
+def test_element_selected(session):
+    # 13.1 step 5
+    session.url = option_doc
+    element = session.find.css("#selected", all=False)
+
+    result = is_element_selected(session, element.id)
+    assert_success(result, True)
+
+
+def test_element_not_selected(session):
+    # 13.1 step 5
+    session.url = option_doc
+    element = session.find.css("#notSelected", all=False)
+
+    result = is_element_selected(session, element.id)
+    assert_success(result, False)
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/is_element_selected/user_prompts.py b/WebDriverTests/imported/w3c/webdriver/tests/is_element_selected/user_prompts.py
new file mode 100644 (file)
index 0000000..b1a181a
--- /dev/null
@@ -0,0 +1,84 @@
+from tests.support.asserts import assert_error, assert_dialog_handled, assert_success
+from tests.support.inline import inline
+from tests.support.fixtures import create_dialog
+
+
+def is_element_selected(session, element_id):
+    return session.transport.send(
+        "GET", "session/{session_id}/element/{element_id}/selected".format(
+            session_id=session.session_id,
+            element_id=element_id))
+
+
+def test_handle_prompt_dismiss(new_session, add_browser_capabilites):
+    # 13.1 step 2
+    _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "dismiss"})}})
+    session.url = inline("<input id=foo>")
+    element = session.find.css("#foo", all=False)
+
+    create_dialog(session)("alert", text="dismiss #1", result_var="dismiss1")
+
+    result = is_element_selected(session, element.id)
+    assert_success(result, False)
+    assert_dialog_handled(session, "dismiss #1")
+
+    create_dialog(session)("confirm", text="dismiss #2", result_var="dismiss2")
+
+    result = is_element_selected(session, element.id)
+    assert_success(result, False)
+    assert_dialog_handled(session, "dismiss #2")
+
+    create_dialog(session)("prompt", text="dismiss #3", result_var="dismiss3")
+
+    result = is_element_selected(session, element.id)
+    assert_success(result, False)
+    assert_dialog_handled(session, "dismiss #3")
+
+
+def test_handle_prompt_accept(new_session, add_browser_capabilites):
+    # 13.1 step 2
+    _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "accept"})}})
+    session.url = inline("<input id=foo>")
+    element = session.find.css("#foo", all=False)
+
+    create_dialog(session)("alert", text="dismiss #1", result_var="dismiss1")
+
+    result = is_element_selected(session, element.id)
+    assert_success(result, False)
+    assert_dialog_handled(session, "dismiss #1")
+
+    create_dialog(session)("confirm", text="dismiss #2", result_var="dismiss2")
+
+    result = is_element_selected(session, element.id)
+    assert_success(result, False)
+    assert_dialog_handled(session, "dismiss #2")
+
+    create_dialog(session)("prompt", text="dismiss #3", result_var="dismiss3")
+
+    result = is_element_selected(session, element.id)
+    assert_success(result, False)
+    assert_dialog_handled(session, "dismiss #3")
+
+
+def test_handle_prompt_missing_value(session):
+    # 13.1 step 2
+    session.url = inline("<input id=foo>")
+    element = session.find.css("#foo", all=False)
+
+    create_dialog(session)("alert", text="dismiss #1", result_var="dismiss1")
+
+    result = is_element_selected(session, element.id)
+    assert_error(result, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #1")
+
+    create_dialog(session)("confirm", text="dismiss #2", result_var="dismiss2")
+
+    result = is_element_selected(session, element.id)
+    assert_error(result, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #2")
+
+    create_dialog(session)("prompt", text="dismiss #3", result_var="dismiss3")
+
+    result = is_element_selected(session, element.id)
+    assert_error(result, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #3")
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/maximize_window/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/maximize_window/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/maximize_window/maximize.py b/WebDriverTests/imported/w3c/webdriver/tests/maximize_window/maximize.py
new file mode 100644 (file)
index 0000000..00d6bc9
--- /dev/null
@@ -0,0 +1,185 @@
+from tests.support.asserts import assert_error, assert_success
+from tests.support.inline import inline
+
+
+def maximize(session):
+    return session.transport.send(
+        "POST", "session/{session_id}/window/maximize".format(**vars(session)))
+
+
+def is_fullscreen(session):
+    # At the time of writing, WebKit does not conform to the Fullscreen API specification.
+    # Remove the prefixed fallback when https://bugs.webkit.org/show_bug.cgi?id=158125 is fixed.
+    return session.execute_script("return !!(window.fullScreen || document.webkitIsFullScreen)")
+
+
+# 10.7.3 Maximize Window
+
+
+def test_no_browsing_context(session, create_window):
+    """
+    2. If the current top-level browsing context is no longer open,
+    return error with error code no such window.
+
+    """
+    session.window_handle = create_window()
+    session.close()
+    response = maximize(session)
+    assert_error(response, "no such window")
+
+
+def test_fully_exit_fullscreen(session):
+    """
+    4. Fully exit fullscreen.
+
+    [...]
+
+    To fully exit fullscreen a document document, run these steps:
+
+      1. If document's fullscreen element is null, terminate these steps.
+
+      2. Unfullscreen elements whose fullscreen flag is set, within
+      document's top layer, except for document's fullscreen element.
+
+      3. Exit fullscreen document.
+
+    """
+    session.window.fullscreen()
+    assert is_fullscreen(session) is True
+
+    response = maximize(session)
+    assert_success(response)
+    assert is_fullscreen(session) is False
+
+
+def test_restore_the_window(session):
+    """
+    5. Restore the window.
+
+    [...]
+
+    To restore the window, given an operating system level window with
+    an associated top-level browsing context, run implementation-specific
+    steps to restore or unhide the window to the visible screen.  Do not
+    return from this operation until the visibility state of the top-level
+    browsing context's active document has reached the visible state,
+    or until the operation times out.
+
+    """
+    session.window.minimize()
+    assert session.execute_script("return document.hidden") is True
+
+    response = maximize(session)
+    assert_success(response)
+
+
+def test_maximize(session):
+    """
+    6. Maximize the window of the current browsing context.
+
+    [...]
+
+    To maximize the window, given an operating system level window with an
+    associated top-level browsing context, run the implementation-specific
+    steps to transition the operating system level window into the
+    maximized window state.  If the window manager supports window
+    resizing but does not have a concept of window maximation, the window
+    dimensions must be increased to the maximum available size permitted
+    by the window manager for the current screen.  Return when the window
+    has completed the transition, or within an implementation-defined
+    timeout.
+
+    """
+    before_size = session.window.size
+
+    response = maximize(session)
+    assert_success(response)
+
+    assert before_size != session.window.size
+
+
+def test_payload(session):
+    """
+    7. Return success with the JSON serialization of the current top-level
+    browsing context's window rect.
+
+    [...]
+
+    A top-level browsing context's window rect is defined as a
+    dictionary of the screenX, screenY, width and height attributes of
+    the WindowProxy. Its JSON representation is the following:
+
+    "x"
+        WindowProxy's screenX attribute.
+
+    "y"
+        WindowProxy's screenY attribute.
+
+    "width"
+        Width of the top-level browsing context's outer dimensions,
+        including any browser chrome and externally drawn window
+        decorations in CSS reference pixels.
+
+    "height"
+        Height of the top-level browsing context's outer dimensions,
+        including any browser chrome and externally drawn window
+        decorations in CSS reference pixels.
+
+    """
+    before_size = session.window.size
+
+    response = maximize(session)
+
+    # step 5
+    assert response.status == 200
+    assert isinstance(response.body["value"], dict)
+
+    value = response.body["value"]
+    assert "width" in value
+    assert "height" in value
+    assert "x" in value
+    assert "y" in value
+    assert isinstance(value["width"], int)
+    assert isinstance(value["height"], int)
+    assert isinstance(value["x"], int)
+    assert isinstance(value["y"], int)
+
+    assert before_size != session.window.size
+
+
+def test_maximize_twice_is_idempotent(session):
+    first_response = maximize(session)
+    assert_success(first_response)
+    max_size = session.window.size
+
+    second_response = maximize(session)
+    assert_success(second_response)
+    assert session.window.size == max_size
+
+
+"""
+TODO(ato): Implicit session start does not use configuration passed on
+from wptrunner.  This causes an exception.
+
+See https://bugzil.la/1398459.
+
+def test_maximize_when_resized_to_max_size(session):
+    # Determine the largest available window size by first maximising
+    # the window and getting the window rect dimensions.
+    #
+    # Then resize the window to the maximum available size.
+    session.end()
+    available = session.window.maximize()
+    session.end()
+
+    session.window.size = available
+
+    # In certain window managers a window extending to the full available
+    # dimensions of the screen may not imply that the window is maximised,
+    # since this is often a special state.  If a remote end expects a DOM
+    # resize event, this may not fire if the window has already reached
+    # its expected dimensions.
+    before = session.window.size
+    session.window.maximize()
+    assert session.window.size == before
+"""
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/maximize_window/user_prompts.py b/WebDriverTests/imported/w3c/webdriver/tests/maximize_window/user_prompts.py
new file mode 100644 (file)
index 0000000..41ef3be
--- /dev/null
@@ -0,0 +1,62 @@
+from tests.support.asserts import assert_error, assert_dialog_handled
+from tests.support.fixtures import create_dialog
+from tests.support.inline import inline
+
+
+def maximize(session):
+    return session.transport.send(
+        "POST", "session/{session_id}/window/maximize".format(**vars(session)))
+
+
+def test_handle_prompt_dismiss_and_notify():
+    """TODO"""
+
+
+def test_handle_prompt_accept_and_notify():
+    """TODO"""
+
+
+def test_handle_prompt_ignore():
+    """TODO"""
+
+
+def test_handle_prompt_accept(new_session, add_browser_capabilites):
+    _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "accept"})}})
+    session.url = inline("<title>WD doc title</title>")
+
+    create_dialog(session)("alert", text="dismiss #1", result_var="dismiss1")
+    response = maximize(session)
+    assert response.status == 200
+    assert_dialog_handled(session, "dismiss #1")
+
+    create_dialog(session)("confirm", text="dismiss #2", result_var="dismiss2")
+    response = maximize(session)
+    assert response.status == 200
+    assert_dialog_handled(session, "dismiss #2")
+
+    create_dialog(session)("prompt", text="dismiss #3", result_var="dismiss3")
+    response = maximize(session)
+    assert response.status == 200
+    assert_dialog_handled(session, "dismiss #3")
+
+
+def test_handle_prompt_missing_value(session, create_dialog):
+    session.url = inline("<title>WD doc title</title>")
+    create_dialog("alert", text="dismiss #1", result_var="dismiss1")
+
+    response = maximize(session)
+
+    assert_error(response, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #1")
+
+    create_dialog("confirm", text="dismiss #2", result_var="dismiss2")
+
+    response = maximize(session)
+    assert_error(response, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #2")
+
+    create_dialog("prompt", text="dismiss #3", result_var="dismiss3")
+
+    response = maximize(session)
+    assert_error(response, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #3")
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/minimize_window/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/minimize_window/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/minimize_window/minimize.py b/WebDriverTests/imported/w3c/webdriver/tests/minimize_window/minimize.py
new file mode 100644 (file)
index 0000000..b80b678
--- /dev/null
@@ -0,0 +1,134 @@
+from tests.support.asserts import assert_error, assert_success
+from tests.support.inline import inline
+
+
+def minimize(session):
+    return session.transport.send(
+        "POST", "session/{session_id}/window/minimize".format(**vars(session)))
+
+
+def is_fullscreen(session):
+    # At the time of writing, WebKit does not conform to the Fullscreen API specification.
+    # Remove the prefixed fallback when https://bugs.webkit.org/show_bug.cgi?id=158125 is fixed.
+    return session.execute_script("return !!(window.fullScreen || document.webkitIsFullScreen)")
+
+# 10.7.4 Minimize Window
+
+
+def test_no_browsing_context(session, create_window):
+    """
+    1. If the current top-level browsing context is no longer open,
+    return error with error code no such window.
+
+    """
+    session.window_handle = create_window()
+    session.close()
+    response = minimize(session)
+    assert_error(response, "no such window")
+
+
+def test_fully_exit_fullscreen(session):
+    """
+    4. Fully exit fullscreen.
+
+    [...]
+
+    To fully exit fullscreen a document document, run these steps:
+
+      1. If document's fullscreen element is null, terminate these steps.
+
+      2. Unfullscreen elements whose fullscreen flag is set, within
+      document's top layer, except for document's fullscreen element.
+
+      3. Exit fullscreen document.
+
+    """
+    session.window.fullscreen()
+    assert is_fullscreen(session) is True
+
+    response = minimize(session)
+    assert_success(response)
+    assert is_fullscreen(session) is False
+    assert session.execute_script("return document.hidden") is True
+
+
+def test_minimize(session):
+    """
+    5. Iconify the window.
+
+    [...]
+
+    To iconify the window, given an operating system level window with an
+    associated top-level browsing context, run implementation-specific
+    steps to iconify, minimize, or hide the window from the visible
+    screen. Do not return from this operation until the visibility state
+    of the top-level browsing context's active document has reached the
+    hidden state, or until the operation times out.
+
+    """
+    assert not session.execute_script("return document.hidden")
+
+    response = minimize(session)
+    assert_success(response)
+
+    assert session.execute_script("return document.hidden")
+
+
+def test_payload(session):
+    """
+    6. Return success with the JSON serialization of the current top-level
+    browsing context's window rect.
+
+    [...]
+
+    A top-level browsing context's window rect is defined as a
+    dictionary of the screenX, screenY, width and height attributes of
+    the WindowProxy. Its JSON representation is the following:
+
+    "x"
+        WindowProxy's screenX attribute.
+
+    "y"
+        WindowProxy's screenY attribute.
+
+    "width"
+        Width of the top-level browsing context's outer dimensions,
+        including any browser chrome and externally drawn window
+        decorations in CSS reference pixels.
+
+    "height"
+        Height of the top-level browsing context's outer dimensions,
+        including any browser chrome and externally drawn window
+        decorations in CSS reference pixels.
+
+    """
+    assert not session.execute_script("return document.hidden")
+
+    response = minimize(session)
+
+    assert response.status == 200
+    assert isinstance(response.body["value"], dict)
+
+    value = response.body["value"]
+    assert "width" in value
+    assert "height" in value
+    assert "x" in value
+    assert "y" in value
+    assert isinstance(value["width"], int)
+    assert isinstance(value["height"], int)
+    assert isinstance(value["x"], int)
+    assert isinstance(value["y"], int)
+
+    assert session.execute_script("return document.hidden")
+
+
+def test_minimize_twice_is_idempotent(session):
+    assert not session.execute_script("return document.hidden")
+
+    first_response = minimize(session)
+    assert_success(first_response)
+    assert session.execute_script("return document.hidden")
+
+    second_response = minimize(session)
+    assert_success(second_response)
+    assert session.execute_script("return document.hidden")
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/minimize_window/user_prompts.py b/WebDriverTests/imported/w3c/webdriver/tests/minimize_window/user_prompts.py
new file mode 100644 (file)
index 0000000..406862b
--- /dev/null
@@ -0,0 +1,62 @@
+from tests.support.asserts import assert_error, assert_dialog_handled
+from tests.support.fixtures import create_dialog
+from tests.support.inline import inline
+
+
+def minimize(session):
+    return session.transport.send(
+        "POST", "session/{session_id}/window/minimize".format(**vars(session)))
+
+
+def test_handle_prompt_dismiss_and_notify():
+    """TODO"""
+
+
+def test_handle_prompt_accept_and_notify():
+    """TODO"""
+
+
+def test_handle_prompt_ignore():
+    """TODO"""
+
+
+def test_handle_prompt_accept(new_session, add_browser_capabilites):
+    _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "accept"})}})
+    session.url = inline("<title>WD doc title</title>")
+
+    create_dialog(session)("alert", text="dismiss #1", result_var="dismiss1")
+    response = minimize(session)
+    assert response.status == 200
+    assert_dialog_handled(session, "dismiss #1")
+
+    create_dialog(session)("confirm", text="dismiss #2", result_var="dismiss2")
+    response = minimize(session)
+    assert response.status == 200
+    assert_dialog_handled(session, "dismiss #2")
+
+    create_dialog(session)("prompt", text="dismiss #3", result_var="dismiss3")
+    response = minimize(session)
+    assert response.status == 200
+    assert_dialog_handled(session, "dismiss #3")
+
+
+def test_handle_prompt_missing_value(session, create_dialog):
+    session.url = inline("<title>WD doc title</title>")
+    create_dialog("alert", text="dismiss #1", result_var="dismiss1")
+
+    response = minimize(session)
+
+    assert_error(response, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #1")
+
+    create_dialog("confirm", text="dismiss #2", result_var="dismiss2")
+
+    response = minimize(session)
+    assert_error(response, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #2")
+
+    create_dialog("prompt", text="dismiss #3", result_var="dismiss3")
+
+    response = minimize(session)
+    assert_error(response, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #3")
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/new_session/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/new_session/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/new_session/conftest.py b/WebDriverTests/imported/w3c/webdriver/tests/new_session/conftest.py
new file mode 100644 (file)
index 0000000..d3ee199
--- /dev/null
@@ -0,0 +1,22 @@
+import pytest
+import sys
+
+import webdriver
+
+
+def product(a, b):
+    return [(a, item) for item in b]
+
+
+def flatten(l):
+    return [item for x in l for item in x]
+
+@pytest.fixture(scope="session")
+def platform_name():
+    return {
+        "linux2": "linux",
+        "win32": "windows",
+        "cygwin": "windows",
+        "darwin": "mac"
+    }.get(sys.platform)
+
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/new_session/create_alwaysMatch.py b/WebDriverTests/imported/w3c/webdriver/tests/new_session/create_alwaysMatch.py
new file mode 100644 (file)
index 0000000..2335048
--- /dev/null
@@ -0,0 +1,13 @@
+#META: timeout=long
+
+import pytest
+
+from conftest import product, flatten
+
+from support.create import valid_data
+
+
+@pytest.mark.parametrize("key,value", flatten(product(*item) for item in valid_data))
+def test_valid(new_session, add_browser_capabilites, key, value):
+    resp = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({key: value})}})
+
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/new_session/create_firstMatch.py b/WebDriverTests/imported/w3c/webdriver/tests/new_session/create_firstMatch.py
new file mode 100644 (file)
index 0000000..58203e5
--- /dev/null
@@ -0,0 +1,12 @@
+#META: timeout=long
+
+import pytest
+
+from conftest import product, flatten
+
+from support.create import valid_data
+
+
+@pytest.mark.parametrize("key,value", flatten(product(*item) for item in valid_data))
+def test_valid(new_session, add_browser_capabilites, key, value):
+    resp = new_session({"capabilities": {"firstMatch": [add_browser_capabilites({key: value})]}})
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/new_session/default_values.py b/WebDriverTests/imported/w3c/webdriver/tests/new_session/default_values.py
new file mode 100644 (file)
index 0000000..0dbc798
--- /dev/null
@@ -0,0 +1,48 @@
+# META: timeout=long
+
+import uuid
+
+import pytest
+
+from webdriver import error
+
+
+def test_basic(new_session, add_browser_capabilites):
+    resp, _ = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({})}})
+    assert set(resp.keys()) == {"sessionId", "capabilities"}
+
+
+def test_repeat_new_session(new_session, add_browser_capabilites):
+    resp, _ = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({})}})
+    with pytest.raises(error.SessionNotCreatedException):
+        new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({})}})
+
+
+def test_no_capabilites(new_session):
+    with pytest.raises(error.InvalidArgumentException):
+        new_session({})
+
+
+def test_missing_first_match(new_session, add_browser_capabilites):
+    resp, _ = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({})}})
+
+
+def test_missing_always_match(new_session, add_browser_capabilites):
+    resp, _ = new_session({"capabilities": {"firstMatch": [add_browser_capabilites({})]}})
+
+
+def test_desired(new_session, add_browser_capabilites):
+    with pytest.raises(error.InvalidArgumentException):
+        resp, _ = new_session({"desiredCapbilities": add_browser_capabilites({})})
+
+
+def test_ignore_non_spec_fields_in_capabilities(new_session, add_browser_capabilites):
+    resp, _ = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({}), "desiredCapbilities": {"pageLoadStrategy": "eager"}}})
+    assert resp["capabilities"]["pageLoadStrategy"] == "normal"
+
+
+def test_valid_but_unmatchable_key(new_session, add_browser_capabilites):
+    resp, _ = new_session({"capabilities": {
+      "firstMatch": [add_browser_capabilites({"pageLoadStrategy": "eager", "foo:unmatchable": True}),
+                     {"pageLoadStrategy": "none"}]}})
+    assert resp["capabilities"]["pageLoadStrategy"] == "none"
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/new_session/invalid_capabilities.py b/WebDriverTests/imported/w3c/webdriver/tests/new_session/invalid_capabilities.py
new file mode 100644 (file)
index 0000000..52f2582
--- /dev/null
@@ -0,0 +1,98 @@
+#META: timeout=long
+
+import pytest
+from webdriver import error
+
+from conftest import product, flatten
+
+
+@pytest.mark.parametrize("value", [None, 1, "{}", []])
+def test_invalid_capabilites(new_session, value):
+    with pytest.raises(error.InvalidArgumentException):
+        new_session({"capabilities": value})
+
+
+@pytest.mark.parametrize("value", [None, 1, "{}", []])
+def test_invalid_always_match(new_session, add_browser_capabilites, value):
+    with pytest.raises(error.InvalidArgumentException):
+        new_session({"capabilities": {"alwaysMatch": value, "firstMatch": [add_browser_capabilites({})]}})
+
+
+@pytest.mark.parametrize("value", [None, 1, "[]", {}])
+def test_invalid_first_match(new_session, add_browser_capabilites, value):
+    with pytest.raises(error.InvalidArgumentException):
+        new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({}), "firstMatch": value}})
+
+
+invalid_data = [
+    ("acceptInsecureCerts", [1, [], {}, "false"]),
+    ("browserName", [1, [], {}, False]),
+    ("browserVersion", [1, [], {}, False]),
+    ("platformName", [1, [], {}, False]),
+    ("pageLoadStrategy", [1, [], {}, False, "invalid", "NONE", "Eager", "eagerblah", "interactive",
+                          " eager", "eager "]),
+    ("proxy", [1, [], "{}", {"proxyType": "SYSTEM"}, {"proxyType": "systemSomething"},
+               {"proxy type": "pac"}, {"proxy-Type": "system"}, {"proxy_type": "system"},
+               {"proxytype": "system"}, {"PROXYTYPE": "system"}, {"proxyType": None},
+               {"proxyType": 1}, {"proxyType": []}, {"proxyType": {"value": "system"}},
+               {" proxyType": "system"}, {"proxyType ": "system"}, {"proxyType ": " system"},
+               {"proxyType": "system "}]),
+    ("timeouts", [1, [], "{}", False, {"pageLOAD": 10}, {"page load": 10},
+                  {"page load": 10}, {"pageLoad": "10"}, {"pageLoad": {"value": 10}},
+                  {"invalid": 10}, {"pageLoad": -1}, {"pageLoad": 2**64},
+                  {"pageLoad": None}, {"pageLoad": 1.1}, {"pageLoad": 10, "invalid": 10},
+                  {" pageLoad": 10}, {"pageLoad ": 10}]),
+    ("unhandledPromptBehavior", [1, [], {}, False, "DISMISS", "dismissABC", "Accept",
+                                 " dismiss", "dismiss "])
+]
+
+@pytest.mark.parametrize("body", [lambda key, value: {"alwaysMatch": {key: value}},
+                                  lambda key, value: {"firstMatch": [{key: value}]}])
+@pytest.mark.parametrize("key,value", flatten(product(*item) for item in invalid_data))
+def test_invalid_values(new_session, add_browser_capabilites, body, key, value):
+    capabilities = body(key, value)
+    if "alwaysMatch" in capabilities:
+        capabilities["alwaysMatch"] = add_browser_capabilites(capabilities["alwaysMatch"])
+    else:
+        capabilities["firstMatch"][0] = add_browser_capabilites(capabilities["firstMatch"][0])
+    with pytest.raises(error.InvalidArgumentException):
+        resp = new_session({"capabilities": capabilities})
+
+
+invalid_extensions = [
+    "firefox",
+    "firefox_binary",
+    "firefoxOptions",
+    "chromeOptions",
+    "automaticInspection",
+    "automaticProfiling",
+    "platform",
+    "version",
+    "browser",
+    "platformVersion",
+    "javascriptEnabled",
+    "nativeEvents",
+    "seleniumProtocol",
+    "profile",
+    "trustAllSSLCertificates",
+    "initialBrowserUrl",
+    "requireWindowFocus",
+    "logFile",
+    "logLevel",
+    "safari.options",
+    "ensureCleanSession",
+]
+
+
+@pytest.mark.parametrize("body", [lambda key, value: {"alwaysMatch": {key: value}},
+                                  lambda key, value: {"firstMatch": [{key: value}]}])
+@pytest.mark.parametrize("key", invalid_extensions)
+def test_invalid_extensions(new_session, add_browser_capabilites, body, key):
+    capabilities = body(key, {})
+    if "alwaysMatch" in capabilities:
+        capabilities["alwaysMatch"] = add_browser_capabilites(capabilities["alwaysMatch"])
+    else:
+        capabilities["firstMatch"][0] = add_browser_capabilites(capabilities["firstMatch"][0])
+    with pytest.raises(error.InvalidArgumentException):
+        resp = new_session({"capabilities": capabilities})
+
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/new_session/merge.py b/WebDriverTests/imported/w3c/webdriver/tests/new_session/merge.py
new file mode 100644 (file)
index 0000000..480fbcd
--- /dev/null
@@ -0,0 +1,81 @@
+#META: timeout=long
+
+import pytest
+from webdriver import error
+
+from conftest import platform_name
+
+
+@pytest.mark.skipif(platform_name() is None, reason="Unsupported platform")
+@pytest.mark.parametrize("body", [lambda key, value: {"alwaysMatch": {key: value}},
+                                  lambda key, value: {"firstMatch": [{key: value}]}])
+def test_platform_name(new_session, add_browser_capabilites, platform_name, body):
+    capabilities = body("platformName", platform_name)
+    if "alwaysMatch" in capabilities:
+        capabilities["alwaysMatch"] = add_browser_capabilites(capabilities["alwaysMatch"])
+    else:
+        capabilities["firstMatch"][0] = add_browser_capabilites(capabilities["firstMatch"][0])
+    resp, _ = new_session({"capabilities": capabilities})
+    assert resp["capabilities"]["platformName"] == platform_name
+
+
+invalid_merge = [
+    ("acceptInsecureCerts", (True, True)),
+    ("unhandledPromptBehavior", ("accept", "accept")),
+    ("unhandledPromptBehavior", ("accept", "dismiss")),
+    ("timeouts", ({"script": 10}, {"script": 10})),
+    ("timeouts", ({"script": 10}, {"pageLoad": 10})),
+]
+
+
+@pytest.mark.parametrize("key,value", invalid_merge)
+def test_merge_invalid(new_session, add_browser_capabilites, key, value):
+    with pytest.raises(error.InvalidArgumentException):
+         new_session({"capabilities":
+                      {"alwaysMatch": add_browser_capabilites({key: value[0]}),
+                       "firstMatch": [{}, {key: value[1]}]}})
+
+
+@pytest.mark.skipif(platform_name() is None, reason="Unsupported platform")
+def test_merge_platformName(new_session, add_browser_capabilites, platform_name):
+    resp, _ = new_session({"capabilities":
+                        {"alwaysMatch": add_browser_capabilites({"timeouts": {"script": 10}}),
+                        "firstMatch": [
+                            {
+                                "platformName": platform_name.upper(),
+                                "pageLoadStrategy": "none"
+                            },
+                            {
+                                "platformName": platform_name,
+                                "pageLoadStrategy": "eager"
+                            }
+                        ]}})
+
+    assert resp["capabilities"]["platformName"] == platform_name
+    assert resp["capabilities"]["pageLoadStrategy"] == "eager"
+
+
+def test_merge_browserName(new_session, add_browser_capabilites):
+    resp, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({})}})
+    browser_settings = {
+        "browserName": resp["capabilities"]["browserName"],
+        "browserVersion": resp["capabilities"]["browserVersion"],
+        "platformName": resp["capabilities"]["platformName"]
+    }
+    session.end()
+
+    resp, _ = new_session({"capabilities":
+                        {"alwaysMatch": add_browser_capabilites({"timeouts": {"script": 10}}),
+                        "firstMatch": [
+                            {
+                                "browserName": browser_settings["browserName"] + "invalid",
+                                "pageLoadStrategy": "none"
+                            },
+                            {
+                                "browserName": browser_settings["browserName"],
+                                "pageLoadStrategy": "eager"
+                            }
+                        ]}})
+
+    assert resp["capabilities"]["browserName"] == browser_settings['browserName']
+    assert resp["capabilities"]["pageLoadStrategy"] == "eager"
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/new_session/response.py b/WebDriverTests/imported/w3c/webdriver/tests/new_session/response.py
new file mode 100644 (file)
index 0000000..c9a8c76
--- /dev/null
@@ -0,0 +1,54 @@
+# META: timeout=long
+
+import uuid
+
+def test_resp_sessionid(new_session, add_browser_capabilites):
+    resp, _ = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({})}})
+    assert isinstance(resp["sessionId"], unicode)
+    uuid.UUID(hex=resp["sessionId"])
+
+
+def test_resp_capabilites(new_session, add_browser_capabilites):
+    resp, _ = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({})}})
+    assert isinstance(resp["sessionId"], unicode)
+    assert isinstance(resp["capabilities"], dict)
+    assert {"browserName",
+            "browserVersion",
+            "platformName",
+            "acceptInsecureCerts",
+            "setWindowRect",
+            "timeouts",
+            "proxy",
+            "pageLoadStrategy"}.issubset(
+                set(resp["capabilities"].keys()))
+
+
+def test_resp_data(new_session, add_browser_capabilites, platform_name):
+    resp, _ = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({})}})
+
+    assert isinstance(resp["capabilities"]["browserName"], unicode)
+    assert isinstance(resp["capabilities"]["browserVersion"], unicode)
+    if platform_name:
+        assert resp["capabilities"]["platformName"] == platform_name
+    else:
+        assert "platformName" in resp["capabilities"]
+    assert resp["capabilities"]["acceptInsecureCerts"] is False
+    assert isinstance(resp["capabilities"]["setWindowRect"], bool)
+    assert resp["capabilities"]["timeouts"]["implicit"] == 0
+    assert resp["capabilities"]["timeouts"]["pageLoad"] == 300000
+    assert resp["capabilities"]["timeouts"]["script"] == 30000
+    assert resp["capabilities"]["proxy"] == {}
+    assert resp["capabilities"]["pageLoadStrategy"] == "normal"
+
+
+def test_timeouts(new_session, add_browser_capabilites, platform_name):
+    resp, _ = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"timeouts": {"implicit": 1000}})}})
+    assert resp["capabilities"]["timeouts"] == {
+        "implicit": 1000,
+        "pageLoad": 300000,
+        "script": 30000
+    }
+
+def test_pageLoadStrategy(new_session, add_browser_capabilites, platform_name):
+    resp, _ = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"pageLoadStrategy": "eager"})}})
+    assert resp["capabilities"]["pageLoadStrategy"] == "eager"
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/new_session/support/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/new_session/support/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/new_session/support/create.py b/WebDriverTests/imported/w3c/webdriver/tests/new_session/support/create.py
new file mode 100644 (file)
index 0000000..85ae1cd
--- /dev/null
@@ -0,0 +1,15 @@
+# Note that we can only test things here all implementations must support
+valid_data = [
+    ("acceptInsecureCerts", [False, None]),
+    ("browserName", [None]),
+    ("browserVersion", [None]),
+    ("platformName", [None]),
+    ("pageLoadStrategy", ["none", "eager", "normal", None]),
+    ("proxy", [None]),
+    ("timeouts", [{"script": 0, "pageLoad": 2.0, "implicit": 2**53 - 1},
+                  {"script": 50, "pageLoad": 25},
+                  {"script": 500},
+                  {}]),
+    ("unhandledPromptBehavior", ["dismiss", "accept", None]),
+    ("test:extension", [True, "abc", 123, [], {"key": "value"}, None]),
+]
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/page_source/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/page_source/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/page_source/source.py b/WebDriverTests/imported/w3c/webdriver/tests/page_source/source.py
new file mode 100644 (file)
index 0000000..97e4e1e
--- /dev/null
@@ -0,0 +1,16 @@
+from tests.support.asserts import assert_success
+from tests.support.inline import inline
+
+
+def get_page_source(session):
+    return session.transport.send(
+        "GET", "session/{session_id}/source".format(**vars(session)))
+
+
+def test_source_matches_outer_html(session):
+    session.url = inline("<html><head><title>Cheese</title><body>Peas")
+
+    expected = session.execute_script("return document.documentElement.outerHTML")
+
+    response = get_page_source(session)
+    assert_success(response, expected)
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/send_alert_text/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/send_alert_text/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/send_alert_text/send.py b/WebDriverTests/imported/w3c/webdriver/tests/send_alert_text/send.py
new file mode 100644 (file)
index 0000000..5b38b6f
--- /dev/null
@@ -0,0 +1,76 @@
+import pytest
+
+from tests.support.asserts import assert_error, assert_success
+from tests.support.inline import inline
+
+
+def send_alert_text(session, body=None):
+    return session.transport.send(
+        "POST", "session/{session_id}/alert/text".format(**vars(session)),
+        body)
+
+
+# 18.4 Send Alert Text
+
+@pytest.mark.parametrize("text", [None, {}, [], 42, True])
+def test_invalid_input(session, text):
+    # 18.4 step 2
+    session.url = inline("<script>window.result = window.prompt('Enter Your Name: ', 'Name');</script>")
+    response = send_alert_text(session, {"text": text})
+    assert_error(response, "invalid argument")
+
+
+def test_no_browsing_context(session, create_window):
+    # 18.4 step 3
+    session.window_handle = create_window()
+    session.close()
+    body = {"text": "Federer"}
+    response = send_alert_text(session, body)
+    assert_error(response, "no such window")
+
+
+def test_no_user_prompt(session):
+    # 18.4 step 4
+    body = {"text": "Federer"}
+    response = send_alert_text(session, body)
+    assert_error(response, "no such alert")
+
+
+def test_alert_element_not_interactable(session):
+    # 18.4 step 5
+    session.url = inline("<script>window.alert('Hello');</script>")
+    body = {"text": "Federer"}
+    response = send_alert_text(session, body)
+    assert_error(response, "element not interactable")
+
+
+def test_confirm_element_not_interactable(session):
+    # 18.4 step 5
+    session.url = inline("<script>window.confirm('Hello');</script>")
+    body = {"text": "Federer"}
+    response = send_alert_text(session, body)
+    assert_error(response, "element not interactable")
+
+
+def test_send_alert_text(session):
+    # 18.4 step 6
+    session.url = inline("<script>window.result = window.prompt('Enter Your Name: ', 'Name');</script>")
+    body = {"text": "Federer"}
+    send_response = send_alert_text(session, body)
+    assert_success(send_response)
+    accept_response = session.transport.send("POST", "session/{session_id}/alert/accept"
+                                             .format(session_id=session.session_id))
+    assert_success(accept_response)
+    assert session.execute_script("return window.result") == "Federer"
+
+
+def test_send_alert_text_with_whitespace(session):
+    # 18.4 step 6
+    session.url = inline("<script>window.result = window.prompt('Enter Your Name: ', 'Name');</script>")
+    body = {"text": " Fed erer "}
+    send_response = send_alert_text(session, body)
+    assert_success(send_response)
+    accept_response = session.transport.send("POST", "session/{session_id}/alert/accept"
+                                             .format(session_id=session.session_id))
+    assert_success(accept_response)
+    assert session.execute_script("return window.result") == " Fed erer "
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/set_window_rect/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/set_window_rect/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/set_window_rect/resizing_and_positioning.py b/WebDriverTests/imported/w3c/webdriver/tests/set_window_rect/resizing_and_positioning.py
new file mode 100644 (file)
index 0000000..66331fa
--- /dev/null
@@ -0,0 +1,61 @@
+import json
+import pytest
+import webdriver
+
+
+def window_size_supported(session):
+    try:
+        session.window.size = ("a", "b")
+    except webdriver.UnsupportedOperationException:
+        return False
+    except webdriver.InvalidArgumentException:
+        return True
+
+def window_position_supported(session):
+    try:
+        session.window.position = ("a", "b")
+    except webdriver.UnsupportedOperationException:
+        return False
+    except webdriver.InvalidArgumentException:
+        return True
+
+
+def test_window_resize(session):
+    if not window_size_supported(session):
+        pytest.skip()
+
+    # setting the window size by webdriver is synchronous
+    # so we should see the results immediately
+
+    session.window.size = (400, 500)
+    assert session.window.size == (400, 500)
+
+    session.window.size = (500, 600)
+    assert session.window.size == (500, 600)
+
+
+"""
+TODO(ato):
+
+    Disable test because the while statements are wrong.
+    To fix this properly we need to write an explicit wait utility.
+
+def test_window_resize_by_script(session):
+    # setting the window size by JS is asynchronous
+    # so we poll waiting for the results
+
+    size0 = session.window.size
+
+    session.execute_script("window.resizeTo(700, 800)")
+    size1 = session.window.size
+    while size0 == size1:
+        size1 = session.window.size
+    assert size1 == (700, 800)
+
+    session.execute_script("window.resizeTo(800, 900)")
+    size2 = session.window.size
+    while size1 == size2:
+        size2 = session.window.size
+        assert size2 == (800, 900)
+    assert size2 == {"width": 200, "height": 100}
+"""
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/set_window_rect/set.py b/WebDriverTests/imported/w3c/webdriver/tests/set_window_rect/set.py
new file mode 100644 (file)
index 0000000..89115f4
--- /dev/null
@@ -0,0 +1,402 @@
+# META: timeout=long
+
+import pytest
+
+from tests.support.asserts import assert_error, assert_success
+
+
+def set_window_rect(session, rect):
+    return session.transport.send(
+        "POST", "session/{session_id}/window/rect".format(**vars(session)),
+        rect)
+
+
+def is_fullscreen(session):
+    # At the time of writing, WebKit does not conform to the Fullscreen API specification.
+    # Remove the prefixed fallback when https://bugs.webkit.org/show_bug.cgi?id=158125 is fixed.
+    return session.execute_script("return !!(window.fullScreen || document.webkitIsFullScreen)")
+
+
+# 10.7.2 Set Window Rect
+
+
+def test_current_top_level_browsing_context_no_longer_open(session, create_window):
+    """
+    1. If the current top-level browsing context is no longer open,
+    return error with error code no such window.
+
+    """
+    session.window_handle = create_window()
+    session.close()
+    response = set_window_rect(session, {})
+    assert_error(response, "no such window")
+
+
+@pytest.mark.parametrize("rect", [
+    {"width": "a"},
+    {"height": "b"},
+    {"width": "a", "height": "b"},
+    {"x": "a"},
+    {"y": "b"},
+    {"x": "a", "y": "b"},
+    {"width": "a", "height": "b", "x": "a", "y": "b"},
+
+    {"width": True},
+    {"height": False},
+    {"width": True, "height": False},
+    {"x": True},
+    {"y": False},
+    {"x": True, "y": False},
+    {"width": True, "height": False, "x": True, "y": False},
+
+    {"width": []},
+    {"height": []},
+    {"width": [], "height": []},
+    {"x": []},
+    {"y": []},
+    {"x": [], "y": []},
+    {"width": [], "height": [], "x": [], "y": []},
+
+    {"height": {}},
+    {"width": {}},
+    {"height": {}, "width": {}},
+    {"x": {}},
+    {"y": {}},
+    {"x": {}, "y": {}},
+    {"width": {}, "height": {}, "x": {}, "y": {}},
+])
+def test_invalid_types(session, rect):
+    """
+    8. If width or height is neither null nor a Number from 0 to 2^31 -
+    1, return error with error code invalid argument.
+
+    9. If x or y is neither null nor a Number from -(2^31) to 2^31 - 1,
+    return error with error code invalid argument.
+    """
+    response = set_window_rect(session, rect)
+    assert_error(response, "invalid argument")
+
+
+@pytest.mark.parametrize("rect", [
+    {"width": -1},
+    {"height": -2},
+    {"width": -1, "height": -2},
+])
+def test_out_of_bounds(session, rect):
+    """
+    8. If width or height is neither null nor a Number from 0 to 2^31 -
+    1, return error with error code invalid argument.
+
+    9. If x or y is neither null nor a Number from -(2^31) to 2^31 - 1,
+    return error with error code invalid argument.
+    """
+    response = set_window_rect(session, rect)
+    assert_error(response, "invalid argument")
+
+
+def test_width_height_floats(session):
+    """
+    8. If width or height is neither null nor a Number from 0 to 2^31 -
+    1, return error with error code invalid argument.
+    """
+
+    response = set_window_rect(session, {"width": 500.5, "height": 420})
+    value = assert_success(response)
+    assert value["width"] == 500
+    assert value["height"] == 420
+
+    response = set_window_rect(session, {"width": 500, "height": 450.5})
+    value = assert_success(response)
+    assert value["width"] == 500
+    assert value["height"] == 450
+
+
+def test_x_y_floats(session):
+    """
+    9. If x or y is neither null nor a Number from -(2^31) to 2^31 - 1,
+    return error with error code invalid argument.
+    """
+
+    response = set_window_rect(session, {"x": 0.5, "y": 420})
+    value = assert_success(response)
+    assert value["x"] == 0
+    assert value["y"] == 420
+
+    response = set_window_rect(session, {"x": 100, "y": 450.5})
+    value = assert_success(response)
+    assert value["x"] == 100
+    assert value["y"] == 450
+
+
+@pytest.mark.parametrize("rect", [
+    {},
+
+    {"width": None},
+    {"height": None},
+    {"width": None, "height": None},
+
+    {"x": None},
+    {"y": None},
+    {"x": None, "y": None},
+
+    {"width": None, "x": None},
+    {"width": None, "y": None},
+    {"height": None, "x": None},
+    {"height": None, "Y": None},
+
+    {"width": None, "height": None, "x": None, "y": None},
+
+    {"width": 200},
+    {"height": 200},
+    {"x": 200},
+    {"y": 200},
+    {"width": 200, "x": 200},
+    {"height": 200, "x": 200},
+    {"width": 200, "y": 200},
+    {"height": 200, "y": 200},
+])
+def test_no_change(session, rect):
+    """
+    13. If width and height are not null:
+
+    [...]
+
+    14. If x and y are not null:
+
+    [...]
+
+    15. Return success with the JSON serialization of the current
+    top-level browsing context's window rect.
+    """
+
+    original = session.window.rect
+    response = set_window_rect(session, rect)
+    assert_success(response, original)
+
+
+def test_fully_exit_fullscreen(session):
+    """
+    10. Fully exit fullscreen.
+
+    [...]
+
+    To fully exit fullscreen a document document, run these steps:
+
+      1. If document's fullscreen element is null, terminate these steps.
+
+      2. Unfullscreen elements whose fullscreen flag is set, within
+      document's top layer, except for document's fullscreen element.
+
+      3. Exit fullscreen document.
+    """
+    session.window.fullscreen()
+    assert is_fullscreen(session) is True
+
+    response = set_window_rect(session, {"width": 400, "height": 400})
+    value = assert_success(response)
+    assert value["width"] == 400
+    assert value["height"] == 400
+
+    assert is_fullscreen(session) is False
+
+
+def test_restore_from_minimized(session):
+    """
+    12. If the visibility state of the top-level browsing context's
+    active document is hidden, restore the window.
+
+    [...]
+
+    To restore the window, given an operating system level window with
+    an associated top-level browsing context, run implementation-specific
+    steps to restore or unhide the window to the visible screen. Do not
+    return from this operation until the visibility state of the top-level
+    browsing context's active document has reached the visible state,
+    or until the operation times out.
+    """
+
+    session.window.minimize()
+    assert session.execute_script("return document.hidden") is True
+
+    response = set_window_rect(session, {"width": 450, "height": 450})
+    value = assert_success(response)
+    assert value["width"] == 450
+    assert value["height"] == 450
+
+    assert session.execute_script("return document.hidden") is False
+
+
+def test_restore_from_maximized(session):
+    """
+    12. If the visibility state of the top-level browsing context's
+    active document is hidden, restore the window.
+
+    [...]
+
+    To restore the window, given an operating system level window with
+    an associated top-level browsing context, run implementation-specific
+    steps to restore or unhide the window to the visible screen. Do not
+    return from this operation until the visibility state of the top-level
+    browsing context's active document has reached the visible state,
+    or until the operation times out.
+    """
+
+    original_size = session.window.size
+    session.window.maximize()
+    assert session.window.size != original_size
+
+    response = set_window_rect(session, {"width": 400, "height": 400})
+    value = assert_success(response)
+    assert value["width"] == 400
+    assert value["height"] == 400
+
+
+def test_height_width(session):
+    original = session.window.rect
+    max = session.execute_script("""
+        return {
+          width: window.screen.availWidth,
+          height: window.screen.availHeight,
+        }""")
+
+    # step 12
+    response = set_window_rect(session, {"width": max["width"] - 100,
+                                         "height": max["height"] - 100})
+
+    # step 14
+    assert_success(response, {"x": original["x"],
+                              "y": original["y"],
+                              "width": max["width"] - 100,
+                              "height": max["height"] - 100})
+
+
+def test_height_width_larger_than_max(session):
+    max = session.execute_script("""
+        return {
+          width: window.screen.availWidth,
+          height: window.screen.availHeight,
+        }""")
+
+    # step 12
+    response = set_window_rect(session, {"width": max["width"] + 100,
+                                         "height": max["height"] + 100})
+
+    # step 14
+    rect = assert_success(response)
+    assert rect["width"] >= max["width"]
+    assert rect["height"] >= max["height"]
+
+
+def test_height_width_as_current(session):
+    original = session.window.rect
+
+    # step 12
+    response = set_window_rect(session, {"width": original["width"],
+                                         "height": original["height"]})
+
+    # step 14
+    assert_success(response, {"x": original["x"],
+                              "y": original["y"],
+                              "width": original["width"],
+                              "height": original["height"]})
+
+
+def test_x_y(session):
+    original = session.window.rect
+
+    # step 13
+    response = set_window_rect(session, {"x": original["x"] + 10,
+                                         "y": original["y"] + 10})
+
+    # step 14
+    assert_success(response, {"x": original["x"] + 10,
+                              "y": original["y"] + 10,
+                              "width": original["width"],
+                              "height": original["height"]})
+
+
+def test_negative_x_y(session):
+    original = session.window.rect
+
+    # step 13
+    response = set_window_rect(session, {"x": - 8, "y": - 8})
+
+    # step 14
+    os = session.capabilities["platformName"]
+    # certain WMs prohibit windows from being moved off-screen
+    if os == "linux":
+        rect = assert_success(response)
+        assert rect["x"] <= 0
+        assert rect["y"] <= 0
+        assert rect["width"] == original["width"]
+        assert rect["height"] == original["height"]
+
+    # On macOS, windows can only be moved off the screen on the
+    # horizontal axis.  The system menu bar also blocks windows from
+    # being moved to (0,0).
+    elif os == "darwin":
+        assert_success(response, {"x": -8,
+                                  "y": 23,
+                                  "width": original["width"],
+                                  "height": original["height"]})
+
+    # It turns out that Windows is the only platform on which the
+    # window can be reliably positioned off-screen.
+    elif os == "windows_nt":
+        assert_success(response, {"x": -8,
+                                  "y": -8,
+                                  "width": original["width"],
+                                  "height": original["height"]})
+
+
+def test_move_to_same_position(session):
+    original_position = session.window.position
+    position = session.window.position = original_position
+    assert position == original_position
+
+
+def test_move_to_same_x(session):
+    original_x = session.window.position[0]
+    position = session.window.position = (original_x, 345)
+    assert position == (original_x, 345)
+
+
+def test_move_to_same_y(session):
+    original_y = session.window.position[1]
+    position = session.window.position = (456, original_y)
+    assert position == (456, original_y)
+
+
+def test_resize_to_same_size(session):
+    original_size = session.window.size
+    size = session.window.size = original_size
+    assert size == original_size
+
+
+def test_resize_to_same_width(session):
+    original_width = session.window.size[0]
+    size = session.window.size = (original_width, 345)
+    assert size == (original_width, 345)
+
+
+def test_resize_to_same_height(session):
+    original_height = session.window.size[1]
+    size = session.window.size = (456, original_height)
+    assert size == (456, original_height)
+
+
+def test_payload(session):
+    # step 14
+    response = set_window_rect(session, {"x": 400, "y": 400})
+
+    assert response.status == 200
+    assert isinstance(response.body["value"], dict)
+    value = response.body["value"]
+    assert "width" in value
+    assert "height" in value
+    assert "x" in value
+    assert "y" in value
+    assert isinstance(value["width"], int)
+    assert isinstance(value["height"], int)
+    assert isinstance(value["x"], int)
+    assert isinstance(value["y"], int)
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/set_window_rect/user_prompts.py b/WebDriverTests/imported/w3c/webdriver/tests/set_window_rect/user_prompts.py
new file mode 100644 (file)
index 0000000..85249d9
--- /dev/null
@@ -0,0 +1,73 @@
+from tests.support.asserts import assert_dialog_handled, assert_error, assert_success
+from tests.support.fixtures import create_dialog
+
+
+def set_window_rect(session, rect):
+    return session.transport.send(
+        "POST", "session/{session_id}/window/rect".format(**vars(session)),
+        rect)
+
+
+def test_handle_prompt_dismiss():
+    """TODO"""
+
+
+def test_handle_prompt_accept(new_session, add_browser_capabilites):
+    _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({"unhandledPromptBehavior": "accept"})}})
+    original = session.window.rect
+
+    # step 2
+    create_dialog(session)("alert", text="dismiss #1", result_var="dismiss1")
+    result = set_window_rect(session, {"x": original["x"],
+                                       "y": original["y"]})
+    assert result.status == 200
+    assert_dialog_handled(session, "dismiss #1")
+
+    create_dialog(session)("confirm", text="dismiss #2", result_var="dismiss2")
+    result = set_window_rect(session, {"x": original["x"],
+                                       "y": original["y"]})
+    assert result.status == 200
+    assert_dialog_handled(session, "dismiss #2")
+
+    create_dialog(session)("prompt", text="dismiss #3", result_var="dismiss3")
+    result = set_window_rect(session, {"x": original["x"],
+                                       "y": original["y"]})
+    assert_success(result)
+    assert_dialog_handled(session, "dismiss #3")
+
+
+def test_handle_prompt_dismiss_and_notify():
+    """TODO"""
+
+
+def test_handle_prompt_accept_and_notify():
+    """TODO"""
+
+
+def test_handle_prompt_ignore():
+    """TODO"""
+
+
+def test_handle_prompt_missing_value(session, create_dialog):
+    original = session.window.rect
+
+    create_dialog("alert", text="dismiss #1", result_var="dismiss1")
+
+    result = set_window_rect(session, {"x": original["x"],
+                                       "y": original["y"]})
+    assert_error(result, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #1")
+
+    create_dialog("confirm", text="dismiss #2", result_var="dismiss2")
+
+    result = set_window_rect(session, {"x": original["x"],
+                                       "y": original["y"]})
+    assert_error(result, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #2")
+
+    create_dialog("prompt", text="dismiss #3", result_var="dismiss3")
+
+    result = set_window_rect(session, {"x": original["x"],
+                                       "y": original["y"]})
+    assert_error(result, "unexpected alert open")
+    assert_dialog_handled(session, "dismiss #3")
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/status/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/status/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/status/status.py b/WebDriverTests/imported/w3c/webdriver/tests/status/status.py
new file mode 100644 (file)
index 0000000..95b2643
--- /dev/null
@@ -0,0 +1,50 @@
+import json
+
+from tests.support.asserts import assert_success
+
+
+def get_status(session):
+    return session.transport.send("GET", "/status")
+
+
+def test_get_status_no_session(http):
+    with http.get("/status") as response:
+        # GET /status should never return an error
+        assert response.status == 200
+
+        # parse JSON response and unwrap 'value' property
+        parsed_obj = json.loads(response.read().decode('utf-8'))
+        value = parsed_obj["value"]
+
+        # Let body be a new JSON Object with the following properties:
+        # "ready"
+        #       The remote end's readiness state.
+        assert value["ready"] in [True, False]
+        # "message"
+        #       An implementation-defined string explaining the remote end's
+        #       readiness state.
+        assert isinstance(value["message"], basestring)
+
+
+def test_status_with_session_running_on_endpoint_node(new_session, add_browser_capabilites):
+    # For an endpoint node, the maximum number of active
+    # sessions is 1: https://www.w3.org/TR/webdriver/#dfn-maximum-active-sessions
+    # A session is open, so we expect `ready` to be False
+    # 8.3 step 1.
+
+    _, session = new_session({"capabilities": {"alwaysMatch": add_browser_capabilites({})}})
+
+    response = get_status(session)
+    value = assert_success(response)
+    assert value["ready"] is False
+    assert "message" in value
+
+    session.end()
+
+    # Active session count is 0, meaning that the
+    # readiness state of the server should be True
+    # 8.3 step 1. Again
+    response = get_status(session)
+    value = assert_success(response)
+    assert value["ready"] is True
+    assert "message" in value
index 6a20fec..dbf9f1d 100644 (file)
@@ -76,6 +76,7 @@ def _restore_windows(session):
     session.window_handle = current_window
 
 
+@ignore_exceptions
 def _switch_to_top_level_browsing_context(session):
     """If the current browsing context selected by WebDriver is a
     `<frame>` or an `<iframe>`, switch it back to the top-level
index cdb6dc1..2f8fe9b 100644 (file)
@@ -40,5 +40,9 @@ def main(request, response):
     if doc is None:
         rv = 404, [("Content-Type", "text/plain")], "Missing doc parameter in query"
     else:
-        rv = [("Content-Type", content_type)], doc
+        response.headers.update([
+          ("Content-Type", content_type),
+          ("X-XSS-Protection", "0")
+        ])
+        rv = doc
     return rv
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/switch_to_parent_frame/__init__.py b/WebDriverTests/imported/w3c/webdriver/tests/switch_to_parent_frame/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/switch_to_parent_frame/switch.py b/WebDriverTests/imported/w3c/webdriver/tests/switch_to_parent_frame/switch.py
new file mode 100644 (file)
index 0000000..215c2a4
--- /dev/null
@@ -0,0 +1,23 @@
+import pytest
+from webdriver import StaleElementReferenceException
+
+from tests.support.asserts import assert_success
+from tests.support.inline import inline, iframe
+
+
+def switch_to_parent_frame(session):
+    return session.transport.send(
+        "POST", "session/{session_id}/frame/parent".format(**vars(session)))
+
+
+def test_stale_element_from_iframe(session):
+    session.url = inline(iframe("<p>foo"))
+    frame_element = session.find.css("iframe", all=False)
+    session.switch_frame(frame_element)
+    stale_element = session.find.css("p", all=False)
+
+    result = switch_to_parent_frame(session)
+    assert_success(result)
+
+    with pytest.raises(StaleElementReferenceException):
+        stale_element.text