+
+
+
+
diff --git a/tests/wpt/web-platform-tests/css/css-contain/support/60x60-red.png b/tests/wpt/web-platform-tests/css/css-contain/support/60x60-red.png
deleted file mode 100644
index 823f125b8e4..00000000000
Binary files a/tests/wpt/web-platform-tests/css/css-contain/support/60x60-red.png and /dev/null differ
diff --git a/tests/wpt/web-platform-tests/css/css-writing-modes/img-intrinsic-size-contribution-001.html b/tests/wpt/web-platform-tests/css/css-writing-modes/img-intrinsic-size-contribution-001.html
new file mode 100644
index 00000000000..08500537f87
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-writing-modes/img-intrinsic-size-contribution-001.html
@@ -0,0 +1,19 @@
+
+
+CSS Test: intrinsic size contributions of images in vertical writing mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/css/css-writing-modes/img-intrinsic-size-contribution-002.html b/tests/wpt/web-platform-tests/css/css-writing-modes/img-intrinsic-size-contribution-002.html
new file mode 100644
index 00000000000..df0ccf2093b
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-writing-modes/img-intrinsic-size-contribution-002.html
@@ -0,0 +1,19 @@
+
+
+CSS Test: intrinsic size contributions of images in vertical writing mode (with the image itself in horizontal writing mode)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/css/css-writing-modes/img-intrinsic-size-contribution-ref.html b/tests/wpt/web-platform-tests/css/css-writing-modes/img-intrinsic-size-contribution-ref.html
new file mode 100644
index 00000000000..ffda7d62ba9
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-writing-modes/img-intrinsic-size-contribution-ref.html
@@ -0,0 +1,16 @@
+
+
+CSS Test Reference: intrinsic size contributions of images in vertical writing mode
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/web-platform-tests/css/css-writing-modes/support/blue-200x100.png b/tests/wpt/web-platform-tests/css/css-writing-modes/support/blue-200x100.png
new file mode 100644
index 00000000000..e32c47dd1ee
Binary files /dev/null and b/tests/wpt/web-platform-tests/css/css-writing-modes/support/blue-200x100.png differ
diff --git a/tests/wpt/web-platform-tests/docs/_writing-tests/testdriver.md b/tests/wpt/web-platform-tests/docs/_writing-tests/testdriver.md
index a934e3278f1..eb9b9fb0413 100644
--- a/tests/wpt/web-platform-tests/docs/_writing-tests/testdriver.md
+++ b/tests/wpt/web-platform-tests/docs/_writing-tests/testdriver.md
@@ -18,9 +18,11 @@ the global scope.
NB: presently, testdriver.js only works in the top-level test browsing
context (and not therefore in any frame or window opened from it).
-### `test_driver.bless(intent, action)`
-#### `intent: a string describing the motivation for this invocation`
-#### `action: an optional function`
+### bless
+
+Usage: `test_driver.bless(intent, action)`
+ * `intent`: a string describing the motivation for this invocation
+ * `action`: an optional function
This function simulates [activation][activation], allowing tests to
perform privileged operations that require user interaction. For
@@ -44,8 +46,10 @@ test_driver.bless('initiate media playback', function () {
});
```
-### `test_driver.click(element)`
-#### `element: a DOM Element object`
+### click
+
+Usage: `test_driver.click(element)`
+ * `element`: a DOM Element object
This function causes a click to occur on the target element (an
`Element` object), potentially scrolling the document to make it
@@ -57,9 +61,11 @@ Note that if the element to be clicked does not have a unique ID, the
document must not have any DOM mutations made between the function
being called and the promise settling.
-### `test_driver.send_keys(element, keys)`
-#### `element: a DOM Element object`
-#### `keys: string to send to the element`
+### send_keys
+
+Usage: `test_driver.send_keys(element, keys)`
+ * `element`: a DOM Element object
+ * `keys`: string to send to the element
This function causes the string `keys` to be send to the target
element (an `Element` object), potentially scrolling the document to
diff --git a/tests/wpt/web-platform-tests/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-auto-margins-ref.html b/tests/wpt/web-platform-tests/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-auto-margins-ref.html
new file mode 100644
index 00000000000..8b1258727fc
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-auto-margins-ref.html
@@ -0,0 +1,37 @@
+
+
+
+legend inline auto margins
+
+
+
+
+
+The details element is expected to render as a block box. The element's shadow
+tree is expected to take the element's first summary element child, if any, and
+place it in a first block box container, and then take the element's remaining
+descendants, if any, and place them in a second block box container.
+
+
+<details display:flex> should be ignored. Otherwise details would render as
+something other than a block box.
+
+
+
+ This is the summary.
+
+The details element is expected to render as a block box. The element's shadow
+tree is expected to take the element's first summary element child, if any, and
+place it in a first block box container, and then take the element's remaining
+descendants, if any, and place them in a second block box container.
+
+
+<details display:flex> should be ignored. Otherwise details would render as
+something other than a block box.
+
+
+
+ This is the summary.
+
thing 1
+ thing 2
+
diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/load-error-events-2.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/load-error-events-2.html
index cefa053e754..0748b459092 100644
--- a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/load-error-events-2.html
+++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/load-error-events-2.html
@@ -11,7 +11,7 @@
var test5_load = event_test('no src, parser-inserted, has style sheets blocking scripts, script nesting level == 1', false, false);
-
+
diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/load-error-events-3.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/load-error-events-3.html
index c2cf0dbdd98..83a752ce2cd 100644
--- a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/load-error-events-3.html
+++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/load-error-events-3.html
@@ -13,7 +13,7 @@ var test6_load = event_test('no src, parser-inserted, has style sheets blocking
false, false);
document.write(
- `
+ `
-
+
diff --git a/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/016-1.html b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/016-1.html
index 12990a56070..ceeeb64df63 100644
--- a/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/016-1.html
+++ b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/016-1.html
@@ -11,7 +11,7 @@ onload = function() {
setTimeout(function() {
parent.tests[0].step(function() {
- parent.assert_equals(test_prop, 1, "Global scope from original window timeout");
+ parent.assert_equals(test_prop, 2, "Global scope from original window timeout");
parent.assert_equals(window.test_prop, 2, "Window property from original window timeout")
});
parent.tests[1].step(function() {
@@ -23,7 +23,7 @@ onload = function() {
window.setTimeout(function() {
parent.tests[2].step(function() {
- parent.assert_equals(test_prop, 1, "Global scope from original window timeout");
+ parent.assert_equals(test_prop, 2, "Global scope from original window timeout");
parent.assert_equals(window.test_prop, 2, "Window property from original window timeout")
});
parent.tests[3].step(function() {
diff --git a/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-immediate.window.js b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-immediate.window.js
new file mode 100644
index 00000000000..8d045b9e0ab
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-immediate.window.js
@@ -0,0 +1,119 @@
+// The following tests deal with the pragma and the
+// `Refresh` header. The spec is still hazy on the precise behavior in those
+// cases but we use https://github.com/whatwg/html/issues/4003 as a guideline.
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+
+ const client = new frame.contentWindow.XMLHttpRequest();
+ client.open("GET", "/common/blank.html");
+ client.onabort = t.step_func_done();
+ client.send();
+
+ frame.contentDocument.open();
+ });
+ frame.src = "resources/meta-refresh.py?0";
+}, "document.open() aborts documents that are queued for navigation through refresh with timeout 0 (XMLHttpRequest)");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+
+ frame.contentWindow.fetch("/common/blank.html").then(
+ t.unreached_func("Fetch should have been aborted"),
+ t.step_func_done());
+
+ frame.contentDocument.open();
+ });
+ frame.src = "resources/meta-refresh.py?0";
+}, "document.open() aborts documents that are queued for navigation through refresh with timeout 0 (fetch())");
+
+// We cannot test for img element's error event for this test, as Firefox does
+// not fire the event if the fetch is aborted while Chrome does.
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+
+ let happened = false;
+ const img = frame.contentDocument.createElement("img");
+ img.src = new URL("resources/slow-png.py", document.URL);
+ img.onload = t.unreached_func("Image loading should not have succeeded");
+ // The image fetch starts in a microtask, so let's be sure to test after
+ // the fetch has started.
+ t.step_timeout(() => {
+ frame.contentDocument.open();
+ happened = true;
+ });
+ // If 3 seconds have passed and the image has still not loaded, we consider
+ // it aborted. slow-png.py only sleeps for 2 wallclock seconds.
+ t.step_timeout(t.step_func_done(() => {
+ assert_true(happened);
+ }), 3000);
+ });
+ frame.src = "resources/meta-refresh.py?0";
+}, "document.open() aborts documents that are queued for navigation through refresh with timeout 0 (image loading)");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+
+ const client = new frame.contentWindow.XMLHttpRequest();
+ client.open("GET", "/common/blank.html");
+ client.onabort = t.step_func_done();
+ client.send();
+
+ frame.contentDocument.open();
+ });
+ frame.src = "resources/http-refresh.py?0";
+}, "document.open() aborts documents that are queued for navigation through Refresh header with timeout 0 (XMLHttpRequest)");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+
+ frame.contentWindow.fetch("/common/blank.html").then(
+ t.unreached_func("Fetch should have been aborted"),
+ t.step_func_done());
+
+ frame.contentDocument.open();
+ });
+ frame.src = "resources/http-refresh.py?0";
+}, "document.open() aborts documents that are queued for navigation through Refresh header with timeout 0 (fetch())");
+
+// We cannot test for img element's error event for this test, as Firefox does
+// not fire the event if the fetch is aborted while Chrome does.
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+
+ let happened = false;
+ const img = frame.contentDocument.createElement("img");
+ img.src = new URL("resources/slow-png.py", document.URL);
+ img.onload = t.unreached_func("Image loading should not have succeeded");
+ // The image fetch starts in a microtask, so let's be sure to test after
+ // the fetch has started.
+ t.step_timeout(() => {
+ frame.contentDocument.open();
+ happened = true;
+ });
+ // If 3 seconds have passed and the image has still not loaded, we consider
+ // it aborted. slow-png.py only sleeps for 2 wallclock seconds.
+ t.step_timeout(t.step_func_done(() => {
+ assert_true(happened);
+ }), 3000);
+ });
+ frame.src = "resources/http-refresh.py?0";
+}, "document.open() aborts documents that are queued for navigation through Refresh header with timeout 0 (image loading)");
diff --git a/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-multisecond-header.window.js b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-multisecond-header.window.js
new file mode 100644
index 00000000000..8c6c1267c4e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-multisecond-header.window.js
@@ -0,0 +1,69 @@
+// The following tests deal with the pragma and the
+// `Refresh` header. The spec is still hazy on the precise behavior in those
+// cases but we use https://github.com/whatwg/html/issues/4003 as a guideline.
+//
+// This is separate from abort-refresh-multisecond-meta.window.js to avoid
+// browser interventions that limit the number of connections in a tab.
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+
+ const client = new frame.contentWindow.XMLHttpRequest();
+ client.open("GET", "/common/blank.html");
+ client.onload = t.step_func_done(() => {
+ assert_true(happened);
+ });
+ client.onerror = t.unreached_func("XMLHttpRequest should have succeeded");
+ client.onabort = t.unreached_func("XMLHttpRequest should have succeeded");
+ client.ontimeout = t.unreached_func("XMLHttpRequest should have succeeded");
+ client.send();
+
+ frame.contentDocument.open();
+ happened = true;
+ });
+ frame.src = "resources/http-refresh.py?1";
+}, "document.open() does NOT abort documents that are queued for navigation through Refresh header with 1-sec timeout (XMLHttpRequest)");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+ frame.contentWindow.fetch("/common/blank.html").then(
+ t.step_func_done(() => {
+ assert_true(happened);
+ }),
+ t.unreached_func("Fetch should have succeeded")
+ );
+ frame.contentDocument.open();
+ happened = true;
+ });
+ frame.src = "resources/http-refresh.py?1";
+}, "document.open() does NOT abort documents that are queued for navigation through Refresh header with 1-sec timeout (fetch())");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+ const img = frame.contentDocument.createElement("img");
+ img.src = new URL("resources/slow-png.py", document.URL);
+ img.onload = t.step_func_done(() => {
+ assert_true(happened);
+ });
+ img.onerror = t.unreached_func("Image loading should not have errored");
+ // The image fetch starts in a microtask, so let's be sure to test after
+ // the fetch has started.
+ t.step_timeout(() => {
+ frame.contentDocument.open();
+ happened = true;
+ });
+ });
+ frame.src = "resources/http-refresh.py?4";
+}, "document.open() does NOT abort documents that are queued for navigation through Refresh header with 4-sec timeout (image loading)");
diff --git a/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-multisecond-meta.window.js b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-multisecond-meta.window.js
new file mode 100644
index 00000000000..2895f959e55
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-multisecond-meta.window.js
@@ -0,0 +1,69 @@
+// The following tests deal with the pragma and the
+// `Refresh` header. The spec is still hazy on the precise behavior in those
+// cases but we use https://github.com/whatwg/html/issues/4003 as a guideline.
+//
+// This is separate from abort-refresh-multisecond-header.window.js to avoid
+// browser interventions that limit the number of connections in a tab.
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+
+ const client = new frame.contentWindow.XMLHttpRequest();
+ client.open("GET", "/common/blank.html");
+ client.onload = t.step_func_done(() => {
+ assert_true(happened);
+ });
+ client.onerror = t.unreached_func("XMLHttpRequest should have succeeded");
+ client.onabort = t.unreached_func("XMLHttpRequest should have succeeded");
+ client.ontimeout = t.unreached_func("XMLHttpRequest should have succeeded");
+ client.send();
+
+ frame.contentDocument.open();
+ happened = true;
+ });
+ frame.src = "resources/meta-refresh.py?1";
+}, "document.open() does NOT abort documents that are queued for navigation through refresh with 1-sec timeout (XMLHttpRequest)");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+ frame.contentWindow.fetch("/common/blank.html").then(
+ t.step_func_done(() => {
+ assert_true(happened);
+ }),
+ t.unreached_func("Fetch should have succeeded")
+ );
+ frame.contentDocument.open();
+ happened = true;
+ });
+ frame.src = "resources/meta-refresh.py?1";
+}, "document.open() does NOT abort documents that are queued for navigation through refresh with 1-sec timeout (fetch())");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+ const img = frame.contentDocument.createElement("img");
+ img.src = new URL("resources/slow-png.py", document.URL);
+ img.onload = t.step_func_done(() => {
+ assert_true(happened);
+ });
+ img.onerror = t.unreached_func("Image loading should not have errored");
+ // The image fetch starts in a microtask, so let's be sure to test after
+ // the fetch has started.
+ t.step_timeout(() => {
+ frame.contentDocument.open();
+ happened = true;
+ });
+ });
+ frame.src = "resources/meta-refresh.py?4";
+}, "document.open() does NOT abort documents that are queued for navigation through refresh with 4-sec timeout (image loading)");
diff --git a/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-while-navigating.window.js b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-while-navigating.window.js
new file mode 100644
index 00000000000..e3efeffb8b3
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-while-navigating.window.js
@@ -0,0 +1,179 @@
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ const client = new frame.contentWindow.XMLHttpRequest();
+ client.open("GET", "/common/blank.html");
+ // The abort event handler is called synchronously in Chrome but
+ // asynchronously in Firefox. See https://crbug.com/879620.
+ client.onabort = t.step_func_done();
+ client.send();
+ frame.contentWindow.location.href = new URL("resources/dummy.html", document.URL);
+ frame.contentDocument.open();
+ });
+ frame.src = "/common/blank.html";
+}, "document.open() aborts documents that are navigating through Location (XMLHttpRequest)");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+ frame.contentWindow.fetch("/common/blank.html").then(
+ t.unreached_func("Fetch should have been aborted"),
+ t.step_func_done(() => {
+ assert_true(happened);
+ }));
+ frame.contentWindow.location.href = new URL("resources/dummy.html", document.URL);
+ frame.contentDocument.open();
+ happened = true;
+ });
+ frame.src = "/common/blank.html";
+}, "document.open() aborts documents that are navigating through Location (fetch())");
+
+// We cannot test for img element's error event for this test, as Firefox does
+// not fire the event if the fetch is aborted while Chrome does.
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+ const img = frame.contentDocument.createElement("img");
+ img.src = new URL("resources/slow-png.py", document.URL);
+ img.onload = t.unreached_func("Image loading should not have succeeded");
+ // The image fetch starts in a microtask, so let's be sure to test after
+ // the fetch has started.
+ t.step_timeout(() => {
+ frame.contentWindow.location.href = new URL("resources/dummy.html", document.URL);
+ frame.contentDocument.open();
+ happened = true;
+ });
+ // If 3 seconds have passed and the image has still not loaded, we consider
+ // it aborted. slow-png.py only sleeps for 2 wallclock seconds.
+ t.step_timeout(t.step_func_done(() => {
+ assert_true(happened);
+ }), 3000);
+ });
+ frame.src = "/common/blank.html";
+}, "document.open() aborts documents that are navigating through Location (image loading)");
+
+async_test(t => {
+ const div = document.body.appendChild(document.createElement("div"));
+ t.add_cleanup(() => div.remove());
+ div.innerHTML = "";
+ const frame = div.childNodes[0];
+ const client = new frame.contentWindow.XMLHttpRequest();
+ client.open("GET", "/common/blank.html");
+ client.onabort = t.step_func_done();
+ client.send();
+ frame.contentDocument.open();
+}, "document.open() aborts documents that are navigating through iframe loading (XMLHttpRequest)");
+
+async_test(t => {
+ const div = document.body.appendChild(document.createElement("div"));
+ t.add_cleanup(() => div.remove());
+ div.innerHTML = "";
+ const frame = div.childNodes[0];
+ frame.contentWindow.fetch("/common/blank.html").then(
+ t.unreached_func("Fetch should have been aborted"),
+ t.step_func_done());
+ frame.contentDocument.open();
+}, "document.open() aborts documents that are navigating through iframe loading (fetch())");
+
+// We cannot test for img element's error event for this test, as Firefox does
+// not fire the event if the fetch is aborted while Chrome does.
+//
+// We use /common/slow.py here as the source of the iframe, to prevent the
+// situation where when document.open() is called the initial about:blank
+// document has already become inactive.
+async_test(t => {
+ const div = document.body.appendChild(document.createElement("div"));
+ t.add_cleanup(() => div.remove());
+ div.innerHTML = "";
+ const frame = div.childNodes[0];
+ let happened = false;
+ const img = frame.contentDocument.createElement("img");
+ img.src = new URL("resources/slow-png.py", document.URL);
+ img.onload = t.unreached_func("Image loading should not have succeeded");
+ // The image fetch starts in a microtask, so let's be sure to test after
+ // the fetch has started.
+ t.step_timeout(() => {
+ frame.contentDocument.open();
+ happened = true;
+ });
+ // If 3 seconds have passed and the image has still not loaded, we consider
+ // it aborted. slow-png.py only sleeps for 2 wallclock seconds.
+ t.step_timeout(t.step_func_done(() => {
+ assert_true(happened);
+ }), 3000);
+}, "document.open() aborts documents that are navigating through iframe loading (image loading)");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ const link = frame.contentDocument.body.appendChild(frame.contentDocument.createElement("a"));
+ link.href = new URL("resources/dummy.html", document.URL);
+
+ const client = new frame.contentWindow.XMLHttpRequest();
+ client.open("GET", "/common/blank.html");
+ client.onabort = t.step_func_done();
+ client.send();
+
+ link.click();
+ frame.contentDocument.open();
+ });
+ frame.src = "/common/blank.html";
+}, "document.open() aborts documents that are queued for navigation through .click() (XMLHttpRequest)");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ const link = frame.contentDocument.body.appendChild(frame.contentDocument.createElement("a"));
+ link.href = new URL("resources/dummy.html", document.URL);
+
+ frame.contentWindow.fetch("/common/blank.html").then(
+ t.unreached_func("Fetch should have been aborted"),
+ t.step_func_done());
+
+ link.click();
+ frame.contentDocument.open();
+ });
+ frame.src = "/common/blank.html";
+}, "document.open() aborts documents that are queued for navigation through .click() (fetch())");
+
+// We cannot test for img element's error event for this test, as Firefox does
+// not fire the event if the fetch is aborted while Chrome does.
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ const link = frame.contentDocument.body.appendChild(frame.contentDocument.createElement("a"));
+ link.href = new URL("resources/dummy.html", document.URL);
+
+ let happened = false;
+ const img = frame.contentDocument.createElement("img");
+ img.src = new URL("resources/slow-png.py", document.URL);
+ img.onload = t.unreached_func("Image loading should not have succeeded");
+ // The image fetch starts in a microtask, so let's be sure to test after
+ // the fetch has started.
+ t.step_timeout(() => {
+ link.click();
+ frame.contentDocument.open();
+ happened = true;
+ });
+ // If 3 seconds have passed and the image has still not loaded, we consider
+ // it aborted. slow-png.py only sleeps for 2 wallclock seconds.
+ t.step_timeout(t.step_func_done(() => {
+ assert_true(happened);
+ }), 3000);
+ });
+ frame.src = "/common/blank.html";
+}, "document.open() aborts documents that are queued for navigation through .click() (image loading)");
diff --git a/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort.sub.window.js b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort.sub.window.js
new file mode 100644
index 00000000000..b2f05cf056d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort.sub.window.js
@@ -0,0 +1,104 @@
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+ const client = new frame.contentWindow.XMLHttpRequest();
+ client.open("GET", "/common/blank.html");
+ client.onload = t.step_func_done(e => {
+ assert_true(happened);
+ });
+ client.onerror = t.unreached_func("XMLHttpRequest should have succeeded");
+ client.onabort = t.unreached_func("XMLHttpRequest should have succeeded");
+ client.ontimeout = t.unreached_func("XMLHttpRequest should have succeeded");
+ client.send();
+ frame.contentDocument.open();
+ happened = true;
+ });
+ frame.src = "/common/blank.html";
+}, "document.open() does not abort documents that are not navigating (XMLHttpRequest)");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+ frame.contentWindow.fetch("/common/blank.html").then(
+ t.step_func_done(() => {
+ assert_true(happened);
+ }),
+ t.unreached_func("Fetch should have succeeded")
+ );
+ frame.contentDocument.open();
+ happened = true;
+ });
+ frame.src = "/common/blank.html";
+}, "document.open() does not abort documents that are not navigating (fetch())");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+ const img = frame.contentDocument.createElement("img");
+ img.src = new URL("resources/slow-png.py", document.URL);
+ img.onload = t.step_func_done(() => {
+ assert_true(happened);
+ });
+ img.onerror = t.unreached_func("Image loading should not have errored");
+ // The image fetch starts in a microtask, so let's be sure to test after
+ // the fetch has started.
+ t.step_timeout(() => {
+ frame.contentDocument.open();
+ happened = true;
+ });
+ });
+ frame.src = "/common/blank.html";
+}, "document.open() does not abort documents that are not navigating (image loading)");
+
+async_test(t => {
+ const __SERVER__NAME = "{{host}}";
+ const __PORT = {{ports[ws][0]}};
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+ const ws = new frame.contentWindow.WebSocket(`ws://${__SERVER__NAME}:${__PORT}/echo`);
+ ws.onopen = t.step_func_done(() => {
+ assert_true(happened);
+ });
+ ws.onclose = t.unreached_func("WebSocket fetch should have succeeded");
+ ws.onerror = t.unreached_func("WebSocket should have no error");
+ frame.contentDocument.open();
+ happened = true;
+ });
+ frame.src = "/common/blank.html";
+}, "document.open() does not abort documents that are not navigating (establish a WebSocket connection)");
+
+// An already established WebSocket connection shouldn't be terminated during
+// an "abort a document" anyway. Test just for completeness.
+async_test(t => {
+ const __SERVER__NAME = "{{host}}";
+ const __PORT = {{ports[ws][0]}};
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+ const ws = new frame.contentWindow.WebSocket(`ws://${__SERVER__NAME}:${__PORT}/echo`);
+ ws.onopen = t.step_func(() => {
+ t.step_timeout(t.step_func_done(() => {
+ assert_true(happened);
+ }), 100);
+ frame.contentDocument.open();
+ happened = true;
+ });
+ ws.onclose = t.unreached_func("WebSocket should not be closed");
+ ws.onerror = t.unreached_func("WebSocket should have no error");
+ });
+ frame.src = "/common/blank.html";
+}, "document.open() does not abort documents that are not navigating (already established WebSocket connection)");
diff --git a/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/mutation-observer.window.js b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/mutation-observer.window.js
new file mode 100644
index 00000000000..34e73146a9d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/mutation-observer.window.js
@@ -0,0 +1,19 @@
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => { frame.remove(); });
+ const originalHTMLElement = frame.contentDocument.documentElement;
+ assert_equals(originalHTMLElement.localName, "html");
+ const observer = new frame.contentWindow.MutationObserver(t.step_func_done(records => {
+ // Even though we passed `subtree: true` to observer.observe, due to the
+ // fact that "replace all" algorithm removes children with the "suppress
+ // observers flag" set, we still only get the html element as the sole
+ // removed node.
+ assert_equals(records.length, 1);
+ assert_equals(records[0].type, "childList");
+ assert_equals(records[0].target, frame.contentDocument);
+ assert_array_equals(records[0].addedNodes, []);
+ assert_array_equals(records[0].removedNodes, [originalHTMLElement]);
+ }));
+ observer.observe(frame.contentDocument, { childList: true, subtree: true });
+ assert_equals(frame.contentDocument.open(), frame.contentDocument);
+}, "document.open() should inform mutation observer of node removal");
diff --git a/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/reload.window.js b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/reload.window.js
index d6ff9dc7a45..279020f64da 100644
--- a/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/reload.window.js
+++ b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/reload.window.js
@@ -12,16 +12,16 @@
// that restriction.
//
// In any case, this test as the caller of `document.open()` would be used both
-// as the test file and as part of the test file. The `if (!opener)` condition
-// controls what role this file plays.
+// as the test file and as part of the test file. The `if (window.name !==
+// "opened-dummy-window")` condition controls what role this file plays.
-if (!opener) {
+if (window.name !== "opened-dummy-window") {
async_test(t => {
const testURL = document.URL;
const dummyURL = new URL("resources/dummy.html", document.URL).href;
// 1. Open an auxiliary window.
- const win = window.open("resources/dummy.html");
+ const win = window.open("resources/dummy.html", "opened-dummy-window");
t.add_cleanup(() => { win.close(); });
win.addEventListener("load", t.step_func(() => {
diff --git a/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/http-refresh.py b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/http-refresh.py
new file mode 100644
index 00000000000..d2acd4361f9
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/http-refresh.py
@@ -0,0 +1,3 @@
+def main(request, response):
+ time = request.url_parts.query if request.url_parts.query else '0'
+ return 200, [['Refresh', time]], ''
diff --git a/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/meta-refresh.py b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/meta-refresh.py
new file mode 100644
index 00000000000..dd3cef44b44
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/meta-refresh.py
@@ -0,0 +1,5 @@
+import time
+
+def main(request, response):
+ time = request.url_parts.query if request.url_parts.query else '0'
+ return 200, [['Content-Type', 'text/html']], '' % time
diff --git a/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/slow-png.py b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/slow-png.py
new file mode 100644
index 00000000000..5fa2fd9a9d8
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/slow-png.py
@@ -0,0 +1,8 @@
+from base64 import decodestring
+import time
+
+png_response = decodestring('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVR4nGNiAAAABgADNjd8qAAAAABJRU5ErkJggg==')
+
+def main(request, response):
+ time.sleep(2)
+ return 200, [], png_response
diff --git a/tests/wpt/web-platform-tests/interfaces/trusted-types.tentative.idl b/tests/wpt/web-platform-tests/interfaces/trusted-types.tentative.idl
new file mode 100644
index 00000000000..a3a635b9927
--- /dev/null
+++ b/tests/wpt/web-platform-tests/interfaces/trusted-types.tentative.idl
@@ -0,0 +1,53 @@
+// https://github.com/wicg/trusted-types
+
+typedef (DOMString or TrustedHTML) HTMLString;
+typedef (DOMString or TrustedScript) ScriptString;
+typedef (DOMString or TrustedScriptURL) ScriptURLString;
+typedef (USVString or TrustedURL) URLString;
+
+[Exposed=Window]
+interface TrustedHTML {
+ stringifier;
+};
+
+[Exposed=Window]
+interface TrustedScript {
+ stringifier;
+};
+
+[Exposed=Window]
+interface TrustedScriptURL {
+ stringifier;
+};
+
+[Exposed=Window]
+interface TrustedURL {
+ stringifier;
+};
+
+[Exposed=Window]
+interface TrustedTypePolicyFactory {
+ TrustedTypePolicy createPolicy(DOMString policyName, TrustedTypePolicyOptions policyOptions);
+ // All the policy object names that have been created
+ sequence getPolicyNames();
+};
+
+[Exposed=Window]
+interface TrustedTypePolicy {
+ readonly attribute DOMString name;
+ TrustedHTML createHTML(DOMString input);
+ TrustedScript createScript(DOMString input);
+ TrustedScriptURL createScriptURL(DOMString input);
+ TrustedURL createURL(DOMString input);
+};
+
+dictionary TrustedTypePolicyOptions {
+ CreateHTMLCallback createHTML;
+ CreateScriptCallback createScript;
+ CreateURLCallback createScriptURL;
+ CreateURLCallback createURL;
+};
+
+callback CreateHTMLCallback = DOMString (DOMString input);
+callback CreateScriptCallback = DOMString (DOMString input);
+callback CreateURLCallback = USVString (DOMString input);
diff --git a/tests/wpt/web-platform-tests/payment-request/payment-response/onpayerdetailchange-attribute.manual.https.html b/tests/wpt/web-platform-tests/payment-request/payment-response/onpayerdetailchange-attribute.manual.https.html
index 9f92d284063..c8dd92636c6 100644
--- a/tests/wpt/web-platform-tests/payment-request/payment-response/onpayerdetailchange-attribute.manual.https.html
+++ b/tests/wpt/web-platform-tests/payment-request/payment-response/onpayerdetailchange-attribute.manual.https.html
@@ -13,7 +13,7 @@ function runTest(button, options, expected){
response.addEventListener("payerdetailchange", resolve);
});
const error = button.previousElementSibling.textContent.trim();
- const retryPromise = response.retry({ error });
+ await response.retry({ error });
const event = await eventPromise;
assert_true(event instanceof PaymentRequestUpdateEvent);
for(const [prop, value] of Object.entries(expected)){
diff --git a/tests/wpt/web-platform-tests/tools/ci/check_stability.py b/tests/wpt/web-platform-tests/tools/ci/check_stability.py
index 684f7a51894..2b32eb50c0f 100644
--- a/tests/wpt/web-platform-tests/tools/ci/check_stability.py
+++ b/tests/wpt/web-platform-tests/tools/ci/check_stability.py
@@ -266,8 +266,7 @@ def run(venv, wpt_args, **kwargs):
do_delayed_imports()
wpt_kwargs["prompt"] = False
- wpt_kwargs["install_browser"] = True
- wpt_kwargs["install"] = wpt_kwargs["product"].split(":")[0] == "firefox"
+ wpt_kwargs["install_browser"] = wpt_kwargs["product"].split(":")[0] == "firefox"
wpt_kwargs["pause_after_test"] = False
wpt_kwargs["verify_log_full"] = False
diff --git a/tests/wpt/web-platform-tests/tools/ci/ci_resources_unittest.sh b/tests/wpt/web-platform-tests/tools/ci/ci_resources_unittest.sh
index 78868b93433..a13c60fbd8c 100755
--- a/tests/wpt/web-platform-tests/tools/ci/ci_resources_unittest.sh
+++ b/tests/wpt/web-platform-tests/tools/ci/ci_resources_unittest.sh
@@ -17,7 +17,7 @@ main() {
export PATH=$HOME/firefox:$PATH
cd $WPT_ROOT/resources/test
- tox -- --binary=$HOME/browsers/firefox/firefox
+ tox -- --binary=$HOME/browsers/nightly/firefox/firefox
}
main
diff --git a/tests/wpt/web-platform-tests/tools/ci/ci_taskcluster.sh b/tests/wpt/web-platform-tests/tools/ci/ci_taskcluster.sh
index 118243881a9..546055293d7 100755
--- a/tests/wpt/web-platform-tests/tools/ci/ci_taskcluster.sh
+++ b/tests/wpt/web-platform-tests/tools/ci/ci_taskcluster.sh
@@ -3,8 +3,8 @@
./wpt manifest-download
if [ $1 == "firefox" ]; then
- ./wpt run firefox --log-tbpl=../artifacts/log_tbpl.log --log-tbpl-level=info --log-wptreport=../artifacts/wpt_report.json --log-mach=- --this-chunk=$3 --total-chunks=$4 --test-type=$2 -y --install-browser --no-pause --no-restart-on-unexpected --reftest-internal --install-fonts --no-fail-on-unexpected
+ ./wpt run firefox --log-tbpl=../artifacts/log_tbpl.log --log-tbpl-level=info --log-wptreport=../artifacts/wpt_report.json --log-mach=- --this-chunk=$4 --total-chunks=$5 --test-type=$3 -y --install-browser --channel=$2 --no-pause --no-restart-on-unexpected --reftest-internal --install-fonts --no-fail-on-unexpected
elif [ $1 == "chrome" ]; then
- ./wpt run chrome --log-tbpl=../artifacts/log_tbpl.log --log-tbpl-level=info --log-wptreport=../artifacts/wpt_report.json --log-mach=- --this-chunk=$3 --total-chunks=$4 --test-type=$2 -y --no-pause --no-restart-on-unexpected --install-fonts --no-fail-on-unexpected
+ ./wpt run chrome --log-tbpl=../artifacts/log_tbpl.log --log-tbpl-level=info --log-wptreport=../artifacts/wpt_report.json --log-mach=- --channel=$2 --this-chunk=$4 --total-chunks=$5 --test-type=$3 -y --no-pause --no-restart-on-unexpected --install-fonts --no-fail-on-unexpected
fi
gzip ../artifacts/wpt_report.json
diff --git a/tests/wpt/web-platform-tests/tools/ci/commands.json b/tests/wpt/web-platform-tests/tools/ci/commands.json
index 0f8f5823699..361c9e4f3de 100644
--- a/tests/wpt/web-platform-tests/tools/ci/commands.json
+++ b/tests/wpt/web-platform-tests/tools/ci/commands.json
@@ -1,7 +1,42 @@
{
- "test-jobs": {"path": "jobs.py", "script": "run", "parser": "create_parser", "help": "List test jobs that should run for a set of commits",
- "virtualenv": false},
- "check-stability": {"path": "check_stability.py", "script": "run", "parser": "get_parser", "parse_known": true, "help": "Check test stability",
- "virtualenv": true, "install": ["requests"], "requirements": ["../wptrunner/requirements.txt"]},
- "make-hosts-file": {"path": "make_hosts_file.py", "script": "run", "parser": "create_parser", "help": "Output a hosts file to stdout", "virtualenv": false}
+ "test-jobs": {
+ "path": "jobs.py",
+ "script": "run",
+ "parser": "create_parser",
+ "help": "List test jobs that should run for a set of commits",
+ "virtualenv": false
+ },
+ "check-stability": {
+ "path": "check_stability.py",
+ "script": "run",
+ "parser": "get_parser",
+ "parse_known": true,
+ "help": "Check test stability",
+ "virtualenv": true,
+ "install": [
+ "requests"
+ ],
+ "requirements": [
+ "../wptrunner/requirements.txt"
+ ]
+ },
+ "make-hosts-file": {
+ "path": "make_hosts_file.py",
+ "script": "run",
+ "parser": "create_parser",
+ "help": "Output a hosts file to stdout",
+ "virtualenv": false
+ },
+ "tc-download": {
+ "path": "tcdownload.py",
+ "script": "run",
+ "parser": "get_parser",
+ "parse_known": true,
+ "help": "Download logs from taskcluster",
+ "virtualenv": true,
+ "install": [
+ "requests",
+ "pygithub"
+ ]
+ }
}
diff --git a/tests/wpt/web-platform-tests/tools/ci/tcdownload.py b/tests/wpt/web-platform-tests/tools/ci/tcdownload.py
new file mode 100644
index 00000000000..8813dccc888
--- /dev/null
+++ b/tests/wpt/web-platform-tests/tools/ci/tcdownload.py
@@ -0,0 +1,95 @@
+import argparse
+import os
+import logging
+
+import requests
+
+import github
+
+
+logging.basicConfig()
+logger = logging.getLogger("tc-download")
+
+
+def get_parser():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--ref", action="store", default="master",
+ help="Branch (in the GitHub repository) or commit to fetch logs for")
+ parser.add_argument("--artifact-name", action="store", default="wpt_report.json.gz",
+ help="Log type to fetch")
+ parser.add_argument("--repo-name", action="store", default="web-platform-tests/wpt",
+ help="GitHub repo name in the format owner/repo. "
+ "This must be the repo from which the TaskCluster run was scheduled "
+ "(for PRs this is the repo into which the PR would merge)")
+ parser.add_argument("--token-file", action="store",
+ help="File containing GitHub token")
+ parser.add_argument("--out-dir", action="store", default=".",
+ help="Path to save the logfiles")
+ return parser
+
+
+def get_json(url, key=None):
+ resp = requests.get(url)
+ resp.raise_for_status()
+ data = resp.json()
+ if key:
+ data = data[key]
+ return data
+
+
+def get(url, dest, name):
+ resp = requests.get(url)
+ resp.raise_for_status()
+ path = os.path.join(dest, name)
+ with open(path, "w") as f:
+ f.write(resp.content)
+ return path
+
+
+def run(*args, **kwargs):
+ if not os.path.exists(kwargs["out_dir"]):
+ os.mkdir(kwargs["out_dir"])
+
+ if kwargs["token_file"]:
+ with open(kwargs["token_file"]) as f:
+ gh = github.Github(f.read().strip())
+ else:
+ gh = github.Github()
+
+ repo = gh.get_repo(kwargs["repo_name"])
+ commit = repo.get_commit(kwargs["ref"])
+ statuses = commit.get_statuses()
+ taskgroups = set()
+
+ for status in statuses:
+ if not status.context.startswith("Taskcluster "):
+ continue
+ if status.state == "pending":
+ continue
+ taskgroup_id = status.target_url.rsplit("/", 1)[1]
+ taskgroups.add(taskgroup_id)
+
+ if not taskgroups:
+ logger.error("No complete TaskCluster runs found for ref %s" % kwargs["ref"])
+ return
+
+ for taskgroup in taskgroups:
+ taskgroup_url = "https://queue.taskcluster.net/v1/task-group/%s/list"
+ artifacts_list_url = "https://queue.taskcluster.net/v1/task/%s/artifacts"
+ tasks = get_json(taskgroup_url % taskgroup, "tasks")
+ for task in tasks:
+ task_id = task["status"]["taskId"]
+ url = artifacts_list_url % (task_id,)
+ for artifact in get_json(url, "artifacts"):
+ if artifact["name"].endswith(kwargs["artifact_name"]):
+ filename = "%s-%s-%s" % (task["task"]["metadata"]["name"],
+ task_id,
+ kwargs["artifact_name"])
+ path = get("%s/%s" % (url, artifact["name"]), kwargs["out_dir"], filename)
+ logger.info(path)
+
+
+def __main__():
+ kwargs = get_parser().parse_args()
+
+ run(None, vars(kwargs))
diff --git a/tests/wpt/web-platform-tests/tools/docker/start.sh b/tests/wpt/web-platform-tests/tools/docker/start.sh
index 3325bb24f58..c2fd91d96d4 100755
--- a/tests/wpt/web-platform-tests/tools/docker/start.sh
+++ b/tests/wpt/web-platform-tests/tools/docker/start.sh
@@ -15,6 +15,7 @@ REMOTE=${1:-https://github.com/web-platform-tests/wpt}
BRANCH=${2:-master}
REV=${3:-FETCH_HEAD}
BROWSER=${4:-all}
+CHANNEL=${5:-nightly}
cd ~
@@ -32,10 +33,22 @@ git checkout -b build ${REV}
sudo sh -c './wpt make-hosts-file >> /etc/hosts'
-if [[ $BROWSER == "chrome"* ]] || [[ "$BROWSER" == all ]]
+if [[ $BROWSER == "chrome" ]] || [[ "$BROWSER" == all ]]
then
# Install Chrome dev
- deb_archive=google-chrome-unstable_current_amd64.deb
+ if [[ "$CHANNEL" == "dev" ]] || [[ "$CHANNEL" == "nightly" ]]
+ then
+ deb_archive=google-chrome-unstable_current_amd64.deb
+ elif [[ "$CHANNEL" == "beta" ]]
+ then
+ deb_archive=google-chrome-beta_current_amd64.deb
+ elif [[ "$CHANNEL" == "stable" ]]
+ then
+ deb_archive=google-chrome-stable_current_amd64.deb
+ else
+ echo Unrecognized release channel: $CHANNEL >&2
+ exit 1
+ fi
wget https://dl.google.com/linux/direct/$deb_archive
sudo apt-get -qqy update && sudo gdebi -n $deb_archive
diff --git a/tests/wpt/web-platform-tests/tools/wpt/browser.py b/tests/wpt/web-platform-tests/tools/wpt/browser.py
index 9834e5d53f3..65752a25f12 100644
--- a/tests/wpt/web-platform-tests/tools/wpt/browser.py
+++ b/tests/wpt/web-platform-tests/tools/wpt/browser.py
@@ -26,12 +26,12 @@ class Browser(object):
return NotImplemented
@abstractmethod
- def install_webdriver(self, dest=None):
+ def install_webdriver(self, dest=None, channel=None):
"""Install the WebDriver implementation for this browser."""
return NotImplemented
@abstractmethod
- def find_binary(self):
+ def find_binary(self, venv_path=None, channel=None):
"""Find the binary of the browser.
If the WebDriver for the browser is able to find the binary itself, this
@@ -84,9 +84,27 @@ class Firefox(Browser):
return "%s%s" % (platform, bits)
- def install(self, dest=None):
+ def install(self, dest=None, channel="nightly"):
"""Install Firefox."""
+ branch = {
+ "nightly": "mozilla-central",
+ "beta": "mozilla-beta",
+ "stable": "mozilla-stable"
+ }
+ scraper = {
+ "nightly": "daily",
+ "beta": "release",
+ "stable": "release"
+ }
+ version = {
+ "stable": "latest",
+ "beta": "latest-beta",
+ "nightly": "latest"
+ }
+ if channel not in branch:
+ raise ValueError("Unrecognised release channel: %s" % channel)
+
from mozdownload import FactoryScraper
import mozinstall
@@ -103,9 +121,12 @@ class Firefox(Browser):
# os.getcwd() doesn't include the venv path
dest = os.path.join(os.getcwd(), "_venv")
- dest = os.path.join(dest, "browsers")
+ dest = os.path.join(dest, "browsers", channel)
- filename = FactoryScraper("daily", branch="mozilla-central", destination=dest).download()
+ filename = FactoryScraper(scraper[channel],
+ branch=branch[channel],
+ version=version[channel],
+ destination=dest).download()
try:
mozinstall.install(filename, dest)
@@ -146,11 +167,14 @@ class Firefox(Browser):
return binary
- def find_binary(self, venv_path=None):
+ def find_binary(self, venv_path=None, channel=None):
if venv_path is None:
venv_path = os.path.join(os.getcwd(), "_venv")
- binary = self.find_binary_path(os.path.join(venv_path, "browsers"))
+ path = os.path.join(venv_path, "browsers")
+ if channel is not None:
+ path = os.path.join(path, channel)
+ binary = self.find_binary_path(path)
if not binary and uname[0] == "Darwin":
macpaths = ["/Applications/FirefoxNightly.app/Contents/MacOS",
@@ -190,6 +214,18 @@ class Firefox(Browser):
if channel == "stable":
repo = "https://hg.mozilla.org/releases/mozilla-release"
tag = "FIREFOX_%s_RELEASE" % version.replace(".", "_")
+ elif channel == "beta":
+ repo = "https://hg.mozilla.org/releases/mozilla-beta"
+ major_version = version.split(".", 1)[0]
+ # For beta we have a different format for betas that are now in stable releases
+ # vs those that are not
+ tags = get("https://hg.mozilla.org/releases/mozilla-beta/json-tags").json()["tags"]
+ tags = {item["tag"] for item in tags}
+ end_tag = "FIREFOX_BETA_%s_END" % major_version
+ if end_tag in tags:
+ tag = end_tag
+ else:
+ tag = "tip"
else:
repo = "https://hg.mozilla.org/mozilla-central"
if channel == "beta":
@@ -202,8 +238,14 @@ class Firefox(Browser):
return "%s/archive/%s.zip/testing/profiles/" % (repo, tag)
- def install_prefs(self, binary, dest=None):
- version, channel = self.get_version_and_channel(binary)
+ def install_prefs(self, binary, dest=None, channel=None):
+ version, channel_ = self.get_version_and_channel(binary)
+ if channel is not None and channel != channel_:
+ # Beta doesn't always seem to have the b in the version string, so allow the
+ # manually supplied value to override the one from the binary
+ logger.warning("Supplied channel doesn't match binary, using supplied channel")
+ elif channel is None:
+ channel = channel_
if dest is None:
dest = os.pwd
@@ -257,11 +299,18 @@ class Firefox(Browser):
assert latest_release != 0
return "v%s.%s.%s" % tuple(str(item) for item in latest_release)
- def install_webdriver(self, dest=None):
+ def install_webdriver(self, dest=None, channel=None):
"""Install latest Geckodriver."""
if dest is None:
dest = os.getcwd()
+ if channel == "nightly":
+ path = self.install_geckodriver_nightly(dest)
+ if path is not None:
+ return path
+ else:
+ logger.warning("Nightly webdriver not found; falling back to release")
+
version = self._latest_geckodriver_version()
format = "zip" if uname[0] == "Windows" else "tar.gz"
logger.debug("Latest geckodriver release %s" % version)
@@ -273,9 +322,39 @@ class Firefox(Browser):
untar(get(url).raw, dest=dest)
return find_executable(os.path.join(dest, "geckodriver"))
- def version(self, binary=None):
+ def install_geckodriver_nightly(self, dest):
+ import tarfile
+ import mozdownload
+ logger.info("Attempting to install webdriver from nightly")
+ try:
+ s = mozdownload.DailyScraper(branch="mozilla-central",
+ extension="common.tests.tar.gz",
+ destination=dest)
+ package_path = s.download()
+ except mozdownload.errors.NotFoundError:
+ return
+
+ try:
+ exe_suffix = ".exe" if uname[0] == "Windows" else ""
+ with tarfile.open(package_path, "r") as f:
+ try:
+ member = f.getmember("bin%sgeckodriver%s" % (os.path.sep,
+ exe_suffix))
+ except KeyError:
+ return
+ # Remove bin/ from the path.
+ member.name = os.path.basename(member.name)
+ f.extractall(members=[member], path=dest)
+ path = os.path.join(dest, member.name)
+ logger.info("Extracted geckodriver to %s" % path)
+ finally:
+ os.unlink(package_path)
+
+ return path
+
+ def version(self, binary=None, channel=None):
"""Retrieve the release version of the installed browser."""
- binary = binary or self.find_binary()
+ binary = binary or self.find_binary(channel)
version_string = call(binary, "--version").strip()
m = re.match(r"Mozilla Firefox (.*)", version_string)
if not m:
@@ -289,16 +368,16 @@ class Fennec(Browser):
product = "fennec"
requirements = "requirements_firefox.txt"
- def install(self, dest=None):
+ def install(self, dest=None, channel=None):
raise NotImplementedError
- def find_binary(self, venv_path=None):
+ def find_binary(self, venv_path=None, channel=None):
raise NotImplementedError
def find_webdriver(self):
raise NotImplementedError
- def install_webdriver(self, dest=None):
+ def install_webdriver(self, dest=None, channel=None):
raise NotImplementedError
def version(self, binary=None):
@@ -324,7 +403,7 @@ class Chrome(Browser):
logger.warn("Unable to find the browser binary.")
return None
- def install(self, dest=None):
+ def install(self, dest=None, channel=None):
raise NotImplementedError
def platform_string(self):
@@ -346,13 +425,13 @@ class Chrome(Browser):
return "%s%s" % (platform, bits)
- def find_binary(self):
+ def find_binary(self, venv_path=None, channel=None):
raise NotImplementedError
def find_webdriver(self):
return find_executable("chromedriver")
- def install_webdriver(self, dest=None):
+ def install_webdriver(self, dest=None, channel=None):
if dest is None:
dest = os.pwd
latest = get("http://chromedriver.storage.googleapis.com/LATEST_RELEASE").text.strip()
@@ -391,18 +470,18 @@ class ChromeAndroid(Browser):
product = "chrome_android"
requirements = "requirements_chrome_android.txt"
- def install(self, dest=None):
+ def install(self, dest=None, channel=None):
raise NotImplementedError
- def find_binary(self):
+ def find_binary(self, venv_path=None, channel=None):
raise NotImplementedError
def find_webdriver(self):
return find_executable("chromedriver")
- def install_webdriver(self, dest=None):
+ def install_webdriver(self, dest=None, channel=None):
chrome = Chrome()
- return chrome.install_webdriver(dest)
+ return chrome.install_webdriver(dest, channel)
def version(self, binary):
return None
@@ -425,7 +504,7 @@ class Opera(Browser):
logger.warn("Unable to find the browser binary.")
return None
- def install(self, dest=None):
+ def install(self, dest=None, channel=None):
raise NotImplementedError
def platform_string(self):
@@ -447,13 +526,13 @@ class Opera(Browser):
return "%s%s" % (platform, bits)
- def find_binary(self):
+ def find_binary(self, venv_path=None, channel=None):
raise NotImplementedError
def find_webdriver(self):
return find_executable("operadriver")
- def install_webdriver(self, dest=None):
+ def install_webdriver(self, dest=None, channel=None):
if dest is None:
dest = os.pwd
latest = get("https://api.github.com/repos/operasoftware/operachromiumdriver/releases/latest").json()["tag_name"]
@@ -487,16 +566,16 @@ class Edge(Browser):
product = "edge"
requirements = "requirements_edge.txt"
- def install(self, dest=None):
+ def install(self, dest=None, channel=None):
raise NotImplementedError
- def find_binary(self):
+ def find_binary(self, venv_path=None, channel=None):
raise NotImplementedError
def find_webdriver(self):
return find_executable("MicrosoftWebDriver")
- def install_webdriver(self, dest=None):
+ def install_webdriver(self, dest=None, channel=None):
raise NotImplementedError
def version(self, binary):
@@ -509,16 +588,16 @@ class InternetExplorer(Browser):
product = "ie"
requirements = "requirements_ie.txt"
- def install(self, dest=None):
+ def install(self, dest=None, channel=None):
raise NotImplementedError
- def find_binary(self):
+ def find_binary(self, venv_path=None, channel=None):
raise NotImplementedError
def find_webdriver(self):
return find_executable("IEDriverServer.exe")
- def install_webdriver(self, dest=None):
+ def install_webdriver(self, dest=None, channel=None):
raise NotImplementedError
def version(self, binary):
@@ -534,16 +613,16 @@ class Safari(Browser):
product = "safari"
requirements = "requirements_safari.txt"
- def install(self, dest=None):
+ def install(self, dest=None, channel=None):
raise NotImplementedError
- def find_binary(self):
+ def find_binary(self, venv_path=None, channel=None):
raise NotImplementedError
def find_webdriver(self):
return find_executable("safaridriver")
- def install_webdriver(self):
+ def install_webdriver(self, dest=None, channel=None):
raise NotImplementedError
def version(self, binary):
@@ -574,8 +653,10 @@ class Servo(Browser):
return (platform, extension, decompress)
- def install(self, dest=None):
+ def install(self, dest=None, channel="nightly"):
"""Install latest Browser Engine."""
+ if channel != "nightly":
+ raise ValueError("Only nightly versions of Servo are available")
if dest is None:
dest = os.pwd
@@ -588,13 +669,16 @@ class Servo(Browser):
os.chmod(path, st.st_mode | stat.S_IEXEC)
return path
- def find_binary(self):
- return find_executable("servo")
+ def find_binary(self, venv_path=None, channel=None):
+ path = find_executable("servo", os.path.join(venv_path, "servo"))
+ if path is None:
+ path = find_executable("servo")
+ return path
def find_webdriver(self):
return None
- def install_webdriver(self, dest=None):
+ def install_webdriver(self, dest=None, channel=None):
raise NotImplementedError
def version(self, binary):
@@ -609,16 +693,16 @@ class Sauce(Browser):
product = "sauce"
requirements = "requirements_sauce.txt"
- def install(self, dest=None):
+ def install(self, dest=None, channel=None):
raise NotImplementedError
- def find_binary(self):
+ def find_binary(self, venev_path=None, channel=None):
raise NotImplementedError
def find_webdriver(self):
raise NotImplementedError
- def install_webdriver(self, dest=None):
+ def install_webdriver(self, dest=None, channel=None):
raise NotImplementedError
def version(self, binary):
@@ -631,16 +715,16 @@ class WebKit(Browser):
product = "webkit"
requirements = "requirements_webkit.txt"
- def install(self, dest=None):
+ def install(self, dest=None, channel=None):
raise NotImplementedError
- def find_binary(self, path=None):
+ def find_binary(self, venv_path=None, channel=None):
return None
def find_webdriver(self):
return None
- def install_webdriver(self):
+ def install_webdriver(self, dest=None, channel=None):
raise NotImplementedError
def version(self, binary):
diff --git a/tests/wpt/web-platform-tests/tools/wpt/install.py b/tests/wpt/web-platform-tests/tools/wpt/install.py
index d779651c990..62c833aa3f0 100644
--- a/tests/wpt/web-platform-tests/tools/wpt/install.py
+++ b/tests/wpt/web-platform-tests/tools/wpt/install.py
@@ -2,20 +2,62 @@ import argparse
import browser
import sys
+
+latest_channels = {
+ 'firefox': 'nightly',
+ 'chrome': 'dev',
+ 'servo': 'nightly'
+}
+
+channel_by_name = {
+ 'stable': 'stable',
+ 'release': 'stable',
+ 'beta': 'beta',
+ 'nightly': latest_channels,
+ 'dev': latest_channels,
+ 'preview': latest_channels,
+ 'experimental': latest_channels,
+}
+
+
def get_parser():
- parser = argparse.ArgumentParser()
- parser.add_argument('browser', choices=['firefox', 'chrome'],
+ parser = argparse.ArgumentParser(description="""Install a given browser or webdriver frontend.
+
+ For convenience the release channel of the browser accepts various spellings,
+ but we actually support at most three variants; whatever the latest development
+ release is (e.g. Firefox nightly or Chrome dev), the latest beta release, and
+ the most recent stable release.""")
+ parser.add_argument('browser', choices=['firefox', 'chrome', 'servo'],
help='name of web browser product')
parser.add_argument('component', choices=['browser', 'webdriver'],
help='name of component')
+ parser.add_argument('--channel', choices=channel_by_name.keys(),
+ default="nightly", help='Name of browser release channel. '
+ '"stable" and "release" are synonyms for the latest browser stable release,'
+ '"nightly", "dev", "experimental", and "preview" are all synonyms for '
+ 'the latest available development release. For WebDriver installs, '
+ 'we attempt to select an appropriate, compatible, version for the '
+ 'latest browser release on the selected channel.')
parser.add_argument('-d', '--destination',
help='filesystem directory to place the component')
return parser
+def get_channel(browser, channel):
+ channel = channel_by_name[channel]
+ if isinstance(channel, dict):
+ channel = channel[browser]
+ return channel
+
+
def run(venv, **kwargs):
browser = kwargs["browser"]
destination = kwargs["destination"]
+ channel = get_channel(browser, kwargs["channel"])
+
+ if channel != kwargs["channel"]:
+ print "Interpreting channel '%s' as '%s'" % (kwargs["channel"],
+ channel)
if destination is None:
if venv:
@@ -27,10 +69,10 @@ def run(venv, **kwargs):
raise argparse.ArgumentError(None,
"No --destination argument, and no default for the environment")
- install(browser, kwargs["component"], destination)
+ install(browser, kwargs["component"], destination, channel)
-def install(name, component, destination):
+def install(name, component, destination, channel="nightly"):
if component == 'webdriver':
method = 'install_webdriver'
else:
@@ -38,4 +80,6 @@ def install(name, component, destination):
subclass = getattr(browser, name.title())
sys.stdout.write('Now installing %s %s...\n' % (name, component))
- getattr(subclass(), method)(dest=destination)
+ path = getattr(subclass(), method)(dest=destination, channel=channel)
+ if path:
+ sys.stdout.write('Binary installed as %s\n' % (path,))
diff --git a/tests/wpt/web-platform-tests/tools/wpt/run.py b/tests/wpt/web-platform-tests/tools/wpt/run.py
index aeeb22be961..036c38f2586 100644
--- a/tests/wpt/web-platform-tests/tools/wpt/run.py
+++ b/tests/wpt/web-platform-tests/tools/wpt/run.py
@@ -7,7 +7,7 @@ from distutils.spawn import find_executable
wpt_root = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
sys.path.insert(0, os.path.abspath(os.path.join(wpt_root, "tools")))
-from . import browser, utils, virtualenv
+from . import browser, install, utils, virtualenv
from ..serve import serve
logger = None
@@ -47,7 +47,15 @@ def create_parser():
parser.add_argument("--yes", "-y", dest="prompt", action="store_false", default=True,
help="Don't prompt before installing components")
parser.add_argument("--install-browser", action="store_true",
- help="Install the latest development version of the browser")
+ help="Install the browser")
+ parser.add_argument("--channel", action="store",
+ choices=install.channel_by_name.keys(),
+ default=None, help='Name of browser release channel.'
+ '"stable" and "release" are synonyms for the latest browser stable release,'
+ '"nightly", "dev", "experimental", and "preview" are all synonyms for '
+ 'the latest available development release. For WebDriver installs, '
+ 'we attempt to select an appropriate, compatible, version for the '
+ 'latest browser release on the selected channel.')
parser._add_container_actions(wptcommandline.create_parser())
return parser
@@ -150,9 +158,9 @@ class BrowserSetup(object):
elif resp == "n":
return False
- def install(self, venv):
+ def install(self, venv, channel=None):
if self.prompt_install(self.name):
- return self.browser.install(venv.path)
+ return self.browser.install(venv.path, channel)
def install_requirements(self):
self.venv.install_requirements(os.path.join(wpt_root, "tools", "wptrunner", self.browser.requirements))
@@ -167,7 +175,8 @@ class Firefox(BrowserSetup):
def setup_kwargs(self, kwargs):
if kwargs["binary"] is None:
- binary = self.browser.find_binary(self.venv.path)
+ binary = self.browser.find_binary(self.venv.path,
+ kwargs["browser_channel"])
if binary is None:
raise WptrunError("""Firefox binary not found on $PATH.
@@ -205,7 +214,9 @@ Consider installing certutil via your OS package manager or directly.""")
kwargs["test_types"].remove("wdspec")
if kwargs["prefs_root"] is None:
- prefs_root = self.browser.install_prefs(kwargs["binary"], self.venv.path)
+ prefs_root = self.browser.install_prefs(kwargs["binary"],
+ self.venv.path,
+ channel=kwargs["browser_channel"])
kwargs["prefs_root"] = prefs_root
@@ -290,7 +301,7 @@ class Edge(BrowserSetup):
name = "edge"
browser_cls = browser.Edge
- def install(self, venv):
+ def install(self, venv, channel=None):
raise NotImplementedError
def setup_kwargs(self, kwargs):
@@ -311,7 +322,7 @@ class InternetExplorer(BrowserSetup):
name = "ie"
browser_cls = browser.InternetExplorer
- def install(self, venv):
+ def install(self, venv, channel=None):
raise NotImplementedError
def setup_kwargs(self, kwargs):
@@ -332,7 +343,7 @@ class Safari(BrowserSetup):
name = "safari"
browser_cls = browser.Safari
- def install(self, venv):
+ def install(self, venv, channel=None):
raise NotImplementedError
def setup_kwargs(self, kwargs):
@@ -349,7 +360,7 @@ class Sauce(BrowserSetup):
name = "sauce"
browser_cls = browser.Sauce
- def install(self, venv):
+ def install(self, venv, channel=None):
raise NotImplementedError
def setup_kwargs(self, kwargs):
@@ -362,13 +373,13 @@ class Servo(BrowserSetup):
name = "servo"
browser_cls = browser.Servo
- def install(self, venv):
+ def install(self, venv, channel=None):
if self.prompt_install(self.name):
return self.browser.install(venv.path)
def setup_kwargs(self, kwargs):
if kwargs["binary"] is None:
- binary = self.browser.find_binary()
+ binary = self.browser.find_binary(self.venv.path, None)
if binary is None:
raise WptrunError("Unable to find servo binary on the PATH")
@@ -379,7 +390,7 @@ class WebKit(BrowserSetup):
name = "webkit"
browser_cls = browser.WebKit
- def install(self, venv):
+ def install(self, venv, channel=None):
raise NotImplementedError
def setup_kwargs(self, kwargs):
@@ -401,7 +412,7 @@ product_setup = {
}
-def setup_wptrunner(venv, prompt=True, install=False, **kwargs):
+def setup_wptrunner(venv, prompt=True, install_browser=False, **kwargs):
from wptrunner import wptrunner, wptcommandline
global logger
@@ -424,9 +435,20 @@ def setup_wptrunner(venv, prompt=True, install=False, **kwargs):
setup_cls = product_setup[kwargs["product"]](venv, prompt, sub_product)
setup_cls.install_requirements()
- if install:
+ if install_browser and not kwargs["channel"]:
+ kwargs["channel"] = "nightly"
+
+ if kwargs["channel"]:
+ channel = install.get_channel(kwargs["product"], kwargs["channel"])
+ if channel != kwargs["channel"]:
+ logger.info("Interpreting channel '%s' as '%s'" % (kwargs["channel"],
+ channel))
+ kwargs["browser_channel"] = channel
+ del kwargs["channel"]
+
+ if install_browser:
logger.info("Installing browser")
- kwargs["binary"] = setup_cls.install(venv)
+ kwargs["binary"] = setup_cls.install(venv, channel=channel)
setup_cls.setup(kwargs)
@@ -447,7 +469,7 @@ def run(venv, **kwargs):
kwargs = setup_wptrunner(venv,
prompt=prompt,
- install=install_browser,
+ install_browser=install_browser,
**kwargs)
rv = run_single(venv, **kwargs) > 0
diff --git a/tests/wpt/web-platform-tests/tools/wpt/tests/test_wpt.py b/tests/wpt/web-platform-tests/tools/wpt/tests/test_wpt.py
index b39173e64f2..8f8e5186c7c 100644
--- a/tests/wpt/web-platform-tests/tools/wpt/tests/test_wpt.py
+++ b/tests/wpt/web-platform-tests/tools/wpt/tests/test_wpt.py
@@ -166,9 +166,9 @@ def test_run_firefox(manifest_dir):
os.environ["MOZ_HEADLESS"] = "1"
try:
if sys.platform == "darwin":
- fx_path = os.path.join(wpt.localpaths.repo_root, "_venv", "browsers", "Firefox Nightly.app")
+ fx_path = os.path.join(wpt.localpaths.repo_root, "_venv", "browsers", "nightly", "Firefox Nightly.app")
else:
- fx_path = os.path.join(wpt.localpaths.repo_root, "_venv", "browsers", "firefox")
+ fx_path = os.path.join(wpt.localpaths.repo_root, "_venv", "browsers", "nightly", "firefox")
if os.path.exists(fx_path):
shutil.rmtree(fx_path)
with pytest.raises(SystemExit) as excinfo:
@@ -294,15 +294,14 @@ def test_install_chromedriver():
@pytest.mark.xfail(sys.platform == "win32",
reason="Tests currently don't work on Windows for path reasons")
def test_install_firefox():
-
if sys.platform == "darwin":
- fx_path = os.path.join(wpt.localpaths.repo_root, "_venv", "browsers", "Firefox Nightly.app")
+ fx_path = os.path.join(wpt.localpaths.repo_root, "_venv", "browsers", "nightly", "Firefox Nightly.app")
else:
- fx_path = os.path.join(wpt.localpaths.repo_root, "_venv", "browsers", "firefox")
+ fx_path = os.path.join(wpt.localpaths.repo_root, "_venv", "browsers", "nightly", "firefox")
if os.path.exists(fx_path):
shutil.rmtree(fx_path)
with pytest.raises(SystemExit) as excinfo:
- wpt.main(argv=["install", "firefox", "browser"])
+ wpt.main(argv=["install", "firefox", "browser", "--channel=nightly"])
assert excinfo.value.code == 0
assert os.path.exists(fx_path)
shutil.rmtree(fx_path)
diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptcommandline.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptcommandline.py
index 4af5367a038..e6c624994d9 100644
--- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptcommandline.py
+++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptcommandline.py
@@ -192,6 +192,12 @@ scheme host and port.""")
help="Path to directory containing extra json files to add to run info")
config_group.add_argument("--product", action="store", choices=product_choices,
default=None, help="Browser against which to run tests")
+ config_group.add_argument("--browser-version", action="store",
+ default=None, help="Informative string detailing the browser "
+ "release version. This is included in the run_info data.")
+ config_group.add_argument("--browser-channel", action="store",
+ default=None, help="Informative string detailing the browser "
+ "release channel. This is included in the run_info data.")
config_group.add_argument("--config", action="store", type=abs_path, dest="config",
help="Path to config file")
config_group.add_argument("--install-fonts", action="store_true",
diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptrunner.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptrunner.py
index 02420826d8a..a6a29724ad7 100644
--- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptrunner.py
+++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptrunner.py
@@ -47,6 +47,7 @@ def get_loader(test_paths, product, debug=None, run_info_extras=None, **kwargs):
run_info = wpttest.get_run_info(kwargs["run_info"], product,
browser_version=kwargs.get("browser_version"),
+ browser_channel=kwargs.get("browser_channel"),
debug=debug,
extras=run_info_extras)
diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wpttest.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wpttest.py
index c29ba974a99..4086a89e4cf 100644
--- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wpttest.py
+++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wpttest.py
@@ -67,7 +67,10 @@ def get_run_info(metadata_root, product, **kwargs):
class RunInfo(dict):
- def __init__(self, metadata_root, product, debug, browser_version=None, extras=None):
+ def __init__(self, metadata_root, product, debug,
+ browser_version=None,
+ browser_channel=None,
+ extras=None):
import mozinfo
self._update_mozinfo(metadata_root)
self.update(mozinfo.info)
@@ -89,6 +92,8 @@ class RunInfo(dict):
self["debug"] = False
if browser_version:
self["browser_version"] = browser_version
+ if browser_channel:
+ self["browser_channel"] = browser_channel
if extras is not None:
self.update(extras)
diff --git a/tests/wpt/web-platform-tests/trusted-types/idlharness.window.js b/tests/wpt/web-platform-tests/trusted-types/idlharness.window.js
new file mode 100644
index 00000000000..de13697764e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/trusted-types/idlharness.window.js
@@ -0,0 +1,18 @@
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+
+idl_test(
+ ['trusted-types.tentative'],
+ ['dom', 'html'],
+ idl_array => {
+ idl_array.add_objects({
+ TrustedTypePolicyFactory: ['window.TrustedTypes'],
+ TrustedTypePolicy: ['window.TrustedTypes.createPolicy("SomeName", { createHTML: s => s })'],
+ TrustedHTML: ['window.TrustedTypes.createPolicy("SomeName1", { createHTML: s => s }).createHTML("A string")'],
+ TrustedScript: ['window.TrustedTypes.createPolicy("SomeName2", { createScript: s => s }).createScript("A string")'],
+ TrustedScriptURL: ['window.TrustedTypes.createPolicy("SomeName3", { createScriptURL: s => s }).createScriptURL("A string")'],
+ TrustedURL: ['window.TrustedTypes.createPolicy("SomeName4", { createURL: s => s }).createURL("A string")']
+ });
+ },
+ 'Trusted Types'
+);
diff --git a/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/property-types.js b/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/property-types.js
index 5bafb20dfcf..232a508e07c 100644
--- a/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/property-types.js
+++ b/tests/wpt/web-platform-tests/web-animations/animation-model/animation-types/property-types.js
@@ -1068,6 +1068,23 @@ const transformListType = {
{ time: 500, expected: [ 1, 1, 1, 1, 100, 100 ] },
{ time: 1000, expected: [ 1, 1, 1, 1, 100, 100 ] }]);
}, `${property}: non-invertible matrices in mismatched transform lists`);
+
+ test(t => {
+ const idlName = propertyToIDL(property);
+ const target = createTestElement(t, setup);
+ const animation = target.animate(
+ {
+ [idlName]: ['perspective(0)', 'perspective(10px)'],
+ },
+ 1000
+ );
+ testAnimationSampleMatrices(animation, idlName,
+ [{ time: 500, expected: [ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, -0.05,
+ 0, 0, 0, 1 ] }]);
+ }, `${property}: perspective`);
+
},
testAddition: function(property, setup) {
diff --git a/tests/wpt/web-platform-tests/webaudio/the-audio-api/the-oscillatornode-interface/detune-limiting.html b/tests/wpt/web-platform-tests/webaudio/the-audio-api/the-oscillatornode-interface/detune-limiting.html
new file mode 100644
index 00000000000..81a1293d035
--- /dev/null
+++ b/tests/wpt/web-platform-tests/webaudio/the-audio-api/the-oscillatornode-interface/detune-limiting.html
@@ -0,0 +1,154 @@
+
+
+
+
+ Oscillator Detune Limits
+
+
+
+
+
+
+
+
+
+