diff --git a/content-security-policy/securitypolicyviolation/idl.html b/content-security-policy/securitypolicyviolation/idl.html index 17f492e7344de6..a4f9e68f8314db 100644 --- a/content-security-policy/securitypolicyviolation/idl.html +++ b/content-security-policy/securitypolicyviolation/idl.html @@ -21,6 +21,9 @@ long lineNumber; long columnNumber; }; + + interface Event { + }; -
diff --git a/css/css-animations/animation-delay-011.html b/css/css-animations/animation-delay-011.html new file mode 100644 index 00000000000000..415a5747553797 --- /dev/null +++ b/css/css-animations/animation-delay-011.html @@ -0,0 +1,24 @@ + + +CSS Animations Test: inherited animation-delay with mismatched animation-name length + + + + +
diff --git a/css/css-ui/text-overflow-026-ref.html b/css/css-ui/text-overflow-026-ref.html new file mode 100644 index 00000000000000..f2db8c747fa8ac --- /dev/null +++ b/css/css-ui/text-overflow-026-ref.html @@ -0,0 +1,62 @@ + + + + + Reference: text-overflow with leading white-space + + + + + +
+The test PASS if all of the following are true:
+1. there are no red areas
+2. the first two blocks display "PASS" but no ellipsis
+3. the last three blocks display an ellipsis
+
+ +
+ + PASS PASS PASS PASS PASS +
+ +
+ + + PASS PASS PASS PASS PASS +
+ +
+  … +
+ +
+  … +
+ +
+ a… +
+ + + diff --git a/css/css-ui/text-overflow-026.html b/css/css-ui/text-overflow-026.html new file mode 100644 index 00000000000000..2d1aa57cc8923f --- /dev/null +++ b/css/css-ui/text-overflow-026.html @@ -0,0 +1,67 @@ + + + + + Test: text-overflow with leading white-space + + + + + + + +
+The test PASS if all of the following are true:
+1. there are no red areas
+2. the first two blocks display "PASS" but no ellipsis
+3. the last three blocks display an ellipsis
+
+ +
+ + PASS PASS PASS PASS PASS +
+ +
+ + + PASS PASS PASS PASS PASS +
+ +
+   + FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL +
+ +
+   + FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL +
+ +
+ a + FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL +
+ + + diff --git a/css/selectors/any-link-dynamic-001-ref.html b/css/selectors/any-link-dynamic-001-ref.html new file mode 100644 index 00000000000000..b5407429be803d --- /dev/null +++ b/css/selectors/any-link-dynamic-001-ref.html @@ -0,0 +1,10 @@ + + +CSS test reference + + + + This should be green + diff --git a/css/selectors/any-link-dynamic-001.html b/css/selectors/any-link-dynamic-001.html new file mode 100644 index 00000000000000..e84989fd0c2708 --- /dev/null +++ b/css/selectors/any-link-dynamic-001.html @@ -0,0 +1,14 @@ + + +CSS test: Handling of dynamic changes to :any-link selectors + + + + + + This should be green + diff --git a/custom-elements/Document-createElement.html b/custom-elements/Document-createElement.html index e446c507ca865a..52a68e8e178976 100644 --- a/custom-elements/Document-createElement.html +++ b/custom-elements/Document-createElement.html @@ -29,6 +29,21 @@ }, 'document.createElement must create an instance of custom elements'); +test(function () { + class AutonomousCustomElement extends HTMLElement {}; + class IsCustomElement extends HTMLElement {}; + + customElements.define('autonomous-custom-element', AutonomousCustomElement); + customElements.define('is-custom-element', IsCustomElement); + + var instance = document.createElement('autonomous-custom-element', { is: "is-custom-element"}); + + assert_true(instance instanceof AutonomousCustomElement); + assert_equals(instance.localName, 'autonomous-custom-element'); + assert_equals(instance.namespaceURI, 'http://www.w3.org/1999/xhtml', 'A custom element HTML must use HTML namespace'); + +}, 'document.createElement must create an instance of autonomous custom elements when it has is attribute'); + function assert_reports(expected, testFunction, message) { var uncaughtError = null; window.onerror = function (message, url, lineNumber, columnNumber, error) { uncaughtError = error; return true; } diff --git a/custom-elements/parser/parser-constructs-custom-elements-with-is.html b/custom-elements/parser/parser-constructs-custom-elements-with-is.html new file mode 100644 index 00000000000000..96c00278a3d7a0 --- /dev/null +++ b/custom-elements/parser/parser-constructs-custom-elements-with-is.html @@ -0,0 +1,51 @@ + + + +Custom Elements: Changes to the HTML parser + + + + + + + + +
+ + + + + + diff --git a/custom-elements/upgrading/Node-cloneNode.html b/custom-elements/upgrading/Node-cloneNode.html index 0d158fd59e4863..0492e1f39a131d 100644 --- a/custom-elements/upgrading/Node-cloneNode.html +++ b/custom-elements/upgrading/Node-cloneNode.html @@ -30,6 +30,25 @@ 'A cloned custom element must be an instance of the custom element'); }, 'Node.prototype.cloneNode(false) must be able to clone a custom element'); +test(function () { + class AutonomousCustomElement extends HTMLElement {}; + class IsCustomElement extends HTMLElement {}; + + customElements.define('autonomous-custom-element', AutonomousCustomElement); + customElements.define('is-custom-element', IsCustomElement); + + var instance = document.createElement('autonomous-custom-element', { is: "is-custom-element"}); + assert_true(instance instanceof HTMLElement); + assert_true(instance instanceof AutonomousCustomElement); + + var clone = instance.cloneNode(false); + assert_not_equals(instance, clone); + assert_true(clone instanceof HTMLElement, + 'A cloned custom element must be an instance of HTMLElement'); + assert_true(clone instanceof AutonomousCustomElement, + 'A cloned custom element must be an instance of the custom element'); +}, 'Node.prototype.cloneNode(false) must be able to clone as a autonomous custom element when it contains is attribute'); + test_with_window(function (contentWindow) { var contentDocument = contentWindow.document; class MyCustomElement extends contentWindow.HTMLElement {} diff --git a/dom/events/EventListener-invoke-legacy.html b/dom/events/EventListener-invoke-legacy.html index 85a4b0a5fe64ef..a01afcd8d1985c 100644 --- a/dom/events/EventListener-invoke-legacy.html +++ b/dom/events/EventListener-invoke-legacy.html @@ -51,22 +51,16 @@ } function setupTransition(elem) { - elem.style.transition = ''; - requestAnimationFrame(function() { - elem.style.color = 'red'; - elem.style.transition = 'color 30ms'; - requestAnimationFrame(function() { - elem.style.color = 'green'; - }); - }); + getComputedStyle(elem).color; + elem.style.color = 'green'; + elem.style.transition = 'color 30ms'; } function setupAnimation(elem) { - elem.style.animation = 'test 30ms 2'; + elem.style.animation = 'test 30ms'; } runLegacyEventTest('transitionend', 'webkitTransitionEnd', "TransitionEvent", setupTransition); runLegacyEventTest('animationend', 'webkitAnimationEnd', "AnimationEvent", setupAnimation); -runLegacyEventTest('animationiteration', 'webkitAnimationIteration', "AnimationEvent", setupAnimation); runLegacyEventTest('animationstart', 'webkitAnimationStart', "AnimationEvent", setupAnimation); diff --git a/html/semantics/scripting-1/the-script-element/module/inline-async-execorder.html b/html/semantics/scripting-1/the-script-element/module/inline-async-execorder.html new file mode 100644 index 00000000000000..db03612e82b42b --- /dev/null +++ b/html/semantics/scripting-1/the-script-element/module/inline-async-execorder.html @@ -0,0 +1,29 @@ + + + Inline async module script execution order + + + + + + + + + + + + diff --git a/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html b/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html index ab510c675ad170..27e50f7fd69537 100644 --- a/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html +++ b/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html @@ -26,4 +26,4 @@ + onerror="unreachable()" onload="log.push(3)"> diff --git a/html/semantics/scripting-1/the-script-element/module/load-error-events-inline.html b/html/semantics/scripting-1/the-script-element/module/load-error-events-inline.html index c4dd0807f62a62..58397dd07d48b4 100644 --- a/html/semantics/scripting-1/the-script-element/module/load-error-events-inline.html +++ b/html/semantics/scripting-1/the-script-element/module/load-error-events-inline.html @@ -59,4 +59,3 @@ - diff --git a/html/semantics/scripting-1/the-script-element/module/module-in-xhtml.xhtml b/html/semantics/scripting-1/the-script-element/module/module-in-xhtml.xhtml index 724c9e750743f8..1655e61a7c54e3 100644 --- a/html/semantics/scripting-1/the-script-element/module/module-in-xhtml.xhtml +++ b/html/semantics/scripting-1/the-script-element/module/module-in-xhtml.xhtml @@ -10,7 +10,11 @@ window.evaluated_module_script = true; diff --git a/html/semantics/scripting-1/the-script-element/module/resources/fast-module.js b/html/semantics/scripting-1/the-script-element/module/resources/fast-module.js new file mode 100644 index 00000000000000..3a76cf71f6c592 --- /dev/null +++ b/html/semantics/scripting-1/the-script-element/module/resources/fast-module.js @@ -0,0 +1 @@ +loaded.push("fast"); diff --git a/html/semantics/scripting-1/the-script-element/module/resources/slow-module.js b/html/semantics/scripting-1/the-script-element/module/resources/slow-module.js new file mode 100644 index 00000000000000..4623ef7360409a --- /dev/null +++ b/html/semantics/scripting-1/the-script-element/module/resources/slow-module.js @@ -0,0 +1,3 @@ +// This module is imported with pipe=trickle(d2) to make it load more slowly +// than fast-module.js +loaded.push("slow"); diff --git a/service-workers/service-worker/about-blank-replacement.https.html b/service-workers/service-worker/about-blank-replacement.https.html index 3acfe1b166a68c..e1fefaf290fe52 100644 --- a/service-workers/service-worker/about-blank-replacement.https.html +++ b/service-workers/service-worker/about-blank-replacement.https.html @@ -58,7 +58,7 @@ }); } -async function doAsyncTest(t, scope, extraSearchParams) { +async function doAsyncTest(t, scope) { let reg = await service_worker_unregister_and_register(t, worker, scope); await wait_for_state(t, reg.installing, 'activated'); @@ -70,20 +70,30 @@ let initialResult = frame.contentWindow.nested().document.body.textContent; assert_false(initialResult.startsWith('failure:'), `result: ${initialResult}`); + assert_equals(frame.contentWindow.navigator.serviceWorker.controller.scriptURL, + frame.contentWindow.nested().navigator.serviceWorker.controller.scriptURL, + 'nested about:blank should have same controlling service worker'); + // Next, ask the service worker to find the final client ID for the fully // loaded nested frame. - let nestedURL = new URL(scope, window.location); - nestedURL.searchParams.set('nested', true); - extraSearchParams = extraSearchParams || {}; - for (let p in extraSearchParams) { - nestedURL.searchParams.set(p, extraSearchParams[p]); - } + let nestedURL = new URL(frame.contentWindow.nested().location); let finalResult = await getClientIdByURL(reg.active, nestedURL); assert_false(finalResult.startsWith('failure:'), `result: ${finalResult}`); - // The initial about:blank client and the final loaded client should have - // the same ID value. - assert_equals(initialResult, finalResult, 'client ID values should match'); + // If the nested frame doesn't have a URL to load, then there is no fetch + // event and the body should be empty. We can't verify the final client ID + // against anything. + if (nestedURL.href === 'about:blank' || + nestedURL.href === 'about:srcdoc') { + assert_equals('', initialResult, 'about:blank text content should be blank'); + } + + // If the nested URL is not about:blank, though, then the fetch event handler + // should have populated the body with the client id of the initial about:blank. + // Verify the final client id matches. + else { + assert_equals(initialResult, finalResult, 'client ID values should match'); + } frame.remove(); await service_worker_unregister_and_done(t, scope); @@ -101,8 +111,7 @@ // worker can ping the client to verify its existence. This ping-pong // check is performed during the initial load and when verifying the // final loaded client. - await doAsyncTest(t, 'resources/about-blank-replacement-ping-frame.py', - { 'ping': true }); + await doAsyncTest(t, 'resources/about-blank-replacement-ping-frame.py'); }, 'Initial about:blank modified by parent is controlled, exposed to ' + 'clients.matchAll(), and matches final Client.'); @@ -142,5 +151,27 @@ }, 'Initial about:blank is controlled, exposed to clients.matchAll(), and ' + 'final Client is not controlled by a service worker.'); +promise_test(async function(t) { + // Execute a test where the nested frame is an iframe without a src + // attribute. This simple nested about:blank should still inherit the + // controller and be visible to clients.matchAll(). + await doAsyncTest(t, 'resources/about-blank-replacement-blank-nested-frame.html'); +}, 'Simple about:blank is controlled and is exposed to clients.matchAll().'); + +promise_test(async function(t) { + // Execute a test where the nested frame is an iframe using a non-empty + // srcdoc containing only a tag pair so its textContent is still empty. + // This nested iframe should still inherit the controller and be visible + // to clients.matchAll(). + await doAsyncTest(t, 'resources/about-blank-replacement-srcdoc-nested-frame.html'); +}, 'Nested about:srcdoc is controlled and is exposed to clients.matchAll().'); + +promise_test(async function(t) { + // Execute a test where the nested frame is dynamically added without a src + // attribute. This simple nested about:blank should still inherit the + // controller and be visible to clients.matchAll(). + await doAsyncTest(t, 'resources/about-blank-replacement-blank-dynamic-nested-frame.html'); +}, 'Dynamic about:blank is controlled and is exposed to clients.matchAll().'); + diff --git a/service-workers/service-worker/fetch-response-taint.https.html b/service-workers/service-worker/fetch-response-taint.https.html index a6e7f984ea2449..8ebee0c07374c3 100644 --- a/service-workers/service-worker/fetch-response-taint.https.html +++ b/service-workers/service-worker/fetch-response-taint.https.html @@ -193,6 +193,9 @@ // Fetch to the other origin with same-origin mode should fail. if (origin == OTHER_ORIGIN && mode == 'same-origin') { ng_test(url, mode, credentials); + } else if (origin == BASE_ORIGIN && mode == 'same-origin') { + // Cors type response to a same-origin mode request should fail + ng_test(url, mode, credentials); } else { // The response from the SW should be cors. ok_test(url, mode, credentials, 'cors', 'undefined'); @@ -208,6 +211,9 @@ // Fetch to the other origin with same-origin mode should fail. if (origin == OTHER_ORIGIN && mode == 'same-origin') { ng_test(url, mode, credentials); + } else if (origin == BASE_ORIGIN && mode == 'same-origin') { + // Cors type response to a same-origin mode request should fail + ng_test(url, mode, credentials); } else { // The response from the SW should be cors. ok_test(url, mode, credentials, 'cors', 'username1s'); diff --git a/service-workers/service-worker/resources/about-blank-replacement-blank-dynamic-nested-frame.html b/service-workers/service-worker/resources/about-blank-replacement-blank-dynamic-nested-frame.html new file mode 100644 index 00000000000000..1e0c6209bfc0bd --- /dev/null +++ b/service-workers/service-worker/resources/about-blank-replacement-blank-dynamic-nested-frame.html @@ -0,0 +1,21 @@ + + + + + + diff --git a/service-workers/service-worker/resources/about-blank-replacement-blank-nested-frame.html b/service-workers/service-worker/resources/about-blank-replacement-blank-nested-frame.html new file mode 100644 index 00000000000000..99d07a48cda5ea --- /dev/null +++ b/service-workers/service-worker/resources/about-blank-replacement-blank-nested-frame.html @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/service-workers/service-worker/resources/about-blank-replacement-popup-frame.py b/service-workers/service-worker/resources/about-blank-replacement-popup-frame.py index be5294539833c7..f0b8cd578e3e05 100644 --- a/service-workers/service-worker/resources/about-blank-replacement-popup-frame.py +++ b/service-workers/service-worker/resources/about-blank-replacement-popup-frame.py @@ -12,12 +12,15 @@ def main(request, response): + + + + diff --git a/service-workers/service-worker/worker-interception.https.html b/service-workers/service-worker/worker-interception.https.html index 3ec66a54b6e1e5..4f14746d917f9e 100644 --- a/service-workers/service-worker/worker-interception.https.html +++ b/service-workers/service-worker/worker-interception.https.html @@ -81,10 +81,16 @@ }); }) .then(function(data) { - assert_equals(data, 'dummy-worker-script loaded'); + assert_unreached('intercepted cors response to a same-origin mode ' + + 'worker load should fail'); service_worker_unregister_and_done(t, scope); - }); - }, 'Verify worker script intercepted by cors response succeeds'); + }) + .catch(function(e) { + assert_true(true, 'intercepted cors response to a same-origin mode ' + + 'worker load should fail'); + service_worker_unregister_and_done(t, scope); + }); + }, 'Verify worker script intercepted by cors response fails'); promise_test(function(t) { var worker_url = 'resources/dummy-no-cors-worker.js'; diff --git a/tools/wptrunner/wptrunner/executors/executormarionette.py b/tools/wptrunner/wptrunner/executors/executormarionette.py index edea3f14aa4da4..e9850dfa419137 100644 --- a/tools/wptrunner/wptrunner/executors/executormarionette.py +++ b/tools/wptrunner/wptrunner/executors/executormarionette.py @@ -96,7 +96,7 @@ def setup(self, runner): def teardown(self): try: self.marionette._request_in_app_shutdown() - self.marionette.delete_session(send_request=False, reset_session_id=True) + self.marionette.delete_session(send_request=False) except Exception: # This is typically because the session never started pass @@ -175,7 +175,11 @@ def wait(self): # This can happen if there was a crash return if socket_timeout: - self.marionette.timeout.script = socket_timeout / 2 + try: + self.marionette.timeout.script = socket_timeout / 2 + except (socket.error, IOError): + self.logger.debug("Socket closed") + return self.marionette.switch_to_window(self.runner_handle) while True: @@ -564,7 +568,7 @@ def teardown(self): self.executor.protocol.marionette.set_context(self.executor.protocol.marionette.CONTEXT_CONTENT) except Exception as e: # Ignore errors during teardown - self.logger.warning(traceback.traceback.format_exc(e)) + self.logger.warning(traceback.format_exc(e)) diff --git a/tools/wptrunner/wptrunner/executors/pytestrunner/runner.py b/tools/wptrunner/wptrunner/executors/pytestrunner/runner.py index a2b603dd04439f..61063f83bca3bb 100644 --- a/tools/wptrunner/wptrunner/executors/pytestrunner/runner.py +++ b/tools/wptrunner/wptrunner/executors/pytestrunner/runner.py @@ -58,6 +58,7 @@ def run(path, server_config, session_config, timeout=0): "--showlocals", # display contents of variables in local scope "-p", "no:mozlog", # use the WPT result recorder "-p", "no:cacheprovider", # disable state preservation across invocations + "-o=console_output_style=classic", # disable test progress bar path], plugins=[harness, subtests]) except Exception as e: diff --git a/tools/wptrunner/wptrunner/testrunner.py b/tools/wptrunner/wptrunner/testrunner.py index 64418285e66f16..75f4825f95255c 100644 --- a/tools/wptrunner/wptrunner/testrunner.py +++ b/tools/wptrunner/wptrunner/testrunner.py @@ -120,6 +120,13 @@ def start_runner(runner_command_queue, runner_result_queue, executor_browser_cls, executor_browser_kwargs, stop_flag): """Launch a TestRunner in a new process""" + def log(level, msg): + runner_result_queue.put(("log", (level, {"message": msg}))) + + def handle_error(e): + log("critical", traceback.format_exc()) + stop_flag.set() + try: browser = executor_browser_cls(**executor_browser_kwargs) executor = executor_cls(browser, **executor_kwargs) @@ -128,10 +135,10 @@ def start_runner(runner_command_queue, runner_result_queue, runner.run() except KeyboardInterrupt: stop_flag.set() - except Exception: - runner_result_queue.put(("log", ("critical", {"message": traceback.format_exc()}))) - print >> sys.stderr, traceback.format_exc() - stop_flag.set() + except Exception as e: + handle_error(e) + except Exception as e: + handle_error(e) finally: runner_command_queue = None runner_result_queue = None @@ -389,6 +396,7 @@ def wait_event(self): } try: command, data = self.command_queue.get(True, 1) + self.logger.debug("Got command: %r" % command) except IOError: self.logger.error("Got IOError from poll") return RunnerManagerState.restarting(0) @@ -676,7 +684,18 @@ def cleanup(self): self.browser.cleanup() while True: try: - self.logger.warning(" ".join(map(repr, self.command_queue.get_nowait()))) + cmd, data = self.command_queue.get_nowait() + except Empty: + break + else: + if cmd == "log": + self.log(*data) + else: + self.logger.warning("%r: %r" % (cmd, data)) + while True: + try: + cmd, data = self.remote_queue.get_nowait() + self.logger.warning("%r: %r" % (cmd, data)) except Empty: break diff --git a/tools/wptrunner/wptrunner/wptlogging.py b/tools/wptrunner/wptrunner/wptlogging.py index 4d320617859c5b..2118458a4695fe 100644 --- a/tools/wptrunner/wptrunner/wptlogging.py +++ b/tools/wptrunner/wptrunner/wptlogging.py @@ -1,6 +1,7 @@ import logging import sys import threading +from Queue import Empty from StringIO import StringIO from multiprocessing import Queue @@ -45,7 +46,6 @@ def __call__(self, data): return self.inner(data) - class LogThread(threading.Thread): def __init__(self, queue, logger, level): self.queue = queue @@ -120,5 +120,10 @@ def __exit__(self, *args, **kwargs): self.logging_queue.put(None) if self.logging_thread is not None: self.logging_thread.join(10) + while not self.logging_queue.empty(): + try: + self.logger.warning("Dropping log message: %r", self.logging_queue.get()) + except Exception: + pass self.logging_queue.close() self.logger.info("queue closed") diff --git a/wasm/wasm_local_iframe_test.html b/wasm/wasm_local_iframe_test.html index 9ccebdc75394a1..0f4fbd0c7191ec 100644 --- a/wasm/wasm_local_iframe_test.html +++ b/wasm/wasm_local_iframe_test.html @@ -2,16 +2,18 @@ - + diff --git a/web-animations/animation-model/animation-types/property-list.js b/web-animations/animation-model/animation-types/property-list.js index 46829c31495400..32bf63d3a82175 100644 --- a/web-animations/animation-model/animation-types/property-list.js +++ b/web-animations/animation-model/animation-types/property-list.js @@ -1054,12 +1054,6 @@ const gCSSProperties = { types: [ ] }, - 'overflow-clip-box': { - // https://developer.mozilla.org/en/docs/Web/CSS/overflow-clip-box - types: [ - { type: 'discrete', options: [ [ 'padding-box', 'content-box' ] ] } - ] - }, 'overflow-wrap': { // https://drafts.csswg.org/css-text-3/#propdef-overflow-wrap types: [ diff --git a/webdriver/interface/interface.html b/webdriver/interface/interface.html deleted file mode 100644 index f3c149b1cee06b..00000000000000 --- a/webdriver/interface/interface.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - diff --git a/webdriver/tests/cookies/add_cookie.py b/webdriver/tests/cookies/add_cookie.py index 86a5f86f374603..1ebbcb41de7125 100644 --- a/webdriver/tests/cookies/add_cookie.py +++ b/webdriver/tests/cookies/add_cookie.py @@ -1,15 +1,14 @@ from tests.support.fixtures import clear_all_cookies -from tests.support.fixtures import server_config from datetime import datetime, timedelta -def test_add_domain_cookie(session, url): +def test_add_domain_cookie(session, url, server_config): session.url = url("/common/blank.html") clear_all_cookies(session) create_cookie_request = { "cookie": { "name": "hello", "value": "world", - "domain": "web-platform.test", + "domain": server_config["domains"][""], "path": "/", "httpOnly": False, "secure": False @@ -37,16 +36,16 @@ def test_add_domain_cookie(session, url): assert cookie["name"] == "hello" assert cookie["value"] == "world" - assert cookie["domain"] == ".web-platform.test" + assert cookie["domain"] == ".%s" % server_config["domains"][""] -def test_add_cookie_for_ip(session, url, server_config): +def test_add_cookie_for_ip(session, url, server_config, configuration): session.url = "http://127.0.0.1:%s/404" % (server_config["ports"]["http"][0]) clear_all_cookies(session) create_cookie_request = { "cookie": { "name": "hello", "value": "world", - "domain": "127.0.0.1", + "domain": configuration["host"], "path": "/", "httpOnly": False, "secure": False @@ -142,3 +141,37 @@ def test_add_session_cookie(session, url): assert cookie["name"] == "hello" assert cookie["value"] == "world" + +def test_add_session_cookie_with_leading_dot_character_in_domain(session, url, server_config): + session.url = url("/common/blank.html") + clear_all_cookies(session) + create_cookie_request = { + "cookie": { + "name": "hello", + "value": "world", + "domain": ".%s" % server_config["domains"][""] + } + } + result = session.transport.send("POST", "session/%s/cookie" % session.session_id, create_cookie_request) + assert result.status == 200 + assert "value" in result.body + assert isinstance(result.body["value"], dict) + + result = session.transport.send("GET", "session/%s/cookie" % session.session_id) + assert result.status == 200 + assert "value" in result.body + assert isinstance(result.body["value"], list) + assert len(result.body["value"]) == 1 + assert isinstance(result.body["value"][0], dict) + + cookie = result.body["value"][0] + 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"] == ".%s" % server_config["domains"][""] diff --git a/webdriver/tests/cookies/get_named_cookie.py b/webdriver/tests/cookies/get_named_cookie.py index 027859dd7f9d12..f367eccf947ab6 100644 --- a/webdriver/tests/cookies/get_named_cookie.py +++ b/webdriver/tests/cookies/get_named_cookie.py @@ -61,14 +61,14 @@ def test_get_named_cookie(session, url): # convert from seconds since epoch assert datetime.utcfromtimestamp(cookie["expiry"]).strftime(utc_string_format) == a_year_from_now -def test_duplicated_cookie(session, url): +def test_duplicated_cookie(session, url, server_config): session.url = url("/common/blank.html") clear_all_cookies(session) create_cookie_request = { "cookie": { "name": "hello", "value": "world", - "domain": "web-platform.test", + "domain": server_config["domains"][""], "path": "/", "httpOnly": False, "secure": False @@ -79,7 +79,7 @@ def test_duplicated_cookie(session, url): assert "value" in result.body assert isinstance(result.body["value"], dict) - session.url = inline("") + session.url = inline("" % server_config["domains"][""]) result = session.transport.send("GET", "session/%s/cookie" % session.session_id) assert result.status == 200 assert "value" in result.body diff --git a/webdriver/tests/element_click/select.py b/webdriver/tests/element_click/select.py index 15c36fc454fa6c..ca5e498e72e32e 100644 --- a/webdriver/tests/element_click/select.py +++ b/webdriver/tests/element_click/select.py @@ -211,3 +211,15 @@ def test_out_of_view_multiple(session): last_option = options[-1] last_option.click() assert last_option.selected + + +def test_option_disabled(session): + session.url = inline(""" + """) + option = session.find.css("option", all=False) + assert not option.selected + + option.click() + assert not option.selected diff --git a/webdriver/tests/retrieval/__init__.py b/webdriver/tests/element_retrieval/__init__.py similarity index 100% rename from webdriver/tests/retrieval/__init__.py rename to webdriver/tests/element_retrieval/__init__.py diff --git a/webdriver/tests/retrieval/find_element.py b/webdriver/tests/element_retrieval/find_element.py similarity index 100% rename from webdriver/tests/retrieval/find_element.py rename to webdriver/tests/element_retrieval/find_element.py diff --git a/webdriver/tests/retrieval/find_element_from_element.py b/webdriver/tests/element_retrieval/find_element_from_element.py similarity index 100% rename from webdriver/tests/retrieval/find_element_from_element.py rename to webdriver/tests/element_retrieval/find_element_from_element.py diff --git a/webdriver/tests/retrieval/find_element_from_elements.py b/webdriver/tests/element_retrieval/find_element_from_elements.py similarity index 100% rename from webdriver/tests/retrieval/find_element_from_elements.py rename to webdriver/tests/element_retrieval/find_element_from_elements.py diff --git a/webdriver/tests/retrieval/find_elements.py b/webdriver/tests/element_retrieval/find_elements.py similarity index 100% rename from webdriver/tests/retrieval/find_elements.py rename to webdriver/tests/element_retrieval/find_elements.py diff --git a/webdriver/tests/interaction/element_clear.py b/webdriver/tests/interaction/element_clear.py index f9755f784e52bd..546dc18ef39584 100644 --- a/webdriver/tests/interaction/element_clear.py +++ b/webdriver/tests/interaction/element_clear.py @@ -1,185 +1,363 @@ import pytest + from tests.support.asserts import assert_error, assert_success from tests.support.inline import inline -def 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)) +@pytest.fixture(scope="session") +def text_file(tmpdir_factory): + fh = tmpdir_factory.mktemp("tmp").join("hello.txt") + fh.write("hello") + return fh -# 14.2 Element Clear +def element_clear(session, element): + return session.transport.send("POST", "/session/%s/element/%s/clear" % + (session.session_id, element.id)) -def test_no_browsing_context(session, create_window): - # 14.2 step 1 - session.url = inline("

This is not an editable paragraph.") - element = session.find.css("p", all=False) - session.window_handle = create_window() +def test_closed_context(session, create_window): + new_window = create_window() + session.window_handle = new_window + session.url = inline("") + element = session.find.css("input", all=False) session.close() - response = clear(session, element) + response = element_clear(session, element) assert_error(response, "no such window") -def test_element_not_found(session): - # 14.2 Step 2 - response = session.transport.send("POST", "session/{session_id}/element/{element_id}/clear" - .format(session_id=session.session_id, - element_id="box1")) +def test_connected_element(session): + session.url = inline("") + element = session.find.css("input", all=False) - assert_error(response, "no such element") + session.url = inline("") + response = element_clear(session, element) + assert_error(response, "stale element reference") -def test_element_not_editable(session): - # 14.2 Step 3 - session.url = inline("

This is not an editable paragraph.") +def test_pointer_interactable(session): + session.url = inline("") + element = session.find.css("input", all=False) - element = session.find.css("p", all=False) - response = clear(session, element) - assert_error(response, "invalid element state") + response = element_clear(session, element) + assert_error(response, "element not interactable") -def test_button_element_not_resettable(session): - # 14.2 Step 3 - session.url = inline("") +def test_keyboard_interactable(session): + session.url = inline(""" + +

+ + """) element = session.find.css("input", all=False) - response = clear(session, element) - assert_error(response, "invalid element state") + 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("" % (type, value)) + element = session.find.css("input", all=False) + assert element.property("value") == value + + response = element_clear(session, element) + assert_success(response) + assert element.property("value") == default + + +@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("" % type) + element = session.find.css("input", all=False) + + response = element_clear(session, element) + assert_error(response, "invalid element state") -def test_disabled_element_not_resettable(session): - # 14.2 Step 3 - session.url = inline("") +@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("" % type) element = session.find.css("input", all=False) - response = clear(session, element) + + response = element_clear(session, element) assert_error(response, "invalid element state") -def test_scroll_into_element_view(session): - # 14.2 Step 4 - session.url = inline("
") +def test_textarea(session): + session.url = inline("") + element = session.find.css("textarea", all=False) + assert element.property("value") == "foobar" - # Scroll to the bottom right of the page - session.execute_script("window.scrollTo(document.body.scrollWidth, document.body.scrollHeight);") - element = session.find.css("input", all=False) - # Clear and scroll back to the top of the page - response = clear(session, element) + response = element_clear(session, element) assert_success(response) + assert element.property("value") == "" - # Check if element cleared is scrolled into view - rect = session.execute_script("return document.getElementsByTagName(\"input\")[0].getBoundingClientRect()") - pageDict = {} +def test_textarea_disabled(session): + session.url = inline("") + element = session.find.css("textarea", all=False) - pageDict["innerHeight"] = session.execute_script("return window.innerHeight") - pageDict["innerWidth"] = session.execute_script("return window.innerWidth") - pageDict["pageXOffset"] = session.execute_script("return window.pageXOffset") - pageDict["pageYOffset"] = session.execute_script("return window.pageYOffset") + response = element_clear(session, element) + assert_error(response, "invalid element state") - assert rect["top"] < (pageDict["innerHeight"] + pageDict["pageYOffset"]) and \ - rect["left"] < (pageDict["innerWidth"] + pageDict["pageXOffset"]) and \ - (rect["top"] + element.rect["height"]) > pageDict["pageYOffset"] and \ - (rect["left"] + element.rect["width"]) > pageDict["pageXOffset"] +def test_textarea_readonly(session): + session.url = inline("") + element = session.find.css("textarea", all=False) -# TODO -# Any suggestions on implementation? -# def test_session_implicit_wait_timeout(session): - # 14.2 Step 5 + response = element_clear(session, element) + assert_error(response, "invalid element state") -# TODO -# Any suggestions on implementation? -# def test_element_not_interactable(session): -# # 14.2 Step 6 -# assert_error(response, "element not interactable") +def test_input_file(session, text_file): + session.url = inline("") + 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_element_readonly(session): - # 14.2 Step 7 - session.url = inline("") +def test_input_file_multiple(session, text_file): + session.url = inline("") element = session.find.css("input", all=False) - response = clear(session, element) + 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 = 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_element_disabled(session): - # 14.2 Step 7 - session.url = inline("") +def test_button(session): + session.url = inline("") + button = session.find.css("button", all=False) - element = session.find.css("input", all=False) - response = clear(session, element) + response = element_clear(session, button) assert_error(response, "invalid element state") -def test_element_pointer_events_disabled(session): - # 14.2 Step 7 - session.url = inline("") +def test_button_with_subtree(session): + """ + Whilst an is normally editable, the focusable area + where it is placed will default to the + """) + 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("

foobar

") + element = session.find.css("p", all=False) + assert element.property("innerHTML") == "foobar" + + response = element_clear(session, element) + assert_success(response) + assert element.property("innerHTML") == "" + + +def test_contenteditable_focus(session): + session.url = inline(""" +

foobar

+ + + """) + element = session.find.css("p", all=False) + assert element.property("innerHTML") == "foobar" + + response = element_clear(session, element) + assert_success(response) + assert element.property("innerHTML") == "" + assert session.execute_script("return window.events") == ["focus", "blur"] + + +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") == "
" + + +def test_resettable_element_focus(session): + session.url = inline(""" + + + + """) + element = session.find.css("input", all=False) + assert element.property("value") == "foobar" + + response = element_clear(session, element) + assert_success(response) + assert element.property("value") == "" + assert session.execute_script("return window.events") == ["focus", "blur"] + + +def test_resettable_element_focus_when_empty(session): + session.url = inline(""" + + + + """) element = session.find.css("input", all=False) - response = clear(session, element) + assert element.property("value") == "" + + response = element_clear(session, element) + assert_success(response) + assert element.property("value") == "" + assert session.execute_script("return window.events") == [] + + +@pytest.mark.parametrize("type", + ["checkbox", + "radio", + "hidden", + "submit", + "button", + "image"]) +def test_non_editable_inputs(session, type): + session.url = inline("" % type) + element = session.find.css("input", all=False) + + response = element_clear(session, element) assert_error(response, "invalid element state") -@pytest.mark.parametrize("element", [["text", ""], - ["search", ""], - ["url", ""], - ["tele", ""], - ["email", ""], - ["password", ""], - ["date", ""], - ["time", ""], - ["number", ""], - ["range", ""], - ["color", ""], - ["file", ""], - ["textarea", ""], - ["sel", ""], - ["out", ""], - ["para", "

This is an editable paragraph.

"]]) - -def test_clear_content_editable_resettable_element(session, element): - # 14.2 Step 8 - url = element[1] + """ - - """ % element[0] - session.url = inline(url) - # Step 1 - empty_element = session.find.css("#empty", all=False) - clear_element_test_helper(session, empty_element, False) - session.execute_script("document.getElementById(\"focusCheck\").checked = false;") - session.execute_script("document.getElementById(\"blurCheck\").checked = false;") - # Step 2 - 4 - test_element = session.find.css("#" + element[0], all=False) - clear_element_test_helper(session, test_element, True) - - -def clear_element_test_helper(session, element, value): - response = clear(session, element) +def test_scroll_into_view(session): + session.url = inline(""" + +
+ """) + element = session.find.css("input", all=False) + assert element.property("value") == "foobar" + assert session.execute_script("return window.scrollY") == 0 + + # scroll to the bottom right of the page + session.execute_script(""" + let {scrollWidth, scrollHeight} = document.body; + window.scrollTo(scrollWidth, scrollHeight); + """) + + # clear and scroll back to the top of the page + response = element_clear(session, element) assert_success(response) - response = session.execute_script("return document.getElementById(\"focusCheck\").checked;") - assert response is value - response = session.execute_script("return document.getElementById(\"blurCheck\").checked;") - assert response is value - if element.name == "p": - response = session.execute_script("return document.getElementById(\"para\").innerHTML;") - assert response == "" - else: - assert element.property("value") == "" + assert element.property("value") == "" + + # check if element cleared is scrolled into view + rect = session.execute_script(""" + let [input] = arguments; + return input.getBoundingClientRect(); + """, args=(element,)) + window = session.execute_script(""" + let {innerHeight, innerWidth, pageXOffset, pageYOffset} = window; + return {innerHeight, innerWidth, pageXOffset, 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"] diff --git a/webdriver/tests/state/get_element_attribute.py b/webdriver/tests/state/get_element_attribute.py index 1301a45a73c5dd..ce78e11d3ff22b 100644 --- a/webdriver/tests/state/get_element_attribute.py +++ b/webdriver/tests/state/get_element_attribute.py @@ -1,3 +1,5 @@ +# META: timeout=long + import pytest from tests.support.asserts import assert_error, assert_success, assert_dialog_handled diff --git a/webdriver/tests/state/get_element_property.py b/webdriver/tests/state/get_element_property.py index c76c56104628c9..e4da98e0c3facc 100644 --- a/webdriver/tests/state/get_element_property.py +++ b/webdriver/tests/state/get_element_property.py @@ -1,3 +1,5 @@ +# META: timeout=long + 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 diff --git a/webdriver/tests/state/get_element_tag_name.py b/webdriver/tests/state/get_element_tag_name.py index 2dd7528bb2092e..e3ed83f3f20ec7 100644 --- a/webdriver/tests/state/get_element_tag_name.py +++ b/webdriver/tests/state/get_element_tag_name.py @@ -1,3 +1,5 @@ +# META: timeout=long + 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 diff --git a/webdriver/tests/state/is_element_selected.py b/webdriver/tests/state/is_element_selected.py index 392929a582864a..b51ba020fa4cc3 100644 --- a/webdriver/tests/state/is_element_selected.py +++ b/webdriver/tests/state/is_element_selected.py @@ -1,3 +1,5 @@ +# META: timeout=long + 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