Merge pull request #9414 from w3c/gwhit-css-1959
Test for font-variation-settings
diff --git a/2dcontext/drawing-images-to-the-canvas/2d.drawImage.zerocanvas.html b/2dcontext/drawing-images-to-the-canvas/2d.drawImage.zerocanvas.html
index 5f1c7fa..1621c03 100644
--- a/2dcontext/drawing-images-to-the-canvas/2d.drawImage.zerocanvas.html
+++ b/2dcontext/drawing-images-to-the-canvas/2d.drawImage.zerocanvas.html
@@ -8,34 +8,29 @@
<body class="show_output">
<h1>2d.drawImage.zerocanvas</h1>
-<p class="desc"></p>
+<p class="desc">drawImage with zero-sized canvas as the source shoud throw exception</p>
<p class="output">Actual output:</p>
<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
-<p class="output expectedtext">Expected output:<p><img src="/images/green-100x50.png" class="output expected" id="expected" alt="">
+
<ul id="d"></ul>
<script>
-var t = async_test("");
+var t = async_test("drawImage with zero-sized canvas as the source shoud throw exception");
_addTest(function(canvas, ctx) {
-ctx.fillStyle = '#0f0';
-ctx.fillRect(0, 0, 100, 50);
-
var canvas2 = document.createElement('canvas');
canvas2.width = 0;
-canvas2.height = 10;
-ctx.drawImage(canvas2, 0, 0);
+canvas2.height = 50;
+assert_throws("INVALID_STATE_ERR", function() { ctx.drawImage(canvas2, 0, 0); });
-canvas2.width = 10;
+canvas2.width = 50;
canvas2.height = 0;
-ctx.drawImage(canvas2, 0, 0);
+assert_throws("INVALID_STATE_ERR", function() { ctx.drawImage(canvas2, 0, 0); });
canvas2.width = 0;
canvas2.height = 0;
-ctx.drawImage(canvas2, 0, 0);
-
-_assertPixelApprox(canvas, 50,25, 0,255,0,255, "50,25", "0,255,0,255", 2);
+assert_throws("INVALID_STATE_ERR", function() { ctx.drawImage(canvas2, 0, 0); });
});
diff --git a/2dcontext/tools/spec.yaml b/2dcontext/tools/spec.yaml
index 278dc95..e57bbc8 100644
--- a/2dcontext/tools/spec.yaml
+++ b/2dcontext/tools/spec.yaml
@@ -586,7 +586,7 @@
text: "If the image argument is <...> an HTMLVideoElement object whose readyState attribute is either HAVE_NOTHING or HAVE_METADATA<^>, then the implementation *must* return without drawing anything."
- id: 2d.drawImage.zerocanvas
previously: [ 10, "dw and dh" ]
- text: "If the image argument is an HTMLCanvasElement object with either a horizontal dimension or a vertical dimension equal to zero, then the implementation *must* return without drawing anything<^>."
+ text: "If the image argument is an HTMLCanvasElement or an OffscreenCanvas object with either a horizontal dimension or a vertical dimension equal to zero, then the implementation *must* throw an INVALID_STATE_ERR exception<^>."
- id: 2d.drawImage.zerosource
text: "If one of the sw or sh arguments is zero<^>, the implementation *must* return without drawing anything."
- id: 2d.drawImage.paint
diff --git a/2dcontext/tools/tests2d.yaml b/2dcontext/tools/tests2d.yaml
index 7da08f9..f7b858a 100644
--- a/2dcontext/tools/tests2d.yaml
+++ b/2dcontext/tools/tests2d.yaml
@@ -9002,27 +9002,22 @@
expected: green
- name: 2d.drawImage.zerocanvas
+ desc: drawImage with zero-sized canvas as the source shoud throw exception
testing:
- 2d.drawImage.zerocanvas
code: |
- ctx.fillStyle = '#0f0';
- ctx.fillRect(0, 0, 100, 50);
-
var canvas2 = document.createElement('canvas');
canvas2.width = 0;
- canvas2.height = 10;
- ctx.drawImage(canvas2, 0, 0);
+ canvas2.height = 50;
+ @assert throws INVALID_STATE_ERR ctx.drawImage(canvas2, 0, 0);
- canvas2.width = 10;
+ canvas2.width = 50;
canvas2.height = 0;
- ctx.drawImage(canvas2, 0, 0);
+ @assert throws INVALID_STATE_ERR ctx.drawImage(canvas2, 0, 0);
canvas2.width = 0;
canvas2.height = 0;
- ctx.drawImage(canvas2, 0, 0);
-
- @assert pixel 50,25 ==~ 0,255,0,255;
- expected: green
+ @assert throws INVALID_STATE_ERR ctx.drawImage(canvas2, 0, 0);
- name: 2d.drawImage.svg
desc: drawImage() of an SVG image
diff --git a/IndexedDB/interleaved-cursors.html b/IndexedDB/interleaved-cursors-common.js
similarity index 93%
rename from IndexedDB/interleaved-cursors.html
rename to IndexedDB/interleaved-cursors-common.js
index 3112690..a76ec52 100644
--- a/IndexedDB/interleaved-cursors.html
+++ b/IndexedDB/interleaved-cursors-common.js
@@ -1,12 +1,5 @@
-<!doctype html>
-<meta charset="utf-8">
-<meta name="timeout" content="long">
-<title>IndexedDB: Interleaved iteration of multiple cursors</title>
-<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="support-promises.js"></script>
-<script>
+// Infrastructure shared by interleaved-cursors-{small,large}.html
+
// Number of objects that each iterator goes over.
const itemCount = 10;
@@ -169,7 +162,7 @@
});
}
-for (let cursorCount of [1, 10, 100, 500]) {
+function cursorTest(cursorCount) {
promise_test(testCase => {
return createDatabase(testCase, (database, transaction) => {
const store = database.createObjectStore('cache',
@@ -193,4 +186,3 @@
});
}, `${cursorCount} cursors`);
}
-</script>
diff --git a/IndexedDB/interleaved-cursors-large.html b/IndexedDB/interleaved-cursors-large.html
new file mode 100644
index 0000000..6f4e440
--- /dev/null
+++ b/IndexedDB/interleaved-cursors-large.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>IndexedDB: Interleaved iteration of multiple cursors</title>
+<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support-promises.js"></script>
+<script src="interleaved-cursors-common.js"></script>
+<script>
+cursorTest(250);
+</script>
diff --git a/IndexedDB/interleaved-cursors-small.html b/IndexedDB/interleaved-cursors-small.html
new file mode 100644
index 0000000..a4c4777
--- /dev/null
+++ b/IndexedDB/interleaved-cursors-small.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>IndexedDB: Interleaved iteration of multiple cursors</title>
+<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support-promises.js"></script>
+<script src="interleaved-cursors-common.js"></script>
+<script>
+cursorTest(1);
+cursorTest(10);
+cursorTest(100);
+</script>
diff --git a/README.md b/README.md
index 0247e8c..90f1f47 100644
--- a/README.md
+++ b/README.md
@@ -32,17 +32,22 @@
and read the [Windows Notes](#windows-notes) section below.
To get the tests running, you need to set up the test domains in your
-[`hosts` file](http://en.wikipedia.org/wiki/Hosts_%28file%29%23Location_in_the_file_system). The
-following entries are required:
+[`hosts` file](http://en.wikipedia.org/wiki/Hosts_%28file%29%23Location_in_the_file_system).
+The necessary content can be generated with `./wpt make-hosts-file`; on
+Windows, you will need to preceed the prior command with `python` or
+the path to the Python binary (`python wpt make-hosts-file`).
+
+For example, on most UNIX-like systems, you can setup the hosts file with:
+
+```bash
+./wpt make-hosts-file | sudo tee -a /etc/hosts
```
-127.0.0.1 web-platform.test
-127.0.0.1 www.web-platform.test
-127.0.0.1 www1.web-platform.test
-127.0.0.1 www2.web-platform.test
-127.0.0.1 xn--n8j6ds53lwwkrqhv28a.web-platform.test
-127.0.0.1 xn--lve-6lad.web-platform.test
-0.0.0.0 nonexistent-origin.web-platform.test
+
+And on Windows (note this requires an Administrator privileged shell):
+
+```bash
+python wpt make-hosts-file >> %SystemRoot%\System32\drivers\etc\hosts
```
If you are behind a proxy, you also need to make sure the domains above are
diff --git a/common/css-paint-tests.js b/common/worklet-reftest.js
similarity index 71%
rename from common/css-paint-tests.js
rename to common/worklet-reftest.js
index cd57332..e060835 100644
--- a/common/css-paint-tests.js
+++ b/common/worklet-reftest.js
@@ -1,12 +1,12 @@
// To make sure that we take the snapshot at the right time, we do double
// requestAnimationFrame. In the second frame, we take a screenshot, that makes
// sure that we already have a full frame.
-function importPaintWorkletAndTerminateTestAfterAsyncPaint(code) {
- if (typeof CSS.paintWorklet == "undefined") {
+function importWorkletAndTerminateTestAfterAsyncPaint(worklet, code) {
+ if (typeof worklet == "undefined") {
takeScreenshot();
} else {
var blob = new Blob([code], {type: 'text/javascript'});
- CSS.paintWorklet.addModule(URL.createObjectURL(blob)).then(function() {
+ worklet.addModule(URL.createObjectURL(blob)).then(function() {
requestAnimationFrame(function() {
requestAnimationFrame(function() {
takeScreenshot();
diff --git a/compat/webkit-appearance.tentative.html b/compat/webkit-appearance.tentative.html
new file mode 100644
index 0000000..8c0273d
--- /dev/null
+++ b/compat/webkit-appearance.tentative.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<title>-webkit-appearance support</title>
+<!-- There is no spec for -webkit-appearance. It is supported in Opera, Safari,
+ Chrome, and Edge. Firefox has expressed intent to support it. -->
+<link rel="help" href="https://github.com/whatwg/compat/issues/6">
+<meta name="assert" content="This test checks for support of the -webkit-appearance CSS attribute." />
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id="tester"></div>
+
+<script>
+const WEBKIT_APPEARANCE_VALUES = [
+ 'none',
+ 'checkbox',
+ 'radio',
+ 'push-button',
+ 'square-button',
+ 'button',
+ 'button-bevel',
+ 'inner-spin-button',
+ 'listbox',
+ 'listitem',
+ 'media-enter-fullscreen-button',
+ 'media-exit-fullscreen-button',
+ 'media-mute-button',
+ 'media-play-button',
+ 'media-overlay-play-button',
+ 'media-toggle-closed-captions-button',
+ 'media-slider',
+ 'media-sliderthumb',
+ 'media-volume-slider-container',
+ 'media-volume-slider',
+ 'media-volume-sliderthumb',
+ 'media-controls-background',
+ 'media-controls-fullscreen-background',
+ 'media-current-time-display',
+ 'media-time-remaining-display',
+ 'menulist',
+ 'menulist-button',
+ 'menulist-text',
+ 'menulist-textfield',
+ 'meter',
+ 'progress-bar',
+ 'progress-bar-value',
+ 'slider-horizontal',
+ 'slider-vertical',
+ 'sliderthumb-horizontal',
+ 'sliderthumb-vertical',
+ 'caret',
+ 'searchfield',
+ 'searchfield-cancel-button',
+ 'textfield',
+ 'textarea',
+];
+
+for (const appearance_value of WEBKIT_APPEARANCE_VALUES) {
+ test(() => {
+ const div = document.getElementById('tester');
+ div.style = `-webkit-appearance: ${appearance_value}`;
+ assert_equals(getComputedStyle(div).webkitAppearance, appearance_value);
+ });
+}
+</script>
diff --git a/css/CSS2/normal-flow/margin-collapse-through-zero-height-block.html b/css/CSS2/normal-flow/margin-collapse-through-zero-height-block.html
new file mode 100644
index 0000000..471a4c7
--- /dev/null
+++ b/css/CSS2/normal-flow/margin-collapse-through-zero-height-block.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<title>Collapse bottom margin from previous sibling through zero height block to next sibling</title>
+<link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/CSS22/box.html#collapsing-margins" title="8.3.1 Collapsing margins">
+<link rel="match" href="../../reference/ref-filled-green-200px-square.html">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="overflow:hidden; width:200px; height:400px; background:green;">
+ <div style="margin-bottom:200px;"></div>
+ <div style="height:0;"></div>
+ <div style="height:200px; margin-top:100px; background:white;"></div>
+ <div style="height:200px; background:red;"></div>
+</div>
diff --git a/css/css-align/content-distribution/place-content-shorthand-004.html b/css/css-align/content-distribution/place-content-shorthand-004.html
index 30f45b6..3f9bd88 100644
--- a/css/css-align/content-distribution/place-content-shorthand-004.html
+++ b/css/css-align/content-distribution/place-content-shorthand-004.html
@@ -48,6 +48,12 @@
}, "Verify 'auto' values are invalid");
test(function() {
+ checkInvalidValues("self-start")
+ checkInvalidValues("center self-end")
+ checkInvalidValues("self-end start")
+ }, "Verify self-position values are invalid");
+
+ test(function() {
checkInvalidValues("")
}, "Verify empty declaration is invalid");
</script>
diff --git a/css/css-align/default-alignment/parse-justify-items-002.html b/css/css-align/default-alignment/parse-justify-items-002.html
index 6ba2c7c..1806fa2 100644
--- a/css/css-align/default-alignment/parse-justify-items-002.html
+++ b/css/css-align/default-alignment/parse-justify-items-002.html
@@ -19,39 +19,39 @@
test(function() {
element = document.createElement("div");
document.body.appendChild(element);
- checkValues(element, "justifyItems", "justify-items", "", "legacy");
+ checkValues(element, "justifyItems", "justify-items", "", "normal");
}, "Test 'initial' value when nothing is specified");
test(function() {
container.style.display = "";
- checkInitialValues(element, "justifyItems", "justify-items", "center", "legacy");
+ checkInitialValues(element, "justifyItems", "justify-items", "center", "normal");
}, "Test justify-items: 'initial'");
test(function() {
container.style.display = "grid";
- checkInitialValues(element, "justifyItems", "justify-items", "safe start", "legacy");
+ checkInitialValues(element, "justifyItems", "justify-items", "safe start", "normal");
}, "Test grid items justify-items: 'initial'");
test(function() {
container.style.display = "flex";
- checkInitialValues(element, "justifyItems", "justify-items", "unsafe end", "legacy");
+ checkInitialValues(element, "justifyItems", "justify-items", "unsafe end", "normal");
}, "Test flex items justify-items: 'initial'");
test(function() {
container.style.display = "";
element.style.position = "absolute";
- checkInitialValues(element, "justifyItems", "justify-items", "start", "legacy");
+ checkInitialValues(element, "justifyItems", "justify-items", "start", "normal");
}, "Test absolute positioned elements justify-items: 'initial'");
test(function() {
container.style.display = "grid";
element.style.position = "absolute";
- checkInitialValues(element, "justifyItems", "justify-items", "end", "legacy");
+ checkInitialValues(element, "justifyItems", "justify-items", "end", "normal");
}, "Test absolute positioned grid items justify-items: 'initial'");
test(function() {
container.style.display = "flex";
element.style.position = "absolute";
- checkInitialValues(element, "justifyItems", "justify-items", "end", "legacy");
+ checkInitialValues(element, "justifyItems", "justify-items", "end", "normal");
}, "Test absolute positioned flex items justify-items: 'initial'");
</script>
diff --git a/css/css-align/default-alignment/place-items-shorthand-004.html b/css/css-align/default-alignment/place-items-shorthand-004.html
index c5d9472..aa3ff30 100644
--- a/css/css-align/default-alignment/place-items-shorthand-004.html
+++ b/css/css-align/default-alignment/place-items-shorthand-004.html
@@ -37,7 +37,18 @@
checkInvalidValues("auto")
checkInvalidValues("auto right")
checkInvalidValues("auto auto")
- }, "Verify 'auto' value is invalid as first longhand value.");
+ checkInvalidValues("center auto")
+ }, "Verify 'auto' value is invalid.");
+
+ test(function() {
+ checkInvalidValues("legacy")
+ checkInvalidValues("legacy start")
+ checkInvalidValues("end legacy")
+ checkInvalidValues("legacy left")
+ checkInvalidValues("center legacy")
+ checkInvalidValues("start legacy center")
+ }, "Verify 'legacy' value is invalid.");
+
test(function() {
checkInvalidValues("")
diff --git a/css/css-color/color-function-parsing.html b/css/css-color/color-function-parsing.html
new file mode 100644
index 0000000..7f483bb
--- /dev/null
+++ b/css/css-color/color-function-parsing.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: color() parsing</title>
+<link rel="help" href="https://drafts.csswg.org/css-color-4/#color-function">
+<meta name="assert" content="Tests basic parsing of the color function">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="test"></div>
+<script>
+ const div = document.querySelector("#test");
+ function testColorFunction(description, rule, expectedValue) {
+ test(function() {
+ div.style.color = "black";
+ div.style.color = rule;
+ assert_equals(getComputedStyle(div).color, expectedValue);
+ }, description);
+ }
+
+ testColorFunction("Basic sRGB white", "color(srgb 1 1 1)", "color(srgb 1 1 1)");
+ testColorFunction("White with lots of space", "color( srgb 1 1 1 )", "color(srgb 1 1 1)");
+ testColorFunction("sRGB color", "color(srgb 0.25 0.5 0.75)", "color(srgb 0.25 0.5 0.75)");
+ testColorFunction("Different case for sRGB", "color(SrGb 0.25 0.5 0.75)", "color(srgb 0.25 0.5 0.75)");
+ testColorFunction("sRGB color with unnecessary decimals", "color(srgb 1.00000 0.500000 0.20)", "color(srgb 1 0.5 0.2)");
+ testColorFunction("sRGB white with 0.5 alpha", "color(srgb 1 1 1 / 0.5)", "color(srgb 1 1 1 / 0.5)");
+ testColorFunction("sRGB white with 0 alpha", "color(srgb 1 1 1 / 0)", "color(srgb 1 1 1 / 0)");
+ testColorFunction("sRGB white with 50% alpha", "color(srgb 1 1 1 / 50%)", "color(srgb 1 1 1 / 0.5)");
+ testColorFunction("sRGB white with 0% alpha", "color(srgb 1 1 1 / 0%)", "color(srgb 1 1 1 / 0)");
+ testColorFunction("One missing component is 0", "color(srgb 1 1)", "color(srgb 1 1 0)");
+ testColorFunction("Two missing components are 0", "color(srgb 1)", "color(srgb 1 0 0)");
+ testColorFunction("All components missing", "color(srgb)", "color(srgb 0 0 0)");
+ testColorFunction("Display P3 color", "color(display-p3 0.6 0.7 0.8)", "color(display-p3 0.6 0.7 0.8)");
+ testColorFunction("Different case for Display P3", "color(dIspLaY-P3 0.6 0.7 0.8)", "color(display-p3 0.6 0.7 0.8)");
+
+ testColorFunction("Unknown color space should fallback", "color(unknown 1 2 3, red)", "color(unknown 1 2 3, red)");
+
+ testColorFunction("sRGB color with negative component should clamp to 0", "color(srgb -0.25 0.5 0.75)", "color(srgb 0 0.5 0.75)");
+ testColorFunction("sRGB color with component > 1 should clamp", "color(srgb 0.25 1.5 0.75)", "color(srgb 0.25 1 0.75)");
+ testColorFunction("Display P3 color with negative component should clamp to 0", "color(display-p3 0.5 -199 0.75)", "color(display-p3 0.5 0 0.75)");
+ testColorFunction("Display P3 color with component > 1 should clamp", "color(display-p3 184 1.00001 2347329746587)", "color(display-p3 1 1 1)");
+ testColorFunction("Alpha > 1 should clamp", "color(srgb 0.1 0.2 0.3 / 1.9)", "color(srgb 0.1 0.2 0.3)");
+ testColorFunction("Negative alpha should clamp", "color(srgb 1 1 1 / -0.2)", "color(srgb 1 1 1 / 0)");
+
+ // Invalid properties
+ testColorFunction("Empty", "color()", "rgb(0, 0, 0)");
+ testColorFunction("Bad color space", "color(banana 1 1 1)", "rgb(0, 0, 0)");
+ testColorFunction("Bad Display P3 color space", "color(displayp3 1 1 1)", "rgb(0, 0, 0)");
+ testColorFunction("No color space", "color(1 1 1)", "rgb(0, 0, 0)");
+ testColorFunction("Too many parameters", "color(srgb 1 1 1 1)", "rgb(0, 0, 0)");
+ testColorFunction("Way too many parameters", "color(srgb 1 1 1 1 1)", "rgb(0, 0, 0)");
+ testColorFunction("Bad parameters", "color(srgb 1 eggs 1)", "rgb(0, 0, 0)");
+ testColorFunction("Bad alpha", "color(srgb 1 1 1 / bacon)", "rgb(0, 0, 0)");
+ testColorFunction("Junk after alpha", "color(srgb 1 1 1 / 1 cucumber)", "rgb(0, 0, 0)");
+</script>
diff --git a/css/css-grid/grid-items/grid-minimum-size-grid-items-022.html b/css/css-grid/grid-items/grid-minimum-size-grid-items-022.html
index 66417a4..127ea8d 100644
--- a/css/css-grid/grid-items/grid-minimum-size-grid-items-022.html
+++ b/css/css-grid/grid-items/grid-minimum-size-grid-items-022.html
@@ -135,3 +135,217 @@
<div data-expected-width="8" style="width: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
<div data-expected-width="25"></div>
</div>
+
+<h3>grid content writing-mode: vertical-lr;</h3>
+
+<pre>grid-template-columns: auto;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: auto;">
+ <div data-expected-height="100">XXXXXXXXXX</div>
+ <div data-expected-height="100"></div>
+</div>
+
+<pre>grid-template-columns: 0px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: 0px;">
+ <div data-expected-height="0">XXXXXXXXXX</div>
+ <div data-expected-height="0"></div>
+</div>
+
+<pre>grid-template-columns: 25px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: 25px;">
+ <div data-expected-height="25">XXXXXXXXXX</div>
+ <div data-expected-height="25"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px);</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 0px);">
+ <div data-expected-height="0">XXXXXXXXXX</div>
+ <div data-expected-height="0"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 25px);</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 25px);">
+ <div data-expected-height="25">XXXXXXXXXX</div>
+ <div data-expected-height="25"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px); item height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 0px);">
+ <div data-expected-height="10" style="height: 10px;">XXXXXXXXXX</div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 25px); item height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 25px);">
+ <div data-expected-height="10" style="height: 10px;">XXXXXXXXXX</div>
+ <div data-expected-height="25"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px); item margin height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 0px);">
+ <div data-expected-height="0" style="margin: 5px 0px;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 25px); item margin height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 25px);">
+ <div data-expected-height="15" style="margin: 5px 0px;"></div>
+ <div data-expected-height="25"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px); item padding height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 0px);">
+ <div data-expected-height="10" style="padding: 5px 0px;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 25px); item padding height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 25px);">
+ <div data-expected-height="25" style="padding: 5px 0px;"></div>
+ <div data-expected-height="25"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px); item border height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 0px);">
+ <div data-expected-height="10" style="border: solid 5px blue;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 25px); item border height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 25px);">
+ <div data-expected-height="25" style="border: solid 5px blue;"></div>
+ <div data-expected-height="25"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px); item height + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 0px);">
+ <div data-expected-height="8" style="height: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 25px); item height + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 25px);">
+ <div data-expected-height="8" style="height: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-height="25"></div>
+</div>
+
+<h3>grid content writing-mode: vertical-rl;</h3>
+
+<pre>grid-template-columns: auto;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: auto;">
+ <div data-expected-height="100">XXXXXXXXXX</div>
+ <div data-expected-height="100"></div>
+</div>
+
+<pre>grid-template-columns: 0px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: 0px;">
+ <div data-expected-height="0">XXXXXXXXXX</div>
+ <div data-expected-height="0"></div>
+</div>
+
+<pre>grid-template-columns: 25px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: 25px;">
+ <div data-expected-height="25">XXXXXXXXXX</div>
+ <div data-expected-height="25"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px);</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 0px);">
+ <div data-expected-height="0">XXXXXXXXXX</div>
+ <div data-expected-height="0"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 25px);</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 25px);">
+ <div data-expected-height="25">XXXXXXXXXX</div>
+ <div data-expected-height="25"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px); item height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 0px);">
+ <div data-expected-height="10" style="height: 10px;">XXXXXXXXXX</div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 25px); item height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 25px);">
+ <div data-expected-height="10" style="height: 10px;">XXXXXXXXXX</div>
+ <div data-expected-height="25"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px); item margin height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 0px);">
+ <div data-expected-height="0" style="margin: 5px 0px;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 25px); item margin height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 25px);">
+ <div data-expected-height="15" style="margin: 5px 0px;"></div>
+ <div data-expected-height="25"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px); item padding height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 0px);">
+ <div data-expected-height="10" style="padding: 5px 0px;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 25px); item padding height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 25px);">
+ <div data-expected-height="25" style="padding: 5px 0px;"></div>
+ <div data-expected-height="25"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px); item border height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 0px);">
+ <div data-expected-height="10" style="border: solid 5px blue;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 25px); item border height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 25px);">
+ <div data-expected-height="25" style="border: solid 5px blue;"></div>
+ <div data-expected-height="25"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px); item height + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 0px);">
+ <div data-expected-height="8" style="height: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 25px); item height + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 25px);">
+ <div data-expected-height="8" style="height: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-height="25"></div>
+</div>
diff --git a/css/css-grid/grid-items/grid-minimum-size-grid-items-023.html b/css/css-grid/grid-items/grid-minimum-size-grid-items-023.html
index d821e5c..636a40f 100644
--- a/css/css-grid/grid-items/grid-minimum-size-grid-items-023.html
+++ b/css/css-grid/grid-items/grid-minimum-size-grid-items-023.html
@@ -32,7 +32,7 @@
<div id="log"></div>
-<h3>writing-mode: vertical-lr;</h3>
+<h3>item writing-mode: vertical-lr;</h3>
<pre>grid-template-rows: auto;</pre>
@@ -139,7 +139,7 @@
<div data-expected-height="25"></div>
</div>
-<h3>writing-mode: vertical-rl;</h3>
+<h3>item writing-mode: vertical-rl;</h3>
<pre>grid-template-rows: auto;</pre>
@@ -246,3 +246,216 @@
<div data-expected-height="25"></div>
</div>
+<h3>grid container writing-mode: vertical-lr; & item writing-mode: horizontal-tb;</h3>
+
+<pre>grid-template-rows: auto;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: auto;">
+ <div class="horizontalTB" data-expected-width="100">XXXXXXXXXX</div>
+ <div data-expected-width="100"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px);</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="0">XXXXXXXXXX</div>
+ <div data-expected-width="0"></div>
+</div>
+
+<pre>grid-template-rows: 25px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: 25px;">
+ <div class="horizontalTB" data-expected-width="25">XXXXXXXXXX</div>
+ <div data-expected-width="25"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px);</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="0">XXXXXXXXXX</div>
+ <div data-expected-width="0"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 25px);</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 25px);">
+ <div class="horizontalTB" data-expected-width="25">XXXXXXXXXX</div>
+ <div data-expected-width="25"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px); item width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="10" style="width: 10px;">XXXXXXXXXX</div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 25px); item width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 25px);">
+ <div class="horizontalTB" data-expected-width="10" style="width: 10px;">XXXXXXXXXX</div>
+ <div data-expected-width="25"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px); item margin width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="0" style="margin: 0px 5px;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 25px); item margin width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 25px);">
+ <div class="horizontalTB" data-expected-width="15" style="margin: 0px 5px;"></div>
+ <div data-expected-width="25"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px); item padding width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="10" style="padding: 0px 5px;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 25px); item padding width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 25px);">
+ <div class="horizontalTB" data-expected-width="25" style="padding: 0px 5px;"></div>
+ <div data-expected-width="25"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px); item border width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="10" style="border: solid 5px blue;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 25px); item border width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 25px);">
+ <div class="horizontalTB" data-expected-width="25" style="border: solid 5px blue;"></div>
+ <div data-expected-width="25"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px); item width + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="8" style="width: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 25px); item width + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 25px);">
+ <div class="horizontalTB" data-expected-width="8" style="width: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-width="25"></div>
+</div>
+
+<h3>grid container writing-mode: vertical-rl; & item writing-mode: horizontal-tb;</h3>
+
+<pre>grid-template-rows: auto;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: auto;">
+ <div class="horizontalTB" data-expected-width="100">XXXXXXXXXX</div>
+ <div data-expected-width="100"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px);</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="0">XXXXXXXXXX</div>
+ <div data-expected-width="0"></div>
+</div>
+
+<pre>grid-template-rows: 25px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: 25px;">
+ <div class="horizontalTB" data-expected-width="25">XXXXXXXXXX</div>
+ <div data-expected-width="25"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px);</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="0">XXXXXXXXXX</div>
+ <div data-expected-width="0"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 25px);</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 25px);">
+ <div class="horizontalTB" data-expected-width="25">XXXXXXXXXX</div>
+ <div data-expected-width="25"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px); item width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="10" style="width: 10px;">XXXXXXXXXX</div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 25px); item width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 25px);">
+ <div class="horizontalTB" data-expected-width="10" style="width: 10px;">XXXXXXXXXX</div>
+ <div data-expected-width="25"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px); item margin width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="0" style="margin: 0px 5px;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 25px); item margin width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 25px);">
+ <div class="horizontalTB" data-expected-width="15" style="margin: 0px 5px;"></div>
+ <div data-expected-width="25"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px); item padding width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="10" style="padding: 0px 5px;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 25px); item padding width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 25px);">
+ <div class="horizontalTB" data-expected-width="25" style="padding: 0px 5px;"></div>
+ <div data-expected-width="25"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px); item border width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="10" style="border: solid 5px blue;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 25px); item border width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 25px);">
+ <div class="horizontalTB" data-expected-width="25" style="border: solid 5px blue;"></div>
+ <div data-expected-width="25"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px); item width + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="8" style="width: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 25px); item width + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 25px);">
+ <div class="horizontalTB" data-expected-width="8" style="width: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-width="25"></div>
+</div>
diff --git a/css/css-grid/grid-items/grid-minimum-size-grid-items-024.html b/css/css-grid/grid-items/grid-minimum-size-grid-items-024.html
new file mode 100644
index 0000000..fb706bf
--- /dev/null
+++ b/css/css-grid/grid-items/grid-minimum-size-grid-items-024.html
@@ -0,0 +1,355 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Minimum size of grid items</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="http://www.w3.org/TR/css-grid-1/#min-size-auto" title="6.5. Implied Minimum Size of Grid Items">
+<meta name="assert" content="Checks that automatic minimum size is clamped with different column sizes and spaning items.">
+<link rel="stylesheet" href="../support/grid.css">
+<style>
+.grid {
+ border: solid thick;
+ font: 10px/1 Ahem;
+ width: 50px;
+ height: 50px;
+ grid-template-rows: 25px 25px;
+}
+
+.grid > div {
+ grid-column: span 2;
+}
+
+.grid > div:nth-child(1) {
+ color: blue;
+ background: cyan;
+}
+
+.grid > div:nth-child(2) {
+ background: magenta;
+}
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+
+<body onload="checkLayout('.grid')">
+
+<div id="log"></div>
+
+<pre>grid-template-columns: auto auto;</pre>
+
+<div class="grid" style="grid-template-columns: auto auto;">
+ <div data-expected-width="100">XXXXXXXXXX</div>
+ <div data-expected-width="100"></div>
+</div>
+
+<pre>grid-template-columns: 0px 0px;</pre>
+
+<div class="grid" style="grid-template-columns: 0px 0px;">
+ <div data-expected-width="0">XXXXXXXXXX</div>
+ <div data-expected-width="0"></div>
+</div>
+
+<pre>grid-template-columns: 20px 20px;</pre>
+
+<div class="grid" style="grid-template-columns: 20px 20px;">
+ <div data-expected-width="40">XXXXXXXXXX</div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);</pre>
+
+<div class="grid" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-width="0">XXXXXXXXXX</div>
+ <div data-expected-width="0"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);</pre>
+
+<div class="grid" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-width="40">XXXXXXXXXX</div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item width: 10px;</pre>
+
+<div class="grid" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-width="10" style="width: 10px;">XXXXXXXXXX</div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item width: 10px;</pre>
+
+<div class="grid" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-width="10" style="width: 10px;">XXXXXXXXXX</div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item margin width: 10px;</pre>
+
+<div class="grid" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-width="0" style="margin: 0px 5px;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item margin width: 10px;</pre>
+
+<div class="grid" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-width="30" style="margin: 0px 5px;"></div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item padding width: 10px;</pre>
+
+<div class="grid" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-width="10" style="padding: 0px 5px;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item padding width: 10px;</pre>
+
+<div class="grid" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-width="40" style="padding: 0px 5px;"></div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item border width: 10px;</pre>
+
+<div class="grid" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-width="10" style="border: solid 5px blue;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item border width: 10px;</pre>
+
+<div class="grid" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-width="40" style="border: solid 5px blue;"></div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item width + margin + border + padding: 10px;</pre>
+
+<div class="grid" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-width="8" style="width: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item width + margin + border + padding: 10px;</pre>
+
+<div class="grid" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-width="8" style="width: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-width="40"></div>
+</div>
+
+<h3>grid content writing-mode: vertical-lr;</h3>
+
+<pre>grid-template-columns: auto auto;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: auto auto;">
+ <div data-expected-height="100">XXXXXXXXXX</div>
+ <div data-expected-height="100"></div>
+</div>
+
+<pre>grid-template-columns: 0px 0px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: 0px 0px;">
+ <div data-expected-height="0">XXXXXXXXXX</div>
+ <div data-expected-height="0"></div>
+</div>
+
+<pre>grid-template-columns: 20px 20px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: 20px 20px;">
+ <div data-expected-height="40">XXXXXXXXXX</div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-height="0">XXXXXXXXXX</div>
+ <div data-expected-height="0"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-height="40">XXXXXXXXXX</div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-height="10" style="height: 10px;">XXXXXXXXXX</div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-height="10" style="height: 10px;">XXXXXXXXXX</div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item margin height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-height="0" style="margin: 5px 0px;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item margin height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-height="30" style="margin: 5px 0px;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item padding height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-height="10" style="padding: 5px 0px;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item padding height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-height="40" style="padding: 5px 0px;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item border height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-height="10" style="border: solid 5px blue;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item border height: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-height="40" style="border: solid 5px blue;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item height + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-height="8" style="height: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item height + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-height="8" style="height: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<h3>grid content writing-mode: vertical-rl;</h3>
+
+<pre>grid-template-columns: auto auto;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: auto auto;">
+ <div data-expected-height="100">XXXXXXXXXX</div>
+ <div data-expected-height="100"></div>
+</div>
+
+<pre>grid-template-columns: 0px 0px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: 0px 0px;">
+ <div data-expected-height="0">XXXXXXXXXX</div>
+ <div data-expected-height="0"></div>
+</div>
+
+<pre>grid-template-columns: 20px 20px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: 20px 20px;">
+ <div data-expected-height="40">XXXXXXXXXX</div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-height="0">XXXXXXXXXX</div>
+ <div data-expected-height="0"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-height="40">XXXXXXXXXX</div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-height="10" style="height: 10px;">XXXXXXXXXX</div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-height="10" style="height: 10px;">XXXXXXXXXX</div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item margin height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-height="0" style="margin: 5px 0px;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item margin height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-height="30" style="margin: 5px 0px;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item padding height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-height="10" style="padding: 5px 0px;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item padding height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-height="40" style="padding: 5px 0px;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item border height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-height="10" style="border: solid 5px blue;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item border height: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-height="40" style="border: solid 5px blue;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 0px) minmax(auto, 0px); item height + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 0px) minmax(auto, 0px);">
+ <div data-expected-height="8" style="height: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-columns: minmax(auto, 20px) minmax(auto, 20px); item height + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-columns: minmax(auto, 20px) minmax(auto, 20px);">
+ <div data-expected-height="8" style="height: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-height="40"></div>
+</div>
diff --git a/css/css-grid/grid-items/grid-minimum-size-grid-items-025.html b/css/css-grid/grid-items/grid-minimum-size-grid-items-025.html
new file mode 100644
index 0000000..722426e
--- /dev/null
+++ b/css/css-grid/grid-items/grid-minimum-size-grid-items-025.html
@@ -0,0 +1,465 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Minimum size of grid items</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="http://www.w3.org/TR/css-grid-1/#min-size-auto" title="6.5. Implied Minimum Size of Grid Items">
+<meta name="assert" content="Checks that automatic minimum size is clamped with different row sizes and spaning items.">
+<link rel="stylesheet" href="../support/grid.css">
+<style>
+.grid {
+ border: solid thick;
+ font: 10px/1 Ahem;
+ width: 50px;
+ height: 50px;
+ grid-template-columns: 25px 25px;
+ margin: 50px 0px;
+}
+
+.grid > div {
+ grid-row: span 2;
+}
+
+.grid > div:nth-child(1) {
+ color: blue;
+ background: cyan;
+}
+
+.grid > div:nth-child(2) {
+ background: magenta;
+}
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+
+<body onload="checkLayout('.grid')">
+
+<div id="log"></div>
+
+<h3>item writing-mode: vertical-lr;</h3>
+
+<pre>grid-template-rows: auto auto;</pre>
+
+<div class="grid" style="grid-template-rows: auto auto;">
+ <div class="verticalLR" data-expected-height="100">XXXXXXXXXX</div>
+ <div data-expected-height="100"></div>
+</div>
+
+<pre>grid-template-rows: 0px 0px;</pre>
+
+<div class="grid" style="grid-template-rows: 0px 0px;">
+ <div class="verticalLR" data-expected-height="0">XXXXXXXXXX</div>
+ <div data-expected-height="0"></div>
+</div>
+
+<pre>grid-template-rows: 20px 20px;</pre>
+
+<div class="grid" style="grid-template-rows: 20px 20px;">
+ <div class="verticalLR" data-expected-height="40">XXXXXXXXXX</div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="verticalLR" data-expected-height="0">XXXXXXXXXX</div>
+ <div data-expected-height="0"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="verticalLR" data-expected-height="40">XXXXXXXXXX</div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="verticalLR" data-expected-height="10" style="height: 10px;">XXXXXXXXXX</div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="verticalLR" data-expected-height="10" style="height: 10px;">XXXXXXXXXX</div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item margin height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="verticalLR" data-expected-height="0" style="margin: 5px 0px;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item margin height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="verticalLR" data-expected-height="30" style="margin: 5px 0px;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item padding height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="verticalLR" data-expected-height="10" style="padding: 5px 0px;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item padding height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="verticalLR" data-expected-height="40" style="padding: 5px 0px;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item border height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="verticalLR" data-expected-height="10" style="border: solid 5px blue;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item border height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="verticalLR" data-expected-height="40" style="border: solid 5px blue;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item height + margin + border + padding: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="verticalLR" data-expected-height="8" style="height: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item height + margin + border + padding: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="verticalLR" data-expected-height="8" style="height: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<h3>item writing-mode: vertical-rl;</h3>
+
+<pre>grid-template-rows: auto auto;</pre>
+
+<div class="grid" style="grid-template-rows: auto auto;">
+ <div class="verticalRL" data-expected-height="100">XXXXXXXXXX</div>
+ <div data-expected-height="100"></div>
+</div>
+
+<pre>grid-template-rows: 0px 0px;</pre>
+
+<div class="grid" style="grid-template-rows: 0px 0px;">
+ <div class="verticalRL" data-expected-height="0">XXXXXXXXXX</div>
+ <div data-expected-height="0"></div>
+</div>
+
+<pre>grid-template-rows: 20px 20px;</pre>
+
+<div class="grid" style="grid-template-rows: 20px 20px;">
+ <div class="verticalRL" data-expected-height="40">XXXXXXXXXX</div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="verticalRL" data-expected-height="0">XXXXXXXXXX</div>
+ <div data-expected-height="0"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="verticalRL" data-expected-height="40">XXXXXXXXXX</div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="verticalRL" data-expected-height="10" style="height: 10px;">XXXXXXXXXX</div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="verticalRL" data-expected-height="10" style="height: 10px;">XXXXXXXXXX</div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item margin height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="verticalRL" data-expected-height="0" style="margin: 5px 0px;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item margin height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="verticalRL" data-expected-height="30" style="margin: 5px 0px;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item padding height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="verticalRL" data-expected-height="10" style="padding: 5px 0px;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item padding height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="verticalRL" data-expected-height="40" style="padding: 5px 0px;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item border height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="verticalRL" data-expected-height="10" style="border: solid 5px blue;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item border height: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="verticalRL" data-expected-height="40" style="border: solid 5px blue;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item height + margin + border + padding: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="verticalRL" data-expected-height="8" style="height: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-height="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item height + margin + border + padding: 10px;</pre>
+
+<div class="grid" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="verticalRL" data-expected-height="8" style="height: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-height="40"></div>
+</div>
+
+<h3>grid container writing-mode: vertical-lr; & item writing-mode: horizontal-tb;</h3>
+
+<pre>grid-template-rows: auto auto;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: auto auto;">
+ <div class="horizontalTB" data-expected-width="100">XXXXXXXXXX</div>
+ <div data-expected-width="100"></div>
+</div>
+
+<pre>grid-template-rows: 0px 0px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: 0px 0px;">
+ <div class="horizontalTB" data-expected-width="0">XXXXXXXXXX</div>
+ <div data-expected-width="0"></div>
+</div>
+
+<pre>grid-template-rows: 20px 20px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: 20px 20px;">
+ <div class="horizontalTB" data-expected-width="40">XXXXXXXXXX</div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="0">XXXXXXXXXX</div>
+ <div data-expected-width="0"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="horizontalTB" data-expected-width="40">XXXXXXXXXX</div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="10" style="width: 10px;">XXXXXXXXXX</div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="horizontalTB" data-expected-width="10" style="width: 10px;">XXXXXXXXXX</div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item margin width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="0" style="margin: 0px 5px;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item margin width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="horizontalTB" data-expected-width="30" style="margin: 0px 5px;"></div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item padding width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="10" style="padding: 0px 5px;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item padding width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="horizontalTB" data-expected-width="40" style="padding: 0px 5px;"></div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item border width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="10" style="border: solid 5px blue;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item border width: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="horizontalTB" data-expected-width="40" style="border: solid 5px blue;"></div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item width + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="8" style="width: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item width + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalLR" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="horizontalTB" data-expected-width="8" style="width: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-width="40"></div>
+</div>
+
+<h3>grid container writing-mode: vertical-rl; & item writing-mode: horizontal-tb;</h3>
+
+<pre>grid-template-rows: auto auto;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: auto auto;">
+ <div class="horizontalTB" data-expected-width="100">XXXXXXXXXX</div>
+ <div data-expected-width="100"></div>
+</div>
+
+<pre>grid-template-rows: 0px 0px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: 0px 0px;">
+ <div class="horizontalTB" data-expected-width="0">XXXXXXXXXX</div>
+ <div data-expected-width="0"></div>
+</div>
+
+<pre>grid-template-rows: 20px 20px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: 20px 20px;">
+ <div class="horizontalTB" data-expected-width="40">XXXXXXXXXX</div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="0">XXXXXXXXXX</div>
+ <div data-expected-width="0"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="horizontalTB" data-expected-width="40">XXXXXXXXXX</div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="10" style="width: 10px;">XXXXXXXXXX</div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="horizontalTB" data-expected-width="10" style="width: 10px;">XXXXXXXXXX</div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item margin width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="0" style="margin: 0px 5px;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item margin width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="horizontalTB" data-expected-width="30" style="margin: 0px 5px;"></div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item padding width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="10" style="padding: 0px 5px;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item padding width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="horizontalTB" data-expected-width="40" style="padding: 0px 5px;"></div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item border width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="10" style="border: solid 5px blue;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item border width: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="horizontalTB" data-expected-width="40" style="border: solid 5px blue;"></div>
+ <div data-expected-width="40"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 0px) minmax(auto, 0px); item width + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 0px) minmax(auto, 0px);">
+ <div class="horizontalTB" data-expected-width="8" style="width: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-width="10"></div>
+</div>
+
+<pre>grid-template-rows: minmax(auto, 20px) minmax(auto, 20px); item width + margin + border + padding: 10px;</pre>
+
+<div class="grid verticalRL" style="grid-template-rows: minmax(auto, 20px) minmax(auto, 20px);">
+ <div class="horizontalTB" data-expected-width="8" style="width: 4px; margin: 1px; padding: 1px; border: solid 1px blue;"></div>
+ <div data-expected-width="40"></div>
+</div>
diff --git a/css/css-paint-api/background-image-alpha.https.html b/css/css-paint-api/background-image-alpha.https.html
index de8a0d7..53d869d 100644
--- a/css/css-paint-api/background-image-alpha.https.html
+++ b/css/css-paint-api/background-image-alpha.https.html
@@ -21,7 +21,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="background">
<div id="canvas-opaque" class="container"></div>
@@ -49,7 +49,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/background-image-multiple.https.html b/css/css-paint-api/background-image-multiple.https.html
index 7fb5751..79ff883 100644
--- a/css/css-paint-api/background-image-multiple.https.html
+++ b/css/css-paint-api/background-image-multiple.https.html
@@ -9,7 +9,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="output"></div>
@@ -27,7 +27,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/background-image-tiled.https.html b/css/css-paint-api/background-image-tiled.https.html
index 0497acf..8498c82 100644
--- a/css/css-paint-api/background-image-tiled.https.html
+++ b/css/css-paint-api/background-image-tiled.https.html
@@ -21,7 +21,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="one"></div>
<div id="two"></div>
@@ -38,7 +38,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/geometry-background-image-001.https.html b/css/css-paint-api/geometry-background-image-001.https.html
index d1207e0..601d418 100644
--- a/css/css-paint-api/geometry-background-image-001.https.html
+++ b/css/css-paint-api/geometry-background-image-001.https.html
@@ -13,7 +13,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -28,7 +28,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/geometry-background-image-002.https.html b/css/css-paint-api/geometry-background-image-002.https.html
index 47455ba..1d57073 100644
--- a/css/css-paint-api/geometry-background-image-002.https.html
+++ b/css/css-paint-api/geometry-background-image-002.https.html
@@ -13,7 +13,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -28,7 +28,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/geometry-background-image-tiled-001.https.html b/css/css-paint-api/geometry-background-image-tiled-001.https.html
index 5cf8eb7..8e28b54 100644
--- a/css/css-paint-api/geometry-background-image-tiled-001.https.html
+++ b/css/css-paint-api/geometry-background-image-tiled-001.https.html
@@ -14,7 +14,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -30,7 +30,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/geometry-background-image-tiled-002.https.html b/css/css-paint-api/geometry-background-image-tiled-002.https.html
index 491abd1..9248e38 100644
--- a/css/css-paint-api/geometry-background-image-tiled-002.https.html
+++ b/css/css-paint-api/geometry-background-image-tiled-002.https.html
@@ -14,7 +14,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -29,7 +29,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/geometry-background-image-tiled-003.https.html b/css/css-paint-api/geometry-background-image-tiled-003.https.html
index 9a29c30..5b6b6c7 100644
--- a/css/css-paint-api/geometry-background-image-tiled-003.https.html
+++ b/css/css-paint-api/geometry-background-image-tiled-003.https.html
@@ -14,7 +14,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -29,7 +29,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/geometry-border-image-001.https.html b/css/css-paint-api/geometry-border-image-001.https.html
index 54249d3..3fb4643 100644
--- a/css/css-paint-api/geometry-border-image-001.https.html
+++ b/css/css-paint-api/geometry-border-image-001.https.html
@@ -15,7 +15,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -34,7 +34,7 @@
<script>
document.getElementById('canvas-geometry').style.borderWidth = '10px';
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/geometry-border-image-002.https.html b/css/css-paint-api/geometry-border-image-002.https.html
index 4759886..26e24bb 100644
--- a/css/css-paint-api/geometry-border-image-002.https.html
+++ b/css/css-paint-api/geometry-border-image-002.https.html
@@ -15,7 +15,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -34,7 +34,7 @@
<script>
document.getElementById('canvas-geometry').style.borderImageOutset = '20px';
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/geometry-border-image-003.https.html b/css/css-paint-api/geometry-border-image-003.https.html
index 1ce6ac9..a26f2b7 100644
--- a/css/css-paint-api/geometry-border-image-003.https.html
+++ b/css/css-paint-api/geometry-border-image-003.https.html
@@ -15,7 +15,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -34,7 +34,7 @@
<script>
document.getElementById('canvas-geometry').style.borderImageOutset = '10px';
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/geometry-border-image-004.https.html b/css/css-paint-api/geometry-border-image-004.https.html
index b15b66d..60db7ff 100644
--- a/css/css-paint-api/geometry-border-image-004.https.html
+++ b/css/css-paint-api/geometry-border-image-004.https.html
@@ -15,7 +15,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -35,7 +35,7 @@
<script>
document.getElementById('canvas-geometry').style.borderWidth = '10px';
document.getElementById('canvas-geometry').style.borderImageOutset = '10px';
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/geometry-with-float-size.https.html b/css/css-paint-api/geometry-with-float-size.https.html
index 6cd3eca..65477e4 100644
--- a/css/css-paint-api/geometry-with-float-size.https.html
+++ b/css/css-paint-api/geometry-with-float-size.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -29,7 +29,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/hidpi/device-pixel-ratio.https.html b/css/css-paint-api/hidpi/device-pixel-ratio.https.html
index fb62c23..46a9aa2 100644
--- a/css/css-paint-api/hidpi/device-pixel-ratio.https.html
+++ b/css/css-paint-api/hidpi/device-pixel-ratio.https.html
@@ -13,7 +13,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<p>This test ensures that the PaintWorkletGlobalScope.devicePixelRatio returns
the correct value, which should be identical as window.devicePixelRatio. To
@@ -33,7 +33,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/invalid-image-constructor-error.https.html b/css/css-paint-api/invalid-image-constructor-error.https.html
index 022b915..439ff8b 100644
--- a/css/css-paint-api/invalid-image-constructor-error.https.html
+++ b/css/css-paint-api/invalid-image-constructor-error.https.html
@@ -9,7 +9,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="output"></div>
@@ -33,7 +33,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
diff --git a/css/css-paint-api/invalid-image-paint-error.https.html b/css/css-paint-api/invalid-image-paint-error.https.html
index c185d89..2806ad9 100644
--- a/css/css-paint-api/invalid-image-paint-error.https.html
+++ b/css/css-paint-api/invalid-image-paint-error.https.html
@@ -9,7 +9,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="output"></div>
@@ -30,7 +30,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/invalid-image-pending-script.https.html b/css/css-paint-api/invalid-image-pending-script.https.html
index e19fa41..4347a00 100644
--- a/css/css-paint-api/invalid-image-pending-script.https.html
+++ b/css/css-paint-api/invalid-image-pending-script.https.html
@@ -9,7 +9,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="output"></div>
@@ -26,7 +26,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/overdraw.https.html b/css/css-paint-api/overdraw.https.html
index f95eeb5..5be26f7 100644
--- a/css/css-paint-api/overdraw.https.html
+++ b/css/css-paint-api/overdraw.https.html
@@ -10,7 +10,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="output"></div>
@@ -24,7 +24,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/paint-arguments.https.html b/css/css-paint-api/paint-arguments.https.html
index f4ae452..abfb2a6 100644
--- a/css/css-paint-api/paint-arguments.https.html
+++ b/css/css-paint-api/paint-arguments.https.html
@@ -21,7 +21,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="background">
@@ -43,7 +43,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/paint-function-arguments.https.html b/css/css-paint-api/paint-function-arguments.https.html
index d49f3f2..d87b0b8 100644
--- a/css/css-paint-api/paint-function-arguments.https.html
+++ b/css/css-paint-api/paint-function-arguments.https.html
@@ -21,7 +21,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="background">
@@ -43,7 +43,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/paint2d-composite.https.html b/css/css-paint-api/paint2d-composite.https.html
index ba88f92..80e94e4 100644
--- a/css/css-paint-api/paint2d-composite.https.html
+++ b/css/css-paint-api/paint2d-composite.https.html
@@ -19,7 +19,7 @@
#xor { background-image: paint(xor); }
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="source-over"></div>
<div id="source-in"></div>
@@ -67,7 +67,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/paint2d-filter.https.html b/css/css-paint-api/paint2d-filter.https.html
index 560b1b2..d0c4539 100644
--- a/css/css-paint-api/paint2d-filter.https.html
+++ b/css/css-paint-api/paint2d-filter.https.html
@@ -24,7 +24,7 @@
#filter-url { background-image: paint(filter-url); }
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="filter-none"></div>
<div id="filter-blur-10px"></div>
@@ -100,7 +100,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/paint2d-gradient.https.html b/css/css-paint-api/paint2d-gradient.https.html
index b936430..892a791 100644
--- a/css/css-paint-api/paint2d-gradient.https.html
+++ b/css/css-paint-api/paint2d-gradient.https.html
@@ -9,7 +9,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="output"></div>
@@ -34,7 +34,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/paint2d-image.https.html b/css/css-paint-api/paint2d-image.https.html
index ba89430..6fce4b6 100644
--- a/css/css-paint-api/paint2d-image.https.html
+++ b/css/css-paint-api/paint2d-image.https.html
@@ -10,7 +10,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<div id="output"></div>
<script id="code" type="text/worklet">
@@ -25,6 +25,6 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</html>
diff --git a/css/css-paint-api/paint2d-paths.https.html b/css/css-paint-api/paint2d-paths.https.html
index 55a01b4..091f548 100644
--- a/css/css-paint-api/paint2d-paths.https.html
+++ b/css/css-paint-api/paint2d-paths.https.html
@@ -9,7 +9,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="output"></div>
@@ -42,7 +42,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/paint2d-rects.https.html b/css/css-paint-api/paint2d-rects.https.html
index 24247da..2494272 100644
--- a/css/css-paint-api/paint2d-rects.https.html
+++ b/css/css-paint-api/paint2d-rects.https.html
@@ -10,7 +10,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="output"></div>
@@ -30,7 +30,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/paint2d-shadows.https.html b/css/css-paint-api/paint2d-shadows.https.html
index ad0a1aa..98dcfbc 100644
--- a/css/css-paint-api/paint2d-shadows.https.html
+++ b/css/css-paint-api/paint2d-shadows.https.html
@@ -9,7 +9,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="output"></div>
@@ -33,7 +33,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/paint2d-transform.https.html b/css/css-paint-api/paint2d-transform.https.html
index f5b6aa8..c91b500 100644
--- a/css/css-paint-api/paint2d-transform.https.html
+++ b/css/css-paint-api/paint2d-transform.https.html
@@ -9,7 +9,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="output"></div>
@@ -32,7 +32,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-001.https.html b/css/css-paint-api/parse-input-arguments-001.https.html
index 931a55a..4356ce6 100644
--- a/css/css-paint-api/parse-input-arguments-001.https.html
+++ b/css/css-paint-api/parse-input-arguments-001.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -42,7 +42,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-002.https.html b/css/css-paint-api/parse-input-arguments-002.https.html
index c07c0c0..6fc16c7 100644
--- a/css/css-paint-api/parse-input-arguments-002.https.html
+++ b/css/css-paint-api/parse-input-arguments-002.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -42,7 +42,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-003.https.html b/css/css-paint-api/parse-input-arguments-003.https.html
index ff388de..44fd850 100644
--- a/css/css-paint-api/parse-input-arguments-003.https.html
+++ b/css/css-paint-api/parse-input-arguments-003.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -42,7 +42,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-004.https.html b/css/css-paint-api/parse-input-arguments-004.https.html
index 8d5b8d7..138a790 100644
--- a/css/css-paint-api/parse-input-arguments-004.https.html
+++ b/css/css-paint-api/parse-input-arguments-004.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -43,7 +43,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-005.https.html b/css/css-paint-api/parse-input-arguments-005.https.html
index b726c22..c12e00c 100644
--- a/css/css-paint-api/parse-input-arguments-005.https.html
+++ b/css/css-paint-api/parse-input-arguments-005.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -39,7 +39,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-006.https.html b/css/css-paint-api/parse-input-arguments-006.https.html
index 7d8504c..664b7a8 100644
--- a/css/css-paint-api/parse-input-arguments-006.https.html
+++ b/css/css-paint-api/parse-input-arguments-006.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -38,7 +38,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-007.https.html b/css/css-paint-api/parse-input-arguments-007.https.html
index a59ac93..53f245b 100644
--- a/css/css-paint-api/parse-input-arguments-007.https.html
+++ b/css/css-paint-api/parse-input-arguments-007.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -42,7 +42,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-008.https.html b/css/css-paint-api/parse-input-arguments-008.https.html
index 2d6df23..1914e3c 100644
--- a/css/css-paint-api/parse-input-arguments-008.https.html
+++ b/css/css-paint-api/parse-input-arguments-008.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -42,7 +42,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-009.https.html b/css/css-paint-api/parse-input-arguments-009.https.html
index 03c7c69..21d004d 100644
--- a/css/css-paint-api/parse-input-arguments-009.https.html
+++ b/css/css-paint-api/parse-input-arguments-009.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -40,7 +40,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-010.https.html b/css/css-paint-api/parse-input-arguments-010.https.html
index 0bd6768..d923479 100644
--- a/css/css-paint-api/parse-input-arguments-010.https.html
+++ b/css/css-paint-api/parse-input-arguments-010.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -40,7 +40,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-011.https.html b/css/css-paint-api/parse-input-arguments-011.https.html
index e772a50..6cea438 100644
--- a/css/css-paint-api/parse-input-arguments-011.https.html
+++ b/css/css-paint-api/parse-input-arguments-011.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -38,7 +38,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-012.https.html b/css/css-paint-api/parse-input-arguments-012.https.html
index 422b45f..938150a 100644
--- a/css/css-paint-api/parse-input-arguments-012.https.html
+++ b/css/css-paint-api/parse-input-arguments-012.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -42,7 +42,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-013.https.html b/css/css-paint-api/parse-input-arguments-013.https.html
index cd62879..37e3eb435 100644
--- a/css/css-paint-api/parse-input-arguments-013.https.html
+++ b/css/css-paint-api/parse-input-arguments-013.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -38,7 +38,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-014.https.html b/css/css-paint-api/parse-input-arguments-014.https.html
index 39aee6a..690e488 100644
--- a/css/css-paint-api/parse-input-arguments-014.https.html
+++ b/css/css-paint-api/parse-input-arguments-014.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -40,7 +40,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-015.https.html b/css/css-paint-api/parse-input-arguments-015.https.html
index c2e1844..fba7671 100644
--- a/css/css-paint-api/parse-input-arguments-015.https.html
+++ b/css/css-paint-api/parse-input-arguments-015.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -43,7 +43,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-016.https.html b/css/css-paint-api/parse-input-arguments-016.https.html
index 4bea1b4..8c9d05d 100644
--- a/css/css-paint-api/parse-input-arguments-016.https.html
+++ b/css/css-paint-api/parse-input-arguments-016.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -42,7 +42,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-017.https.html b/css/css-paint-api/parse-input-arguments-017.https.html
index 38f9f43..0d14fe74 100644
--- a/css/css-paint-api/parse-input-arguments-017.https.html
+++ b/css/css-paint-api/parse-input-arguments-017.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -41,7 +41,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-018.https.html b/css/css-paint-api/parse-input-arguments-018.https.html
index 9d03a8d..541332a 100644
--- a/css/css-paint-api/parse-input-arguments-018.https.html
+++ b/css/css-paint-api/parse-input-arguments-018.https.html
@@ -13,7 +13,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<p>This test result should show a rect with black border, where the rect is
filled with green on the lower right corner. The registerPaint('failureIndicator')
@@ -63,7 +63,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-019.https.html b/css/css-paint-api/parse-input-arguments-019.https.html
index 76627fb..707a0c6 100644
--- a/css/css-paint-api/parse-input-arguments-019.https.html
+++ b/css/css-paint-api/parse-input-arguments-019.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -41,7 +41,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-020.https.html b/css/css-paint-api/parse-input-arguments-020.https.html
index b582555..fe8dbad 100644
--- a/css/css-paint-api/parse-input-arguments-020.https.html
+++ b/css/css-paint-api/parse-input-arguments-020.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -40,7 +40,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-021.https.html b/css/css-paint-api/parse-input-arguments-021.https.html
index 666d4c4..0c3a596 100644
--- a/css/css-paint-api/parse-input-arguments-021.https.html
+++ b/css/css-paint-api/parse-input-arguments-021.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -43,7 +43,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/parse-input-arguments-022.https.html b/css/css-paint-api/parse-input-arguments-022.https.html
index 3c5d9f9..50aaa6b 100644
--- a/css/css-paint-api/parse-input-arguments-022.https.html
+++ b/css/css-paint-api/parse-input-arguments-022.https.html
@@ -12,7 +12,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -41,7 +41,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/registered-properties-in-custom-paint.https.html b/css/css-paint-api/registered-properties-in-custom-paint.https.html
index c446347..00b0368 100644
--- a/css/css-paint-api/registered-properties-in-custom-paint.https.html
+++ b/css/css-paint-api/registered-properties-in-custom-paint.https.html
@@ -14,7 +14,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -56,7 +56,7 @@
CSS.registerProperty({name: '--length', syntax: '<length>', initialValue: '0px'});
CSS.registerProperty({name: '--length-initial', syntax: '<length>', initialValue: '20px'});
CSS.registerProperty({name: '--number', syntax: '<number>', initialValue: '0'});
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/style-background-image.https.html b/css/css-paint-api/style-background-image.https.html
index 7853607..6eeaf3c 100644
--- a/css/css-paint-api/style-background-image.https.html
+++ b/css/css-paint-api/style-background-image.https.html
@@ -14,7 +14,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
@@ -56,7 +56,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/style-before-pseudo.https.html b/css/css-paint-api/style-before-pseudo.https.html
index 5249f58..bf3f69f 100644
--- a/css/css-paint-api/style-before-pseudo.https.html
+++ b/css/css-paint-api/style-before-pseudo.https.html
@@ -18,7 +18,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body style="font: 10px/1 Ahem;">
<div></div>
@@ -57,7 +57,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/style-first-letter-pseudo.https.html b/css/css-paint-api/style-first-letter-pseudo.https.html
index 3cdffb4..b8a22ce 100644
--- a/css/css-paint-api/style-first-letter-pseudo.https.html
+++ b/css/css-paint-api/style-first-letter-pseudo.https.html
@@ -15,7 +15,7 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
+<script src="/common/worklet-reftest.js"></script>
<body style="font: 10px/1 Ahem;">
<div>ppp</div>
@@ -51,7 +51,7 @@
</script>
<script>
- importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent);
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>
diff --git a/css/css-paint-api/valid-image-after-load.https.html b/css/css-paint-api/valid-image-after-load.https.html
index 73557d2..44612f9 100644
--- a/css/css-paint-api/valid-image-after-load.https.html
+++ b/css/css-paint-api/valid-image-after-load.https.html
@@ -9,7 +9,6 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
<body>
<div id="output"></div>
diff --git a/css/css-paint-api/valid-image-before-load.https.html b/css/css-paint-api/valid-image-before-load.https.html
index 483d16c..7738d9d 100644
--- a/css/css-paint-api/valid-image-before-load.https.html
+++ b/css/css-paint-api/valid-image-before-load.https.html
@@ -9,7 +9,6 @@
}
</style>
<script src="/common/reftest-wait.js"></script>
-<script src="/common/css-paint-tests.js"></script>
<body>
<div id="output"></div>
diff --git a/css/css-pseudo/first-letter-property-whitelist.html b/css/css-pseudo/first-letter-property-whitelist.html
new file mode 100644
index 0000000..073e554
--- /dev/null
+++ b/css/css-pseudo/first-letter-property-whitelist.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<title>CSS Test: Properties allowed on ::first-letter pseudo elements</title>
+<link rel="author" title="Chris Nardi" href="mailto:cnardi@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#first-letter-styling">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+#target::first-letter {}
+#target { visibility: hidden; }
+</style>
+<div id="target">text</div>
+<script>
+'use strict';
+var style;
+const target = document.querySelector("#target");
+var defaultComputedStyle = getComputedStyle(target);
+
+test(function() {
+ var styleRule = document.styleSheets[0].cssRules[0];
+ assert_equals(styleRule.selectorText, '#target::first-letter', 'make sure we have the correct style rule');
+ style = styleRule.style;
+}, 'pre test setup');
+
+var validProperties = {
+ backgroundAttachment: 'fixed',
+ backgroundBlendMode: 'hue',
+ backgroundClip: 'padding-box',
+ backgroundColor: 'rgb(10, 20, 30)',
+ backgroundImage: 'linear-gradient(black, white)',
+ backgroundOrigin: 'border-box',
+ backgroundPosition: 'left 10px top 20px',
+ backgroundRepeat: 'no-repeat',
+ backgroundSize: '10px 20px',
+ border: '40px dotted rgb(10, 20, 30)',
+ borderImage: 'linear-gradient(black, white) 10% / 20 / 30px repeat',
+ borderRadius: '10px 20px',
+ boxShadow: 'rgb(10, 20, 30) 10px 20px 30px 40px inset',
+ color: 'rgba(10, 20, 30, 0.4)',
+ float: 'right',
+ font: 'italic small-caps 900 normal 10px / 20px sans-serif',
+ fontFeatureSettings: '"vert" 2',
+ fontSizeAdjust: '0.5',
+ fontKerning: 'none',
+ fontVariationSettings: '"XHGT" 0.7',
+ letterSpacing: '12px',
+ margin: '10px 20px 30px 40px',
+ padding: '10px 20px 30px 40px',
+ opacity: '0.5',
+ textDecoration: 'overline wavy rgb(10, 20, 30)',
+ textJustify: 'inter-word',
+ textShadow: 'rgb(10, 20, 30) 10px 20px 30px',
+ textTransform: 'capitalize',
+ textUnderlinePosition: 'under',
+ verticalAlign: '12%',
+ wordSpacing: '12px'
+};
+
+var invalidProperties = {
+ transition: 'transform 1s',
+ transform: 'rotate(45deg)',
+ wordBreak: 'break-all'
+};
+
+function testFirstLetterProperty(property, rule, expected, reason) {
+ test(function() {
+ style[property] = "";
+ style[property] = rule;
+ assert_equals(getComputedStyle(target, '::first-letter')[property], expected);
+ style[property] = "";
+ }, reason);
+}
+
+for (var property in validProperties) {
+ testFirstLetterProperty(property, validProperties[property], validProperties[property],
+ "Whitelisted property " + property + " should be applied to first-letter pseudo elements.");
+}
+
+for (var property in invalidProperties) {
+ testFirstLetterProperty(property, invalidProperties[property], defaultComputedStyle[property],
+ "Non-whitelisted property " + property + " should not be applied to first-letter pseudo elements.");
+}
+</script>
diff --git a/css/css-typed-om/resources/testhelper.js b/css/css-typed-om/resources/testhelper.js
index 0099da2..91af64c 100644
--- a/css/css-typed-om/resources/testhelper.js
+++ b/css/css-typed-om/resources/testhelper.js
@@ -57,6 +57,9 @@
case 'CSSSkewX':
assert_style_value_equals(a.ax, b.ax);
break;
+ case 'CSSSkewY':
+ assert_style_value_equals(a.ay, b.ay);
+ break;
case 'CSSPerspective':
assert_style_value_equals(a.length, b.length);
break;
diff --git a/css/css-typed-om/stylevalue-normalization/normalize-tokens.tentative.html b/css/css-typed-om/stylevalue-normalization/normalize-tokens.tentative.html
index 3311380..5e58bea 100644
--- a/css/css-typed-om/stylevalue-normalization/normalize-tokens.tentative.html
+++ b/css/css-typed-om/stylevalue-normalization/normalize-tokens.tentative.html
@@ -29,22 +29,22 @@
{
value: 'var(--A, 1em)',
expectedResult: [
- new CSSVariableReferenceValue('--A', new CSSUnparsedValue(' 1em')),
+ new CSSVariableReferenceValue('--A', new CSSUnparsedValue([' 1em'])),
]
},
{
value: 'var(--A, var(--B))',
expectedResult: [
- new CSSVariableReferenceValue('--A', new CSSUnparsedValue(' ', new CSSVariableReferenceValue('--B'))),
+ new CSSVariableReferenceValue('--A', new CSSUnparsedValue([' ', new CSSVariableReferenceValue('--B')])),
]
},
{
value: 'calc(42px + var(--foo, 15em) + var(--bar, var(--far) + 15px))',
expectedResult: [
'calc(42px + ',
- new CSSVariableReferenceValue('--foo', new CSSUnparsedValue(' 15em')),
+ new CSSVariableReferenceValue('--foo', new CSSUnparsedValue([' 15em'])),
' + ',
- new CSSVariableReferenceValue('--bar', new CSSUnparsedValue(' ', new CSSVariableReferenceValue('--far'), ' + 15px')),
+ new CSSVariableReferenceValue('--bar', new CSSUnparsedValue([' ', new CSSVariableReferenceValue('--far'), ' + 15px'])),
')',
]
},
@@ -52,11 +52,11 @@
for (const {value, expectedResult} of gTestCases) {
test(t => {
- assert_string_normalizes_to(t, 'color', value, new CSSUnparsedValue(...expectedResult));
+ assert_string_normalizes_to(t, 'color', value, new CSSUnparsedValue(expectedResult));
}, 'Normalizing "' + value + '" on a CSS property returns correct CSSUnparsedValue');
test(t => {
- assert_string_normalizes_to(t, '--X', value, new CSSUnparsedValue(...expectedResult));
+ assert_string_normalizes_to(t, '--X', value, new CSSUnparsedValue(expectedResult));
}, 'Normalizing "' + value + '" on a custom property returns correct CSSUnparsedValue');
}
diff --git a/css/css-typed-om/stylevalue-normalization/transformvalue-normalization.tentative.html b/css/css-typed-om/stylevalue-normalization/transformvalue-normalization.tentative.html
index 626c4bb..9157ae8 100644
--- a/css/css-typed-om/stylevalue-normalization/transformvalue-normalization.tentative.html
+++ b/css/css-typed-om/stylevalue-normalization/transformvalue-normalization.tentative.html
@@ -140,7 +140,7 @@
},
{
cssText: 'skewY(90deg)',
- expected: new CSSSkew(CSS.deg(0), CSS.deg(90)),
+ expected: new CSSSkewY(CSS.deg(90)),
desc: 'skewY()'
},
{
@@ -158,13 +158,14 @@
test(t => {
test_transform_normalization(t,
- 'translate(1px) rotateX(90deg) perspective(1px) skew(90deg) skewX(20deg) scale3d(1, 2, 3)',
+ 'translate(1px) rotateX(90deg) perspective(1px) skew(90deg) skewX(20deg) skewY(30deg) scale3d(1, 2, 3)',
new CSSTransformValue([
new CSSTranslate(CSS.px(1), CSS.px(0)),
new CSSRotate(CSS.number(1), CSS.number(0), CSS.number(0), CSS.deg(90)),
new CSSPerspective(CSS.px(1)),
new CSSSkew(CSS.deg(90), CSS.deg(0)),
new CSSSkewX(CSS.deg(20)),
+ new CSSSkewY(CSS.deg(30)),
new CSSScale(CSS.number(1), CSS.number(2), CSS.number(3)),
]));
}, 'Normalizing a <transform-list> returns a CSSTransformValue containing all the transforms');
diff --git a/css/css-typed-om/stylevalue-serialization/cssTransformValue.tentative.html b/css/css-typed-om/stylevalue-serialization/cssTransformValue.tentative.html
index 48926ad..dc87e81 100644
--- a/css/css-typed-om/stylevalue-serialization/cssTransformValue.tentative.html
+++ b/css/css-typed-om/stylevalue-serialization/cssTransformValue.tentative.html
@@ -55,6 +55,11 @@
desc: 'CSSSkewX'
},
{
+ value: new CSSSkewY(CSS.deg(90)),
+ cssText: 'skewY(90deg)',
+ desc: 'CSSSkewY'
+ },
+ {
value: new CSSPerspective(CSS.px(1)),
cssText: 'perspective(1px)',
desc: 'CSSPerspective'
diff --git a/css/css-typed-om/stylevalue-serialization/cssUnparsedValue.html b/css/css-typed-om/stylevalue-serialization/cssUnparsedValue.html
index 8b7a868..6fc2e02 100644
--- a/css/css-typed-om/stylevalue-serialization/cssUnparsedValue.html
+++ b/css/css-typed-om/stylevalue-serialization/cssUnparsedValue.html
@@ -11,25 +11,25 @@
'use strict';
test(() => {
- assert_equals(new CSSUnparsedValue('lem', 'on', 'ade').toString(), 'lemonade');
+ assert_equals(new CSSUnparsedValue(['lem', 'on', 'ade']).toString(), 'lemonade');
}, 'CSSUnparsedValue containing strings serializes to its concatenated contents');
test(() => {
- assert_equals(new CSSUnparsedValue(
+ assert_equals(new CSSUnparsedValue([
new CSSVariableReferenceValue('--A',
- new CSSUnparsedValue(new CSSVariableReferenceValue('--B'))),
- new CSSVariableReferenceValue('--C')).toString(),
+ new CSSUnparsedValue([new CSSVariableReferenceValue('--B')])),
+ new CSSVariableReferenceValue('--C')]).toString(),
'var(--A,var(--B))var(--C)');
}, 'CSSUnparsedValue containing variable references serializes its ' +
'concatenated contents');
test(() => {
- assert_equals(new CSSUnparsedValue('foo', 'bar ',
+ assert_equals(new CSSUnparsedValue(['foo', 'bar ',
new CSSVariableReferenceValue('--A',
- new CSSUnparsedValue('baz ',
- new CSSVariableReferenceValue('--B'), 'lemon')),
+ new CSSUnparsedValue(['baz ',
+ new CSSVariableReferenceValue('--B'), 'lemon'])),
new CSSVariableReferenceValue('--C',
- new CSSUnparsedValue('ade'))).toString(),
+ new CSSUnparsedValue(['ade']))]).toString(),
'foobar var(--A,baz var(--B)lemon)var(--C,ade)');
}, 'CSSUnparsedValue containing mix of strings and variable references ' +
'serializes to its concatenated contents');
diff --git a/css/css-typed-om/stylevalue-subclasses/cssSkewY.tentative.html b/css/css-typed-om/stylevalue-subclasses/cssSkewY.tentative.html
new file mode 100644
index 0000000..643d2f6
--- /dev/null
+++ b/css/css-typed-om/stylevalue-subclasses/cssSkewY.tentative.html
@@ -0,0 +1,62 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSSkewY tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#cssskewy">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const gInvalidTestCases = [
+ { value: 'auto', desc: 'a keyword'},
+ { value: 3.14, desc: 'a double'},
+ { value: 0, desc: 'a unitless zero'},
+ { value: '10deg', desc: 'a string angle'},
+ { value: CSS.number(10), desc: 'a number CSSUnitValue'},
+ { value: CSS.s(10), desc: 'a time dimension CSSUnitValue'},
+ { value: new CSSMathSum(CSS.px(1)), desc: 'a CSSMathValue of length type' },
+];
+
+for (const {value, desc} of gInvalidTestCases) {
+ test(() => {
+ assert_throws(new TypeError(), () => new CSSSkewY(value));
+ }, 'Constructing a CSSSkewY with ' + desc + ' throws a TypeError');
+}
+
+for (const {value, desc} of gInvalidTestCases) {
+ test(() => {
+ let skewY = new CSSSkewY(CSS.deg(0));
+ assert_throws(new TypeError(), () => skewY.ay = value);
+ assert_style_value_equals(skewY.ay, CSS.deg(0));
+ }, 'Updating CSSSkewY.ay with ' + desc + ' throws a TypeError');
+}
+
+const gValidTestCases = [
+ { value: CSS.deg(-3.14), desc: 'an angle CSSUnitValue' },
+ { value: new CSSMathSum(CSS.deg(1)), desc: 'a CSSMathValue of angle type' },
+];
+
+for (const {value: ay, desc: ayDesc} of gValidTestCases) {
+ test(() => {
+ const skewY = new CSSSkewY(ay);
+ assert_equals(skewY.ay, ay);
+ assert_true(skewY.is2D);
+ }, 'CSSSkewY can be constructed from ' + ayDesc);
+}
+
+for (const {value, desc} of gValidTestCases) {
+ test(() => {
+ let skewY = new CSSSkewY(CSS.deg(0));
+ skewY.ay = value;
+ assert_style_value_equals(skewY.ay, value);
+ }, 'CSSSkewY.ay can be updated to ' + desc);
+}
+
+test(() => {
+ let skewY = new CSSSkewY(CSS.deg(0));
+ skewY.is2D = false;
+ assert_true(skewY.is2D);
+}, 'Modifying skewY.is2D is a no-op');
+
+</script>
diff --git a/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue.html b/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue.html
index 3a994dd..8af27e1 100644
--- a/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue.html
+++ b/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue.html
@@ -37,7 +37,7 @@
for (const {args, description} of gTestArguments) {
test(() => {
- const result = new CSSUnparsedValue(...args);
+ const result = new CSSUnparsedValue(args);
assert_not_equals(result, null,
'A CSSUnparsedValue should be created');
diff --git a/css/css-typed-om/stylevalue-subclasses/cssVariableReferenceValue.html b/css/css-typed-om/stylevalue-subclasses/cssVariableReferenceValue.html
index 24082eb..e729acf 100644
--- a/css/css-typed-om/stylevalue-subclasses/cssVariableReferenceValue.html
+++ b/css/css-typed-om/stylevalue-subclasses/cssVariableReferenceValue.html
@@ -22,7 +22,7 @@
test(() => {
const result = new CSSVariableReferenceValue('--foo',
- new CSSUnparsedValue('lemon'));
+ new CSSUnparsedValue(['lemon']));
assert_not_equals(result, null,
'A CSSVariableReferenceValue should be created');
@@ -30,7 +30,7 @@
'Variable member should be same as passed in the constructor');
assert_not_equals(result.fallback, null,
'Fallback member should not be null');
- assert_style_value_equals(result.fallback, new CSSUnparsedValue('lemon'),
+ assert_style_value_equals(result.fallback, new CSSUnparsedValue(['lemon']),
'Fallback member should be as same as passed in the constructor');
}, 'CSSVariableReferenceValue can be constructed with fallback');
diff --git a/css/css-typed-om/the-stylepropertymap/computed/computed.tentative.html b/css/css-typed-om/the-stylepropertymap/computed/computed.tentative.html
index d2a68e7..edadefa 100644
--- a/css/css-typed-om/the-stylepropertymap/computed/computed.tentative.html
+++ b/css/css-typed-om/the-stylepropertymap/computed/computed.tentative.html
@@ -38,7 +38,7 @@
test(() => {
const result = styleMap.get('--foo');
- assert_style_value_equals(result, new CSSUnparsedValue(' auto'));
+ assert_style_value_equals(result, new CSSUnparsedValue([' auto']));
}, 'Computed StylePropertyMap contains custom property declarations in style rules');
test(() => {
@@ -48,7 +48,7 @@
test(() => {
const result = styleMap.get('--bar');
- assert_style_value_equals(result, new CSSUnparsedValue(' 5'));
+ assert_style_value_equals(result, new CSSUnparsedValue([' 5']));
}, 'Computed StylePropertyMap contains custom property declarations in inline rules');
test(() => {
diff --git a/css/css-typed-om/the-stylepropertymap/computed/get.html b/css/css-typed-om/the-stylepropertymap/computed/get.html
index c11ca73..3e061e1 100644
--- a/css/css-typed-om/the-stylepropertymap/computed/get.html
+++ b/css/css-typed-om/the-stylepropertymap/computed/get.html
@@ -24,7 +24,7 @@
test(t => {
const styleMap = createComputedStyleMap(t, '--foo: auto; --bar: 10px');
assert_style_value_equals(styleMap.get('--foo'),
- new CSSUnparsedValue(' auto'));
+ new CSSUnparsedValue([' auto']));
}, 'Getting a valid custom property from computed style returns the ' +
'correct entry');
diff --git a/css/css-typed-om/the-stylepropertymap/computed/getAll.tentative.html b/css/css-typed-om/the-stylepropertymap/computed/getAll.tentative.html
index cd8dcd0..ca7d3b6 100644
--- a/css/css-typed-om/the-stylepropertymap/computed/getAll.tentative.html
+++ b/css/css-typed-om/the-stylepropertymap/computed/getAll.tentative.html
@@ -31,7 +31,7 @@
test(t => {
const styleMap = createComputedStyleMap(t, '--foo: auto; --bar: 10px');
- assert_style_value_array_equals(styleMap.getAll('--foo'), [new CSSUnparsedValue(' auto')]);
+ assert_style_value_array_equals(styleMap.getAll('--foo'), [new CSSUnparsedValue([' auto'])]);
}, 'Calling StylePropertyMap.getAll with a valid custom property returns a single element list with the correct entry');
test(t => {
diff --git a/css/css-typed-om/the-stylepropertymap/computed/iterable.tentative.html b/css/css-typed-om/the-stylepropertymap/computed/iterable.tentative.html
index 07d59d8..4006b20 100644
--- a/css/css-typed-om/the-stylepropertymap/computed/iterable.tentative.html
+++ b/css/css-typed-om/the-stylepropertymap/computed/iterable.tentative.html
@@ -34,9 +34,9 @@
test(t => {
const styleMap = createComputedStyleMap(t, '--A: A; --C: C; color: red; --B: B;');
- assert_style_value_equals(findInStyleMap(styleMap, '--A'), new CSSUnparsedValue(' A'));
- assert_style_value_equals(findInStyleMap(styleMap, '--B'), new CSSUnparsedValue(' B'));
- assert_style_value_equals(findInStyleMap(styleMap, '--C'), new CSSUnparsedValue(' C'));
+ assert_style_value_equals(findInStyleMap(styleMap, '--A'), new CSSUnparsedValue([' A']));
+ assert_style_value_equals(findInStyleMap(styleMap, '--B'), new CSSUnparsedValue([' B']));
+ assert_style_value_equals(findInStyleMap(styleMap, '--C'), new CSSUnparsedValue([' C']));
}, 'StylePropertyMap iterator returns custom properties with the correct CSSStyleValue');
</script>
diff --git a/css/css-typed-om/the-stylepropertymap/declared/declared.tentative.html b/css/css-typed-om/the-stylepropertymap/declared/declared.tentative.html
index 355a509..b1d7ce6 100644
--- a/css/css-typed-om/the-stylepropertymap/declared/declared.tentative.html
+++ b/css/css-typed-om/the-stylepropertymap/declared/declared.tentative.html
@@ -45,7 +45,7 @@
}, 'Declared StylePropertyMap does not contain inline styles');
test(() => {
- assert_style_value_equals(styleMap.get('--foo'), new CSSUnparsedValue(' auto'));
+ assert_style_value_equals(styleMap.get('--foo'), new CSSUnparsedValue([' auto']));
}, 'Declared StylePropertyMap contains custom property declarations');
test(() => {
diff --git a/css/css-typed-om/the-stylepropertymap/declared/get.html b/css/css-typed-om/the-stylepropertymap/declared/get.html
index aa649df..c4215cb 100644
--- a/css/css-typed-om/the-stylepropertymap/declared/get.html
+++ b/css/css-typed-om/the-stylepropertymap/declared/get.html
@@ -29,7 +29,7 @@
test(t => {
const styleMap = createDeclaredStyleMap(t, '--foo: auto; --bar: 10px');
assert_style_value_equals(styleMap.get('--foo'),
- new CSSUnparsedValue(' auto'));
+ new CSSUnparsedValue([' auto']));
}, 'Getting a valid custom property from CSS rule returns the ' +
'correct entry');
diff --git a/css/css-typed-om/the-stylepropertymap/declared/getAll.tentative.html b/css/css-typed-om/the-stylepropertymap/declared/getAll.tentative.html
index 5fe635c..dd4e90b 100644
--- a/css/css-typed-om/the-stylepropertymap/declared/getAll.tentative.html
+++ b/css/css-typed-om/the-stylepropertymap/declared/getAll.tentative.html
@@ -36,7 +36,7 @@
test(t => {
const styleMap = createDeclaredStyleMap(t, '--foo: auto; --bar: 10px');
- assert_style_value_array_equals(styleMap.getAll('--foo'), [new CSSUnparsedValue(' auto')]);
+ assert_style_value_array_equals(styleMap.getAll('--foo'), [new CSSUnparsedValue([' auto'])]);
}, 'Calling StylePropertyMap.getAll with a valid custom property returns a single element list with the correct entry');
test(t => {
diff --git a/css/css-typed-om/the-stylepropertymap/declared/iterable.tentative.html b/css/css-typed-om/the-stylepropertymap/declared/iterable.tentative.html
index be61e25..0609010 100644
--- a/css/css-typed-om/the-stylepropertymap/declared/iterable.tentative.html
+++ b/css/css-typed-om/the-stylepropertymap/declared/iterable.tentative.html
@@ -42,9 +42,9 @@
assert_array_equals(keys, ['--A', '--B', '--C']);
assert_style_value_array_equals(values, [
- new CSSUnparsedValue(' A'),
- new CSSUnparsedValue(' B'),
- new CSSUnparsedValue(' C'),
+ new CSSUnparsedValue([' A']),
+ new CSSUnparsedValue([' B']),
+ new CSSUnparsedValue([' C']),
])
}, 'StylePropertyMap iterator returns custom properties with the correct CSSStyleValue');
diff --git a/css/css-typed-om/the-stylepropertymap/declared/set.tentative.html b/css/css-typed-om/the-stylepropertymap/declared/set.tentative.html
index fe4cced..232c7d3 100644
--- a/css/css-typed-om/the-stylepropertymap/declared/set.tentative.html
+++ b/css/css-typed-om/the-stylepropertymap/declared/set.tentative.html
@@ -63,11 +63,11 @@
test(t => {
let styleMap = createDeclaredStyleMap(t, '');
- styleMap.set('--foo', new CSSUnparsedValue('auto'));
- assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue('auto'));
+ styleMap.set('--foo', new CSSUnparsedValue(['auto']));
+ assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue(['auto']));
styleMap.set('--foo', '20px');
- assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue('20px'));
+ assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue(['20px']));
}, 'Setting a custom property with CSSStyleValue or String updates its value');
test(t => {
diff --git a/css/css-typed-om/the-stylepropertymap/declared/update.tentative.html b/css/css-typed-om/the-stylepropertymap/declared/update.tentative.html
index a5ee95e..8602e2c 100644
--- a/css/css-typed-om/the-stylepropertymap/declared/update.tentative.html
+++ b/css/css-typed-om/the-stylepropertymap/declared/update.tentative.html
@@ -46,11 +46,11 @@
test(t => {
let styleMap = createDeclaredStyleMap(t, '');
- styleMap.update('--foo', () => new CSSUnparsedValue('auto'));
- assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue('auto'));
+ styleMap.update('--foo', () => new CSSUnparsedValue(['auto']));
+ assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue(['auto']));
- styleMap.update('--foo', () => new CSSUnparsedValue('20px'));
- assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue('20px'));
+ styleMap.update('--foo', () => new CSSUnparsedValue(['20px']));
+ assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue(['20px']));
}, 'Updating a custom property with CSSStyleValue updates its value');
test(t => {
diff --git a/css/css-typed-om/the-stylepropertymap/inline/get.html b/css/css-typed-om/the-stylepropertymap/inline/get.html
index ac7c6e4..8588e6e 100644
--- a/css/css-typed-om/the-stylepropertymap/inline/get.html
+++ b/css/css-typed-om/the-stylepropertymap/inline/get.html
@@ -29,7 +29,7 @@
test(t => {
const styleMap = createInlineStyleMap(t, '--foo: auto; --bar: 10px');
assert_style_value_equals(styleMap.get('--foo'),
- new CSSUnparsedValue(' auto'));
+ new CSSUnparsedValue([' auto']));
}, 'Getting a valid custom property from inline style returns the ' +
'correct entry');
diff --git a/css/css-typed-om/the-stylepropertymap/inline/getAll.tentative.html b/css/css-typed-om/the-stylepropertymap/inline/getAll.tentative.html
index 62cbec3..c7e3700 100644
--- a/css/css-typed-om/the-stylepropertymap/inline/getAll.tentative.html
+++ b/css/css-typed-om/the-stylepropertymap/inline/getAll.tentative.html
@@ -36,7 +36,7 @@
test(t => {
const styleMap = createInlineStyleMap(t, '--foo: auto; --bar: 10px');
- assert_style_value_array_equals(styleMap.getAll('--foo'), [new CSSUnparsedValue(' auto')]);
+ assert_style_value_array_equals(styleMap.getAll('--foo'), [new CSSUnparsedValue([' auto'])]);
}, 'Calling StylePropertyMap.getAll with a valid custom property returns a single element list with the correct entry');
test(t => {
diff --git a/css/css-typed-om/the-stylepropertymap/inline/iterable.tentative.html b/css/css-typed-om/the-stylepropertymap/inline/iterable.tentative.html
index cbf76d8..ebd1df7 100644
--- a/css/css-typed-om/the-stylepropertymap/inline/iterable.tentative.html
+++ b/css/css-typed-om/the-stylepropertymap/inline/iterable.tentative.html
@@ -42,9 +42,9 @@
assert_array_equals(keys, ['--A', '--B', '--C']);
assert_style_value_array_equals(values, [
- new CSSUnparsedValue(' A'),
- new CSSUnparsedValue(' B'),
- new CSSUnparsedValue(' C'),
+ new CSSUnparsedValue([' A']),
+ new CSSUnparsedValue([' B']),
+ new CSSUnparsedValue([' C']),
])
}, 'StylePropertyMap iterator returns custom properties with the correct CSSStyleValue');
diff --git a/css/css-typed-om/the-stylepropertymap/inline/set.tentative.html b/css/css-typed-om/the-stylepropertymap/inline/set.tentative.html
index dc8ccc5..67d2426d 100644
--- a/css/css-typed-om/the-stylepropertymap/inline/set.tentative.html
+++ b/css/css-typed-om/the-stylepropertymap/inline/set.tentative.html
@@ -63,11 +63,11 @@
test(t => {
let styleMap = createInlineStyleMap(t, '');
- styleMap.set('--foo', new CSSUnparsedValue('auto'));
- assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue('auto'));
+ styleMap.set('--foo', new CSSUnparsedValue(['auto']));
+ assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue(['auto']));
styleMap.set('--foo', '20px');
- assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue('20px'));
+ assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue(['20px']));
}, 'Setting a custom property with CSSStyleValue or String updates its value');
test(t => {
diff --git a/css/css-typed-om/the-stylepropertymap/inline/update.tentative.html b/css/css-typed-om/the-stylepropertymap/inline/update.tentative.html
index ac2d834..77f2c10 100644
--- a/css/css-typed-om/the-stylepropertymap/inline/update.tentative.html
+++ b/css/css-typed-om/the-stylepropertymap/inline/update.tentative.html
@@ -46,11 +46,11 @@
test(t => {
let styleMap = createInlineStyleMap(t, '');
- styleMap.update('--foo', () => new CSSUnparsedValue('auto'));
- assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue('auto'));
+ styleMap.update('--foo', () => new CSSUnparsedValue(['auto']));
+ assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue(['auto']));
- styleMap.update('--foo', () => new CSSUnparsedValue('20px'));
- assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue('20px'));
+ styleMap.update('--foo', () => new CSSUnparsedValue(['20px']));
+ assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue(['20px']));
}, 'Updating a custom property with CSSStyleValue updates its value');
test(t => {
diff --git a/css/css-writing-modes/available-size-011.html b/css/css-writing-modes/available-size-011.html
new file mode 100644
index 0000000..38aa583
--- /dev/null
+++ b/css/css-writing-modes/available-size-011.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<title>orthogonal flow parent with max-height</title>
+<meta charset=utf-8>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto">
+<meta name="assert" content="If an orthogonal flow's parent doesn't have a definite block size but does have a max block size, use that as the available size">
+<link rel="match" href="reference/available-size-011-ref.html">
+<meta name="flags" content="">
+<style>
+main {
+ max-height: 1em;
+ line-height: 1em;
+}
+div {
+ writing-mode: vertical-rl;
+}
+</style>
+
+<p>This test passes if the word “PASS” (without the quotation marks) appears below, written horizontally from left to right.
+<main><div>S S A P</div></main>
diff --git a/css/css-writing-modes/available-size-012.html b/css/css-writing-modes/available-size-012.html
new file mode 100644
index 0000000..937129e
--- /dev/null
+++ b/css/css-writing-modes/available-size-012.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Testing Available Space in Orthogonal Flows / max-height + min-height / content height</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto">
+<link rel="match" href="reference/available-size-001-ref.html">
+<meta name="assert" content="When an orthogonal flow's parent doesn't have a definite block size and the nearest ancestor scroller does not have a fixed height but does have a fixed max-height, use that, increased by min-height if it exists and is larger. (same as -001, with min-height)">
+<meta name="flags" content="">
+<style>
+body > div {
+ font-family: monospace; /* to be able to reliably measure things in ch*/
+ font-size: 20px;
+ max-height: 4ch; /* **max**-height does not give the element a definite block size */
+ min-height: 8ch;
+ overflow: hidden;
+ color: transparent;
+ position: relative; /* to act as a container of #red */
+ padding: 1ch 0;
+}
+
+div > div { writing-mode: vertical-rl; }
+
+span {
+ background: green;
+ display: inline-block; /* This should not change it's size or position, but makes the size of the background predictable*/
+}
+
+#red { /* Not necessary when when comparing to the reference, but makes human judgement easier */
+ position: absolute;
+ background: red;
+ left: 0; top: 1ch;
+ writing-mode: vertical-rl;
+ z-index: -1;
+}
+</style>
+
+<p>Test passes if there is a <strong>green rectangle</strong> below and <strong>no red</strong>.
+
+<div>
+ <aside id="red">0</aside>
+ <div>0 0 0 0 <span>0</span> 0 0 0</div> <!-- If this div take its height from
+ the min-height of its parent, it should wrap just right for the green 0 to
+ overlap with the red one. -->
+</div>
diff --git a/css/css-writing-modes/available-size-013.html b/css/css-writing-modes/available-size-013.html
new file mode 100644
index 0000000..1ffd656
--- /dev/null
+++ b/css/css-writing-modes/available-size-013.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Testing Available Space in Orthogonal Flows / height + min-height/ content height</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto">
+<link rel="match" href="reference/available-size-001-ref.html">
+<meta name="assert" content="When an orthogonal flow's parent doesn't have a definite block size and the nearest ancestor scroller does have a fixed height, use that, increased by the min-height if it is set and is larger (same as -003, with min-height).">
+<meta name="flags" content="">
+<style>
+body > div {
+ font-family: monospace; /* to be able to reliably measure things in ch*/
+ font-size: 20px;
+ height: 4ch;
+ min-height: 8ch;
+ width: 300px; /* Shrinkwrapping this div is not what we're interested in testing here, so give it a width. See nested-orthogonal-001.html for that. */
+ overflow: hidden;
+ color: transparent;
+ position: relative; /* to act as a container of #red */
+ writing-mode: vertical-lr;
+ padding: 1ch 0;
+}
+
+div > div { padding-bottom: 2ch; } /* so that the content height of the parent and of the fixed size scrolling ancestor are different */
+div > div > div { writing-mode: vertical-rl; }
+
+span {
+ background: green;
+ display: inline-block; /* This should not change it's size or position, but makes the size of the background predictable*/
+}
+
+#red { /* Not necessary when when comparing to the reference, but makes human judgement easier */
+ position: absolute;
+ background: red;
+ left: 0; top: 1ch;
+ writing-mode: vertical-rl;
+ z-index: -1;
+}
+</style>
+
+<p>Test passes if there is a <strong>green rectangle</strong> below and <strong>no red</strong>.
+
+<div>
+ <aside id="red">0</aside>
+ <div><div>0 0 0 0 <span>0</span> 0 0 0</div></div> <!-- If this div take its height from
+ the height of its scrollable ancestor, it should wrap just right for the green 0 to
+ overlap with the red one. -->
+</div>
diff --git a/css/css-writing-modes/available-size-014.html b/css/css-writing-modes/available-size-014.html
new file mode 100644
index 0000000..e0e41fb
--- /dev/null
+++ b/css/css-writing-modes/available-size-014.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Testing Available Space in Orthogonal Flows / height + min-height / not remaining size</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto">
+<link rel="match" href="reference/available-size-001-ref.html">
+<meta name="assert" content="When an orthogonal flow's parent doesn't have a definite block size and the nearest ancestor scroller does a have fixed height, use that whole height increased by min-height if that's larger, even if some other content already consumes some of it (same as -005, with min-height).">
+<meta name="flags" content="">
+<style>
+body > div {
+ font-family: monospace; /* to be able to reliably measure things in ch*/
+ font-size: 20px;
+ height: 4ch;
+ min-height: 8ch;
+ width: 300px; /* Shrinkwrapping this div is not what we're interested in testing here, so give it a width. See nested-orthogonal-001.html for that. */
+ overflow: hidden;
+ color: transparent;
+ position: relative; /* to act as a container of #red */
+}
+
+div > div { padding-bottom: 2ch; } /* so that the content height of the parent and of the fixed size scrolling ancestor are different */
+div > div > div { writing-mode: vertical-rl; }
+
+span {
+ background: green;
+ display: inline-block; /* This should not change it's size or position, but makes the size of the background predictable*/
+}
+
+#red { /* Not necessary when when comparing to the reference, but makes human judgement easier */
+ position: absolute;
+ background: red;
+ left: 0;
+ writing-mode: vertical-rl;
+ z-index: -1;
+ top: 1ch;
+}
+#spacer { /* shrinks the remaining space of the parent div. */
+ height: 1ch;
+ width: 100%;
+}
+</style>
+
+<p>Test passes if there is a <strong>green rectangle</strong> below and <strong>no red</strong>.
+
+<div>
+ <aside id="red">0</aside>
+ <div><aside id="spacer"></aside><div>0 0 0 0 <span>0</span> 0 0 0</div></div>
+ <!-- If the inner div take its height from the height of its scrollable
+ ancestor, it should wrap just right for the green 0 to overlap with the red
+ one. If instead it takes it size from the remaining height after having
+ removed #spacer, or does some other calculation that takes #spacer into
+ account, it won't line up with #red.-->
+</div>
diff --git a/css/css-writing-modes/available-size-015.html b/css/css-writing-modes/available-size-015.html
new file mode 100644
index 0000000..f7cb13b
--- /dev/null
+++ b/css/css-writing-modes/available-size-015.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Testing Available Space in Orthogonal Flows / ICB / tall max-height + min-height scroller</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto">
+<link rel="match" href="reference/available-size-002-ref.html">
+<meta name="assert" content="When an orthogonal flow's parent doesn't have a definite block size, and there's a scroller with max-height and min-height, and max-height is smaller than the ICB but min-height is larger than the ICB, use the ICB as the available space (same as -008, with min-height).">
+<meta name="flags" content="">
+<style>
+body { margin-top: 0; margin-bottom: 0; } /* Shouldn't matter, but in some browsers does. -007 tests this aspect specifically. */
+div {
+ writing-mode: vertical-rl;
+ font-family: monospace;
+ font-size: 20px;
+ position: relative; /* to be a container for #red*/
+}
+.spacer { /* using 5 spacers of 20vh each instead of a single large one, so
+ that the line would wrap between spacers if it ends up being
+ shorter thatn 100vh*/
+ display: inline-block;
+ height: calc(20vh - 0.1px); /*Using this instead of 20vh, to account for accumulation of rounding errors, that might make 5*20vh taller than 100vh in some browsers*/
+}
+
+span {
+ background: green;
+ display: inline-block; /* This should not change it's size or position, but makes the size of the background predictable*/
+ color: transparent;
+}
+
+#red { /* Not necessary when when comparing to the reference, but makes human judgement easier */
+ position: absolute;
+ background: red;
+ writing-mode: vertical-rl;
+ z-index: -1;
+ font-family: monospace;
+ font-size: 20px;
+ left: 0; top: 0;
+}
+
+section {
+ overflow: hidden;
+ max-height: 40vh;
+ min-height: 120vh;
+}
+</style>
+
+<p>Test passes if there is a <strong>green rectangle</strong> below and <strong>no red</strong>.
+
+<section>
+<div><aside id="red">0</aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside> <span>0</span></div>
+</section>
diff --git a/css/css-writing-modes/available-size-016.html b/css/css-writing-modes/available-size-016.html
new file mode 100644
index 0000000..c3c388e
--- /dev/null
+++ b/css/css-writing-modes/available-size-016.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Testing Available Space in Orthogonal Flows / ICB / tall height + min-height scroller</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto">
+<link rel="match" href="reference/available-size-002-ref.html">
+<meta name="assert" content="When an orthogonal flow's parent doesn't have a definite block size, and there's a scroller with height and min-height, and height is smaller than the ICB but min-height is larger than the ICB, use the ICB as the available space (same as -009, with min-height).">
+<meta name="flags" content="">
+<style>
+body { margin-top: 0; margin-bottom: 0; } /* Shouldn't matter, but in some browsers does. -007 tests this aspect specifically. */
+div {
+ writing-mode: vertical-rl;
+ font-family: monospace;
+ font-size: 20px;
+ position: relative; /* to be a container for #red*/
+}
+.spacer { /* using 5 spacers of 20vh each instead of a single large one, so
+ that the line would wrap between spacers if it ends up being
+ shorter thatn 100vh*/
+ display: inline-block;
+ height: calc(20vh - 0.1px); /*Using this instead of 20vh, to account for accumulation of rounding errors, that might make 5*20vh taller than 100vh in some browsers*/
+}
+
+span {
+ background: green;
+ display: inline-block; /* This should not change it's size or position, but makes the size of the background predictable*/
+ color: transparent;
+}
+
+#red { /* Not necessary when when comparing to the reference, but makes human judgement easier */
+ position: absolute;
+ background: red;
+ writing-mode: vertical-rl;
+ z-index: -1;
+ font-family: monospace;
+ font-size: 20px;
+ left: 0; top: 0;
+}
+
+section {
+ overflow: hidden;
+ writing-mode: vertical-rl;
+ height: 40vh;
+ min-height: 120vh;
+}
+section > section {
+ writing-mode: horizontal-tb;
+}
+</style>
+
+<p>Test passes if there is a <strong>green rectangle</strong> below and <strong>no red</strong>.
+
+<section>
+<div><aside id="red">0</aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside> <span>0</span></div>
+</section>
diff --git a/css/css-writing-modes/available-size-017.html b/css/css-writing-modes/available-size-017.html
new file mode 100644
index 0000000..79f1b85
--- /dev/null
+++ b/css/css-writing-modes/available-size-017.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Testing Available Space in Orthogonal Flows / height + min-height parent</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto">
+<link rel="match" href="reference/available-size-002-ref.html">
+<meta name="assert" content="When an orthogonal flow's parent has a height and a min-height larger than the height, use min-height as the available size.">
+<meta name="flags" content="">
+<style>
+body > div {
+ font-family: monospace; /* to be able to reliably measure things in ch*/
+ font-size: 20px;
+ height: 4ch;
+ min-height: 8ch;
+ color: transparent;
+ position: relative; /* to act as a container of #green */
+}
+
+div > div { writing-mode: vertical-rl; }
+
+span {
+ background: green;
+ display: inline-block; /* This should not change it's size or position, but makes the size of the background predictable*/
+}
+
+#red {
+ position: absolute;
+ background: red;
+ left: 0;
+ writing-mode: vertical-rl;
+ z-index: -1;
+}
+</style>
+
+<p>Test passes if there is a <strong>green rectangle</strong> below and <strong>no red</strong>.
+
+<div>
+ <aside id="red">0</aside>
+ <div>0 0 0 0 <span>0</span> 0 0 0</div> <!-- If this div takes its height from
+ the min-height of its parent (which it should)
+ it should wrap just right for the green 0 to
+ overlap with the red one. -->
+</div>
diff --git a/css/css-writing-modes/available-size-018.html b/css/css-writing-modes/available-size-018.html
new file mode 100644
index 0000000..4e86db7
--- /dev/null
+++ b/css/css-writing-modes/available-size-018.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Testing Available Space in Orthogonal Flows / max-height + min-height parent</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto">
+<link rel="match" href="reference/available-size-002-ref.html">
+<meta name="assert" content="When an orthogonal flow's parent has a max-height and a min-height larger than the height, use min-height as the available size.">
+<meta name="flags" content="">
+<style>
+body > div {
+ font-family: monospace; /* to be able to reliably measure things in ch*/
+ font-size: 20px;
+ max-height: 4ch;
+ min-height: 8ch;
+ color: transparent;
+ position: relative; /* to act as a container of #green */
+}
+
+div > div { writing-mode: vertical-rl; }
+
+span {
+ background: green;
+ display: inline-block; /* This should not change it's size or position, but makes the size of the background predictable*/
+}
+
+#red {
+ position: absolute;
+ background: red;
+ left: 0;
+ writing-mode: vertical-rl;
+ z-index: -1;
+}
+</style>
+
+<p>Test passes if there is a <strong>green rectangle</strong> below and <strong>no red</strong>.
+
+<div>
+ <aside id="red">0</aside>
+ <div>0 0 0 0 <span>0</span> 0 0 0</div> <!-- If this div takes its height from
+ the min-height of its parent (which it should)
+ it should wrap just right for the green 0 to
+ overlap with the red one. -->
+</div>
diff --git a/css/css-writing-modes/reference/available-size-011-ref.html b/css/css-writing-modes/reference/available-size-011-ref.html
new file mode 100644
index 0000000..ef66b4e
--- /dev/null
+++ b/css/css-writing-modes/reference/available-size-011-ref.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>CSS writing mode test reference</title>
+<meta charset=utf-8>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<style>
+div {
+ line-height: 1em;
+ height: 1em;
+ writing-mode: vertical-rl;
+}
+</style>
+
+<p>This test passes if the word “PASS” (without the quotation marks) appears below, written horizontally from left to right.
+<div>S S A P</div>
diff --git a/css/cssom/selectorText-modification-restyle-002.html b/css/cssom/selectorText-modification-restyle-002.html
new file mode 100644
index 0000000..a6b37c2
--- /dev/null
+++ b/css/cssom/selectorText-modification-restyle-002.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<title>CSSOM: Modify selectorText in a shadow tree stylesheet</title>
+<link rel="author" title="Rune Lillesveen" href="mailto:futhark@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/cssom/#dom-cssstylerule-selectortext">
+<link rel="help" href="https://drafts.csswg.org/css-scoping/#selectors">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ #container { color: red }
+ .subtree * { color: pink }
+</style>
+<div id="container">
+ <div id="host"></div>
+</div>
+<script>
+ const root = host.attachShadow({mode:"open"});
+ root.innerHTML = "<style>nomatch { color: green }</style><div>Green</div>";
+ const div = root.querySelector("div");
+
+ test(() => {
+ assert_equals(getComputedStyle(div).color, "rgb(255, 0, 0)", "Color should initial be red.");
+ }, "Check initial color.");
+
+ test(() => {
+ // The combination of the .subtree and CSSOM selector style invalidations
+ // caused the Blink implementation to fail an assertion.
+ container.className = "subtree";
+ root.styleSheets[0].cssRules[0].selectorText = "div";
+ assert_equals(getComputedStyle(div).color, "rgb(0, 128, 0)", "Color should be green after stylesheet change.");
+ }, "Check that color changes correctly after shadow stylesheet selector and #container class is changed.");
+</script>
diff --git a/css/selectors/matches-nested.html b/css/selectors/matches-nested.html
new file mode 100644
index 0000000..b82d43d
--- /dev/null
+++ b/css/selectors/matches-nested.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>CSS Selectors: :matches()</title>
+ <link rel="author" title="Victoria Su" href="mailto:victoriaytsu@google.com">
+ <link rel="help" href="https://drafts.csswg.org/selectors-4/#matches">
+ <meta name="assert" content="This tests that the :matches() selector is effective when nested">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <style>
+ /* Testing that highest specificity is chosen for class outside of :matches() */
+ .a+.b+.c>.e+.d {
+ color: black;
+ font-size: 10px;
+ width: 10px;
+ }
+ .a+:matches(.b+.f, .b+:matches(*, .c>.e, .g, *))+.d {
+ color: red;
+ font-size: 20px;
+ }
+ .a+.b+.c>.e+.d {
+ color: yellow;
+ }
+ /* Testing specificty of a class within :matches() */
+ .a+.c>.e {
+ color: black;
+ }
+ .a+:matches(.b+.f, :matches(.c>.e, .g)) {
+ color: red;
+ }
+ .c>.e {
+ color: black;
+ }
+ </style>
+ </head>
+ <body>
+ <div class="a">
+ </div>
+ <div class="b" id="b2">
+ </div>
+ <div class="c" id="c2">
+ <div class="e">
+ </div>
+ <div class="d" id="d1">
+ Yellow
+ </div>
+ </div>
+ <div class="a">
+ </div>
+ <div class="c" id="c2">
+ <div class="e" id="e1">
+ Red
+ </div>
+ </div>
+ <script>
+
+ var red = "rgb(255, 0, 0)";
+ var yellow = "rgb(255, 255, 0)";
+
+ test(() => {
+ assert_equals(getComputedStyle(d1).color, yellow);
+ assert_equals(getComputedStyle(d1).fontSize, "20px");
+ assert_equals(getComputedStyle(d1).width, "10px");
+ }, "Test nested :matches() chooses highest specificity for class outside :matches().");
+
+ test(() => {
+ assert_equals(getComputedStyle(e1).color, red);
+ }, "Test nested :matches() specificity for class within arguments.");
+
+ </script>
+ </body>
+</html>
\ No newline at end of file
diff --git a/css/selectors/matches-specificity.html b/css/selectors/matches-specificity.html
new file mode 100644
index 0000000..41d7251
--- /dev/null
+++ b/css/selectors/matches-specificity.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>CSS Selectors: :matches()</title>
+ <link rel="author" title="Victoria Su" href="mailto:victoriaytsu@google.com">
+ <link rel="help" href="https://drafts.csswg.org/selectors-4/#matches">
+ <meta name="assert" content="This tests that the :matches() selector chooses the correct specificity">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <style>
+ .b.c + .d + .q.r + .s + #target {
+ font-size: 10px;
+ height: 10px;
+ width: 10px;
+ }
+ :matches(.a, .b.c + .d, .e) + :matches(* + .p, .q.r + .s, * + .t) + #target {
+ height: 20px;
+ width: 20px;
+ }
+ .b.c + .d + .q.r + .s + #target {
+ width: 30px;
+ }
+ </style>
+ </head>
+ <body>
+ <div class="b c"></div>
+ <div class="a d e"></div>
+ <div class="q r"></div>
+ <div class="p s t"></div>
+ <div id="target"></div>
+ <script>
+
+ test(() => {
+ assert_equals(getComputedStyle(target).width, "30px");
+ assert_equals(getComputedStyle(target).height, "20px");
+ assert_equals(getComputedStyle(target).fontSize, "10px");
+ }, "Test :matches() uses highest possible specificity");
+
+ </script>
+ </body>
+</html>
\ No newline at end of file
diff --git a/custom-elements/Document-createElement.html b/custom-elements/Document-createElement.html
index 97a5659..3b89130 100644
--- a/custom-elements/Document-createElement.html
+++ b/custom-elements/Document-createElement.html
@@ -36,12 +36,18 @@
customElements.define('autonomous-custom-element', AutonomousCustomElement);
customElements.define('is-custom-element', IsCustomElement);
- var instance = document.createElement('autonomous-custom-element', { is: "is-custom-element"});
+ 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');
+ var instance2 = document.createElement('undefined-element', { is: 'is-custom-element'});
+ assert_false(instance2.matches(':defined'));
+ class DefinedLater extends HTMLElement {}
+ customElements.define('undefined-element', DefinedLater);
+ document.body.appendChild(instance2);
+ assert_true(instance2 instanceof DefinedLater);
}, 'document.createElement must create an instance of autonomous custom elements when it has is attribute');
function assert_reports(expected, testFunction, message) {
diff --git a/custom-elements/Document-createElementNS.html b/custom-elements/Document-createElementNS.html
index 5711a46..ed30d0d 100644
--- a/custom-elements/Document-createElementNS.html
+++ b/custom-elements/Document-createElementNS.html
@@ -24,6 +24,14 @@
}, 'autonomous: document.createElementNS should check namespaces.');
test(() => {
+ const xhtmlNS = 'http://www.w3.org/1999/xhtml';
+ assert_false(document.createElementNS(xhtmlNS, 'x-foo') instanceof HTMLUnknownElement);
+ assert_false(document.createElementNS(xhtmlNS, 'x-foo', {}) instanceof HTMLUnknownElement);
+ assert_false((new Document()).createElementNS(xhtmlNS, 'x-foo') instanceof HTMLUnknownElement);
+ assert_false((new Document()).createElementNS(xhtmlNS, 'x-foo', {}) instanceof HTMLUnknownElement);
+}, 'autonomous: document.createElementNS should not create HTMLUnknownElement for a valid custom element name');
+
+test(() => {
class MyBuiltinElement extends HTMLElement {};
customElements.define('my-builtin', MyBuiltinElement, { extends: 'address' });
diff --git a/docs/introduction.md b/docs/introduction.md
index c718efd..8833d86 100644
--- a/docs/introduction.md
+++ b/docs/introduction.md
@@ -102,17 +102,22 @@
and read the [Windows Notes](#windows-notes) section below.
To get the tests running, you need to set up the test domains in your
-[`hosts` file](http://en.wikipedia.org/wiki/Hosts_%28file%29%23Location_in_the_file_system). The
-following entries are required:
+[`hosts` file](http://en.wikipedia.org/wiki/Hosts_%28file%29%23Location_in_the_file_system).
+The necessary content can be generated with `./wpt make-hosts-file`; on
+Windows, you will need to preceed the prior command with `python` or
+the path to the Python binary (`python wpt make-hosts-file`).
+
+For example, on most UNIX-like systems, you can setup the hosts file with:
+
+```bash
+./wpt make-hosts-file | sudo tee -a /etc/hosts
```
-127.0.0.1 web-platform.test
-127.0.0.1 www.web-platform.test
-127.0.0.1 www1.web-platform.test
-127.0.0.1 www2.web-platform.test
-127.0.0.1 xn--n8j6ds53lwwkrqhv28a.web-platform.test
-127.0.0.1 xn--lve-6lad.web-platform.test
-0.0.0.0 nonexistent-origin.web-platform.test
+
+And on Windows (note this requires an Administrator privileged shell):
+
+```bash
+python wpt make-hosts-file >> %SystemRoot%\System32\drivers\etc\hosts
```
If you are behind a proxy, you also need to make sure the domains above are
diff --git a/html/editing/editing-0/contenteditable/contentEditable-slotted-inherit.html b/html/editing/editing-0/contenteditable/contentEditable-slotted-inherit.html
new file mode 100644
index 0000000..42da515
--- /dev/null
+++ b/html/editing/editing-0/contenteditable/contentEditable-slotted-inherit.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>contentEditable inherit from light tree parent</title>
+<link rel="author" title="Rune Lillesveen" href="mailto:futhark@chromium.org">
+<link rel=help href="https://html.spec.whatwg.org/multipage/#contenteditable">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<p>You should see the word PASS two times below and no FAIL.</p>
+<div id="host1" contenteditable><div>FAILPASS</div></div>
+<div id="host2" contenteditable><div>FAILPASS</div></div>
+<script>
+ test(() => {
+ const root = host1.attachShadow({mode:"open"});
+ root.innerHTML = "<slot></slot>";
+ const text = host1.firstChild.firstChild;
+ const selection = window.getSelection();
+ selection.collapse(text, 0);
+ selection.extend(text, 4);
+ host1.focus();
+ document.execCommand("delete");
+ host1.blur();
+ assert_equals(text.data, "PASS", "Text should be PASS after FAIL is deleted");
+ }, "Slotted child of contenteditable host should be editable - slot direct child of shadow root");
+
+ test(() => {
+ const root = host2.attachShadow({mode:"open"});
+ root.innerHTML = "<div><slot></slot></div>";
+ const text = host2.firstChild.firstChild;
+ const selection = window.getSelection();
+ selection.collapse(text, 0);
+ selection.extend(text, 4);
+ host2.focus();
+ document.execCommand("delete");
+ host2.blur();
+ assert_equals(text.data, "PASS", "Text should be PASS after FAIL is deleted");
+ }, "Slotted child of contenteditable host should be editable - slot wrapped in shadow tree ancestor");
+</script>
diff --git a/html/semantics/forms/textfieldselection/setSelectionRange.html b/html/semantics/forms/textfieldselection/setSelectionRange.html
new file mode 100644
index 0000000..bdf52a7
--- /dev/null
+++ b/html/semantics/forms/textfieldselection/setSelectionRange.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<meta charset="utf-8">
+<title></title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<textarea>
+
+</textarea>
+<script>
+test(function() {
+ let textarea = document.querySelector('textarea');
+ assert_equals(textarea.selectionStart, 0);
+ assert_equals(textarea.selectionEnd, 0);
+ textarea.setSelectionRange(0, 1);
+ assert_equals(textarea.selectionStart, 0);
+ assert_equals(textarea.selectionEnd, 1);
+}, "setSelectionRange on line boundaries");
+</script>
diff --git a/html/semantics/scripting-1/the-script-element/cacheable-script-throw.py b/html/semantics/scripting-1/the-script-element/cacheable-script-throw.py
new file mode 100644
index 0000000..5df883c
--- /dev/null
+++ b/html/semantics/scripting-1/the-script-element/cacheable-script-throw.py
@@ -0,0 +1,4 @@
+def main(request, response):
+ headers = [("Content-Type", "text/javascript"), ("Cache-control", "public, max-age=100")]
+ body = "throw('fox');"
+ return 200, headers, body
diff --git a/html/semantics/scripting-1/the-script-element/muted-errors-iframe.html b/html/semantics/scripting-1/the-script-element/muted-errors-iframe.html
new file mode 100644
index 0000000..255e79e
--- /dev/null
+++ b/html/semantics/scripting-1/the-script-element/muted-errors-iframe.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<script src="cacheable-script-throw.py?iframe"></script>
diff --git a/html/semantics/scripting-1/the-script-element/muted-errors.sub.html b/html/semantics/scripting-1/the-script-element/muted-errors.sub.html
new file mode 100644
index 0000000..a42179d
--- /dev/null
+++ b/html/semantics/scripting-1/the-script-element/muted-errors.sub.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<title>Muted Errors</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+// https://html.spec.whatwg.org/#report-the-error
+// If script's muted errors is true, then set message to "Script error.",
+// urlString to the empty string, line and col to 0, and errorValue to null.
+ setup({allow_uncaught_exception: true});
+
+ window.log = [];
+ window.addEventListener("error", ev => log.push(ev));
+
+ function check(shouldBeMuted) {
+ assert_equals(log.length, 1);
+ var ev = log[0];
+ log = [];
+ if (shouldBeMuted) {
+ assert_equals(ev.message, "Script error.");
+ assert_equals(ev.error, null, 'error');
+ assert_equals(ev.filename, "", 'filename');
+ assert_equals(ev.lineno, 0, 'lineno');
+ assert_equals(ev.colno, 0, 'colno');
+ } else {
+ assert_not_equals(ev.message, "Script error.");
+ assert_not_equals(ev.error, null);
+ }
+ }
+
+ var test1 = async_test("Errors for same-origin script shouldn't be muted");
+ var check1 = test1.step_func_done(() => check(false));
+
+ var test2 = async_test("Errors for cross-origin script should be muted");
+ var check2 = test2.step_func_done(() => check(true));
+
+ var test3 = async_test("Errors for cross-origin script should be muted " +
+ "even if the script is once loaded as same-origin");
+ function step3() {
+ var script = document.createElement('script');
+ script.setAttribute('src', "//{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/cacheable-script-throw.py?iframe");
+ script.onerror = test3.unreached_func();
+ script.onload = test3.step_func_done(() => check(true));
+ document.body.appendChild(script);
+ }
+ function unreachable() { log.push("unexpected"); }
+</script>
+<script src="cacheable-script-throw.py" onerror="test1.unreached_func()()" onload="check1()"></script>
+<script src="//{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/cacheable-script-throw.py"
+ onerror="test2.unreached_func()()" onload="check2()"></script>
+<iframe src="//{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/muted-errors-iframe.html"
+ onerror="test3.unreached_func()()" onload="step3()"></iframe>
diff --git a/interfaces/accelerometer.idl b/interfaces/accelerometer.idl
index df78885..7e5509d 100644
--- a/interfaces/accelerometer.idl
+++ b/interfaces/accelerometer.idl
@@ -1,11 +1,17 @@
-[Constructor(optional SensorOptions options), SecureContext, Exposed=Window]
+enum LocalCoordinateSystem { "device", "screen" };
+
+dictionary SpatialSensorOptions : SensorOptions {
+ LocalCoordinateSystem referenceFrame = "device";
+};
+
+[Constructor(optional SpatialSensorOptions options), SecureContext, Exposed=Window]
interface Accelerometer : Sensor {
readonly attribute double? x;
readonly attribute double? y;
readonly attribute double? z;
};
-[Constructor(optional SensorOptions options), SecureContext, Exposed=Window]
+[Constructor(optional SpatialSensorOptions options), SecureContext, Exposed=Window]
interface LinearAccelerationSensor : Accelerometer {
};
diff --git a/lint.whitelist b/lint.whitelist
index 2f9b44d..95f82ea 100644
--- a/lint.whitelist
+++ b/lint.whitelist
@@ -225,6 +225,7 @@
SET TIMEOUT: user-timing/*
SET TIMEOUT: webaudio/js/lodash.js
SET TIMEOUT: webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html
+SET TIMEOUT: webauthn/*timeout.https.html
SET TIMEOUT: webdriver/*
SET TIMEOUT: webmessaging/*
SET TIMEOUT: websockets/*
diff --git a/media/foo-no-cors.vtt b/media/foo-no-cors.vtt
new file mode 100644
index 0000000..b533895
--- /dev/null
+++ b/media/foo-no-cors.vtt
@@ -0,0 +1,4 @@
+WEBVTT
+
+00:00:00.000 --> 00:00:05.000
+Foo
diff --git a/offscreen-canvas/drawing-images-to-the-canvas/2d.drawImage.zerocanvas.html b/offscreen-canvas/drawing-images-to-the-canvas/2d.drawImage.zerocanvas.html
index 57210ef..ef66d5e 100644
--- a/offscreen-canvas/drawing-images-to-the-canvas/2d.drawImage.zerocanvas.html
+++ b/offscreen-canvas/drawing-images-to-the-canvas/2d.drawImage.zerocanvas.html
@@ -16,17 +16,16 @@
var offscreenCanvas = new OffscreenCanvas(100, 50);
var ctx = offscreenCanvas.getContext('2d');
-ctx.fillStyle = '#0f0';
-ctx.fillRect(0, 0, 100, 50);
var offscreenCanvas2 = new OffscreenCanvas(0, 10);
-ctx.drawImage(offscreenCanvas2, 0, 0);
+assert_throws("INVALID_STATE_ERR", function() { ctx.drawImage(offscreenCanvas2, 0, 0); });
+
offscreenCanvas2.width = 10;
offscreenCanvas2.height = 0;
-ctx.drawImage(offscreenCanvas2, 0, 0);
+assert_throws("INVALID_STATE_ERR", function() { ctx.drawImage(offscreenCanvas2, 0, 0); });
+
offscreenCanvas2.width = 0;
offscreenCanvas2.height = 0;
-ctx.drawImage(offscreenCanvas2, 0, 0);
-_assertPixelApprox(offscreenCanvas, 50,25, 0,255,0,255, "50,25", "0,255,0,255", 2);
+assert_throws("INVALID_STATE_ERR", function() { ctx.drawImage(offscreenCanvas2, 0, 0); });
t.done();
diff --git a/offscreen-canvas/drawing-images-to-the-canvas/2d.drawImage.zerocanvas.worker.js b/offscreen-canvas/drawing-images-to-the-canvas/2d.drawImage.zerocanvas.worker.js
index 45dfff6..3a17cfe 100644
--- a/offscreen-canvas/drawing-images-to-the-canvas/2d.drawImage.zerocanvas.worker.js
+++ b/offscreen-canvas/drawing-images-to-the-canvas/2d.drawImage.zerocanvas.worker.js
@@ -12,17 +12,16 @@
var offscreenCanvas = new OffscreenCanvas(100, 50);
var ctx = offscreenCanvas.getContext('2d');
-ctx.fillStyle = '#0f0';
-ctx.fillRect(0, 0, 100, 50);
var offscreenCanvas2 = new OffscreenCanvas(0, 10);
-ctx.drawImage(offscreenCanvas2, 0, 0);
+assert_throws("INVALID_STATE_ERR", function() { ctx.drawImage(offscreenCanvas2, 0, 0); });
+
offscreenCanvas2.width = 10;
offscreenCanvas2.height = 0;
-ctx.drawImage(offscreenCanvas2, 0, 0);
+assert_throws("INVALID_STATE_ERR", function() { ctx.drawImage(offscreenCanvas2, 0, 0); });
+
offscreenCanvas2.width = 0;
offscreenCanvas2.height = 0;
-ctx.drawImage(offscreenCanvas2, 0, 0);
-_assertPixelApprox(offscreenCanvas, 50,25, 0,255,0,255, "50,25", "0,255,0,255", 2);
+assert_throws("INVALID_STATE_ERR", function() { ctx.drawImage(offscreenCanvas2, 0, 0); });
t.done();
diff --git a/offscreen-canvas/tools/tests2d.yaml b/offscreen-canvas/tools/tests2d.yaml
index fc3b158..f542d3c 100644
--- a/offscreen-canvas/tools/tests2d.yaml
+++ b/offscreen-canvas/tools/tests2d.yaml
@@ -4417,17 +4417,16 @@
testing:
- 2d.drawImage.zerocanvas
code: |
- ctx.fillStyle = '#0f0';
- ctx.fillRect(0, 0, 100, 50);
var offscreenCanvas2 = new OffscreenCanvas(0, 10);
- ctx.drawImage(offscreenCanvas2, 0, 0);
+ @assert throws INVALID_STATE_ERR ctx.drawImage(offscreenCanvas2, 0, 0);
+
offscreenCanvas2.width = 10;
offscreenCanvas2.height = 0;
- ctx.drawImage(offscreenCanvas2, 0, 0);
+ @assert throws INVALID_STATE_ERR ctx.drawImage(offscreenCanvas2, 0, 0);
+
offscreenCanvas2.width = 0;
offscreenCanvas2.height = 0;
- ctx.drawImage(offscreenCanvas2, 0, 0);
- @assert pixel 50,25 ==~ 0,255,0,255;
+ @assert throws INVALID_STATE_ERR ctx.drawImage(offscreenCanvas2, 0, 0);
- name: 2d.drawImage.wrongtype
desc: Incorrect image types in drawImage do not match any defined overloads, so WebIDL throws a TypeError
diff --git a/picture-in-picture/not-processing-user-gesture.html b/picture-in-picture/not-processing-user-gesture.html
deleted file mode 100644
index 0075894..0000000
--- a/picture-in-picture/not-processing-user-gesture.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!DOCTYPE html>
-<title>Test request Picture-in-Picture requires a user gesture</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<body></body>
-<script>
-promise_test(t => {
- return promise_rejects(t, 'NotAllowedError',
- document.createElement('video').requestPictureInPicture());
-}, );
-</script>
diff --git a/picture-in-picture/request-picture-in-picture.html b/picture-in-picture/request-picture-in-picture.html
index eaabcb7..32bbfc2 100644
--- a/picture-in-picture/request-picture-in-picture.html
+++ b/picture-in-picture/request-picture-in-picture.html
@@ -9,5 +9,21 @@
<script>
promise_test(t => {
return requestPictureInPictureWithTrustedClick(document.createElement('video'));
-});
+}, 'request Picture-in-Picture resolves on user click');
+
+promise_test(t => {
+ return promise_rejects(t, 'NotAllowedError',
+ document.createElement('video').requestPictureInPicture());
+}, 'request Picture-in-Picture requires a user gesture');
+
+promise_test(t => {
+ return callWithTrustedClick(() => {
+ const first = document.createElement('video').requestPictureInPicture();
+ const second = document.createElement('video').requestPictureInPicture();
+ return Promise.all([
+ first,
+ promise_rejects(t, 'NotAllowedError', second)
+ ]);
+ });
+}, 'request Picture-in-Picture consumes user gesture');
</script>
diff --git a/service-workers/service-worker/http-to-https-redirect-and-register.https.html b/service-workers/service-worker/http-to-https-redirect-and-register.https.html
index d78b23a..d1c6678 100644
--- a/service-workers/service-worker/http-to-https-redirect-and-register.https.html
+++ b/service-workers/service-worker/http-to-https-redirect-and-register.https.html
@@ -8,11 +8,13 @@
<script>
'use strict';
+var host_info = get_host_info();
+
// Loads a non-secure url in a new window, which redirects to |target_url|.
// That page then registers a service worker, and messages back with the result.
// Returns a promise that resolves with the result.
function redirect_and_register(target_url) {
- var redirect_url = get_host_info()['UNAUTHENTICATED_ORIGIN'] + base_path() +
+ var redirect_url = host_info.HTTP_REMOTE_ORIGIN + base_path() +
'resources/redirect.py?Redirect=';
var child = window.open(redirect_url + encodeURIComponent(target_url));
return new Promise(resolve => {
@@ -35,7 +37,7 @@
}, 'register on a secure page after redirect from an non-secure url');
promise_test(function(t) {
- var target_url = get_host_info()['UNAUTHENTICATED_ORIGIN'] + base_path() +
+ var target_url = host_info.HTTP_REMOTE_ORIGIN + base_path() +
'resources/http-to-https-redirect-and-register-iframe.html';
return redirect_and_register(target_url)
diff --git a/service-workers/service-worker/resources/vtt-frame.html b/service-workers/service-worker/resources/vtt-frame.html
new file mode 100644
index 0000000..c3ac803
--- /dev/null
+++ b/service-workers/service-worker/resources/vtt-frame.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Page Title</title>
+<video>
+ <track>
+</video>
diff --git a/service-workers/service-worker/update-bytecheck.https.html b/service-workers/service-worker/update-bytecheck.https.html
index 6e4c6ec..ec3d15a 100644
--- a/service-workers/service-worker/update-bytecheck.https.html
+++ b/service-workers/service-worker/update-bytecheck.https.html
@@ -5,6 +5,7 @@
<script src="resources/testharness-helpers.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/test-helpers.sub.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
<script>
/*
@@ -26,11 +27,12 @@
{cors: true, main: 'time', imported: 'default'},
{cors: true, main: 'time', imported: 'time' }];
+const host_info = get_host_info();
settings.reduce((p, s) => {
return p.then(promise_test(function(t) {
var path = !s.cors ? ''
- : 'https://www1.web-platform.test:8443/' +
- 'service-workers/service-worker/resources/';
+ : host_info.HTTPS_REMOTE_ORIGIN +
+ '/service-workers/service-worker/resources/';
var script = 'resources/bytecheck-worker.py' +
'?main=' + s.main +
'&imported=' + s.imported +
diff --git a/service-workers/service-worker/webvtt-cross-origin.https.html b/service-workers/service-worker/webvtt-cross-origin.https.html
new file mode 100644
index 0000000..0f98060
--- /dev/null
+++ b/service-workers/service-worker/webvtt-cross-origin.https.html
@@ -0,0 +1,106 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>cross-origin webvtt returned by service worker is detected</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="resources/test-helpers.sub.js?pipe=sub"></script>
+<body>
+<script>
+// This file tests opaque responses for WebVTT text track. It creates
+// an iframe with a <track> element, controlled by a service worker.
+// Each test tries to load a text track, the service worker intercepts the
+// requests and responds with opaque or non-opaque responses. The opaque
+// responses should result in load errors.
+
+const host_info = get_host_info();
+const kScript = 'resources/fetch-rewrite-worker.js';
+// Add '?ignore' so the service worker falls back for the navigation.
+const kScope = 'resources/vtt-frame.html?ignore';
+let frame;
+
+function load_track(url) {
+ const track = frame.contentDocument.querySelector('track');
+ const result = new Promise((resolve, reject) => {
+ track.onload = (e => {
+ resolve('load event');
+ });
+ track.onerror = (e => {
+ resolve('error event');
+ });
+ });
+
+ track.src = url;
+ // Setting mode to hidden seems needed, or else the text track requests don't
+ // occur.
+ track.track.mode = 'hidden';
+ return result;
+}
+
+promise_test(t => {
+ return service_worker_unregister_and_register(t, kScript, kScope)
+ .then(registration => {
+ promise_test(() => {
+ frame.remove();
+ return registration.unregister();
+ }, 'restore global state');
+
+ return wait_for_state(t, registration.installing, 'activated');
+ })
+ .then(() => {
+ return with_iframe(kScope);
+ })
+ .then(f => {
+ frame = f;
+ })
+ }, 'initialize global state');
+
+promise_test(t => {
+ let url = '/media/foo.vtt';
+ // Add '?url' and tell the service worker to return a same-origin URL.
+ url += '?url=' + host_info.HTTPS_ORIGIN + '/media/foo.vtt';
+ return load_track(url)
+ .then(result => {
+ assert_equals(result, 'load event');
+ });
+ }, 'same-origin text track should load');
+
+promise_test(t => {
+ let url = '/media/foo.vtt';
+ // Add '?url' and tell the service worker to return a cross-origin URL.
+ url += '?url=' + get_host_info().HTTPS_REMOTE_ORIGIN + '/media/foo.vtt';
+ return load_track(url)
+ .then(result => {
+ assert_equals(result, 'error event');
+ });
+ }, 'cross-origin text track with no-cors request should not load');
+
+promise_test(t => {
+ let url = '/media/foo.vtt';
+ // Add '?url' and tell the service worker to return a cross-origin URL that
+ // doesn't support CORS.
+ url += '?url=' + get_host_info().HTTPS_REMOTE_ORIGIN +
+ '/media/foo-no-cors.vtt';
+ // Add '&mode' to tell the service worker to do a CORS request.
+ url += '&mode=cors';
+ return load_track(url)
+ .then(result => {
+ assert_equals(result, 'error event');
+ });
+ }, 'cross-origin text track with rejected cors request should not load');
+
+promise_test(t => {
+ let url = '/media/foo.vtt';
+ // Add '?url' and tell the service worker to return a cross-origin URL.
+ url += '?url=' + get_host_info().HTTPS_REMOTE_ORIGIN + '/media/foo.vtt';
+ // Add '&mode' to tell the service worker to do a CORS request.
+ url += '&mode=cors';
+ // Add '&credentials=anonymous' to allow Access-Control-Allow-Origin=*.
+ url += '&credentials=anonymous';
+ return load_track(url)
+ .then(result => {
+ assert_equals(result, 'load event');
+ });
+ }, 'cross-origin text track with approved cors request should load');
+</script>
+</body>
diff --git a/streams/readable-byte-streams/properties.js b/streams/readable-byte-streams/properties.js
index 02d0294..975fba7 100644
--- a/streams/readable-byte-streams/properties.js
+++ b/streams/readable-byte-streams/properties.js
@@ -88,7 +88,7 @@
assert_not_equals(viewPropDesc.get, undefined, 'view should have a getter');
assert_equals(viewPropDesc.set, undefined, 'view should not have a setter');
assert_not_equals(byobRequest.view, undefined, 'has a non-undefined view property');
- assert_equals(byobRequest.constructor.length, 2, 'constructor has 1 parameter');
+ assert_equals(byobRequest.constructor.length, 0, 'constructor has 0 parameters');
assert_equals(byobRequest.respond.length, 1, 'respond has 1 parameter');
assert_equals(byobRequest.respondWithNewView.length, 1, 'releaseLock has 1 parameter');
diff --git a/tools/ci/commands.json b/tools/ci/commands.json
index d682d2a..a8db428 100644
--- a/tools/ci/commands.json
+++ b/tools/ci/commands.json
@@ -2,5 +2,6 @@
"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"]}
+ "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}
}
diff --git a/tools/ci/lib.sh b/tools/ci/lib.sh
index db49ec6..2273793 100644
--- a/tools/ci/lib.sh
+++ b/tools/ci/lib.sh
@@ -6,15 +6,7 @@
echo "## /etc/hosts ##"
cat /etc/hosts
sudo sed -i 's/^::1\s*localhost/::1/' /etc/hosts
- sudo sh -c 'echo "
-127.0.0.1 web-platform.test
-127.0.0.1 www.web-platform.test
-127.0.0.1 www1.web-platform.test
-127.0.0.1 www2.web-platform.test
-127.0.0.1 xn--n8j6ds53lwwkrqhv28a.web-platform.test
-127.0.0.1 xn--lve-6lad.web-platform.test
-0.0.0.0 nonexistent-origin.web-platform.test
-" >> /etc/hosts'
+ ./wpt make-hosts-file | sudo tee -a /etc/hosts
echo "== /etc/hosts =="
cat /etc/hosts
echo "----------------"
diff --git a/tools/ci/make_hosts_file.py b/tools/ci/make_hosts_file.py
new file mode 100644
index 0000000..b3c7758
--- /dev/null
+++ b/tools/ci/make_hosts_file.py
@@ -0,0 +1,19 @@
+import argparse
+import os
+
+from ..localpaths import repo_root
+
+from ..serve.serve import load_config, normalise_config, make_hosts_file
+
+def create_parser():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("address", default="127.0.0.1", nargs="?", help="Address that hosts should point at")
+ return parser
+
+def run(**kwargs):
+ config = load_config(os.path.join(repo_root, "config.default.json"),
+ os.path.join(repo_root, "config.json"))
+
+ config = normalise_config(config, {})
+
+ print(make_hosts_file(config, kwargs["address"]))
diff --git a/tools/conftest.py b/tools/conftest.py
index 894fe62..4ce5e74 100644
--- a/tools/conftest.py
+++ b/tools/conftest.py
@@ -1,5 +1,6 @@
import platform
import os
+import sys
from hypothesis import settings, HealthCheck
@@ -11,3 +12,11 @@
settings.load_profile(os.getenv("HYPOTHESIS_PROFILE",
"default" if impl != "PyPy" else "pypy"))
+
+# serve can't even be imported on Py3, so totally ignore it even from collection
+collect_ignore = []
+if sys.version_info[0] >= 3:
+ serve = os.path.join(os.path.dirname(__file__), "serve")
+ collect_ignore.extend([os.path.join(root, f)
+ for root, _, files in os.walk(serve)
+ for f in files])
diff --git a/tools/serve/serve.py b/tools/serve/serve.py
index c77badc..9c5e7ca 100644
--- a/tools/serve/serve.py
+++ b/tools/serve/serve.py
@@ -203,6 +203,8 @@
u"天気の良い日",
u"élève"]
+not_subdomains = [u"nonexistent-origin"]
+
class RoutesBuilder(object):
def __init__(self):
self.forbidden_override = [("GET", "/tools/runner/*", handlers.file_handler),
@@ -468,6 +470,24 @@
for subdomain in subdomains}
+def get_not_subdomains(host):
+ #This assumes that the tld is ascii-only or already in punycode
+ return {subdomain: (subdomain.encode("idna"), host)
+ for subdomain in not_subdomains}
+
+
+def make_hosts_file(config, host):
+ rv = []
+
+ for domain in config["domains"].values():
+ rv.append("%s\t%s\n" % (host, domain))
+
+ for not_domain in config.get("not_domains", {}).values():
+ rv.append("0.0.0.0\t%s\n" % not_domain)
+
+ return "".join(rv)
+
+
def start_servers(host, ports, paths, routes, bind_hostname, config, ssl_config,
**kwargs):
servers = defaultdict(list)
@@ -626,6 +646,7 @@
def normalise_config(config, ports):
host = config["external_host"] if config["external_host"] else config["host"]
domains = get_subdomains(host)
+ not_domains = get_not_subdomains(host)
ports_ = {}
for scheme, ports_used in ports.iteritems():
ports_[scheme] = ports_used
@@ -633,6 +654,9 @@
for key, value in domains.iteritems():
domains[key] = ".".join(value)
+ for key, value in not_domains.iteritems():
+ not_domains[key] = ".".join(value)
+
domains[""] = host
ports_ = {}
@@ -644,6 +668,7 @@
config_ = config.copy()
config_["host"] = host
config_["domains"] = domains
+ config_["not_domains"] = not_domains
config_["ports"] = ports_
return config_
diff --git a/tools/serve/test_serve.py b/tools/serve/test_serve.py
new file mode 100644
index 0000000..3337601
--- /dev/null
+++ b/tools/serve/test_serve.py
@@ -0,0 +1,12 @@
+from . import serve
+
+def test_make_hosts_file():
+ hosts = serve.make_hosts_file({
+ "domains": {"www": "www.foo.bar.test", "www1": "www1.foo.bar.test"},
+ "not_domains": {"aaa": "aaa.foo.bar.test", "bbb": "bbb.foo.bar.test"}
+ }, "127.1.1.1")
+ lines = hosts.split("\n")
+ assert "127.1.1.1\twww.foo.bar.test" in lines
+ assert "127.1.1.1\twww1.foo.bar.test" in lines
+ assert "0.0.0.0\taaa.foo.bar.test" in lines
+ assert "0.0.0.0\tbbb.foo.bar.test" in lines
diff --git a/tools/wpt/run.py b/tools/wpt/run.py
index f3fbcbd..236299e 100644
--- a/tools/wpt/run.py
+++ b/tools/wpt/run.py
@@ -11,6 +11,8 @@
sys.path.insert(0, os.path.abspath(os.path.join(wpt_root, "tools")))
from . import browser, utils, virtualenv
+from ..serve import serve
+
logger = None
@@ -94,13 +96,10 @@
def check_environ(product):
if product not in ("firefox", "servo"):
- expected_hosts = ["web-platform.test",
- "www.web-platform.test",
- "www1.web-platform.test",
- "www2.web-platform.test",
- "xn--n8j6ds53lwwkrqhv28a.web-platform.test",
- "xn--lve-6lad.web-platform.test",
- "nonexistent-origin.web-platform.test"]
+ expected_hosts = {".".join(x)
+ for x in serve.get_subdomains("web-platform.test").values()}
+ expected_hosts |= {".".join(x)
+ for x in serve.get_not_subdomains("web-platform.test").values()}
missing_hosts = set(expected_hosts)
if platform.uname()[0] != "Windows":
hosts_path = "/etc/hosts"
@@ -114,13 +113,17 @@
for host in hosts:
missing_hosts.discard(host)
if missing_hosts:
- raise WptrunError("""Missing hosts file configuration. Expected entries like:
+ if platform.uname()[0] != "Windows":
+ message = """Missing hosts file configuration. Run
-%s
+python wpt make-hosts-file >> %s
-See README.md for more details.""" % "\n".join("%s\t%s" %
- ("127.0.0.1" if "nonexistent" not in host else "0.0.0.0", host)
- for host in expected_hosts))
+from a shell with Administrator privileges.""" % hosts_path
+ else:
+ message = """Missing hosts file configuration. Run
+
+./wpt make-hosts-file | sudo tee -a %s""" % hosts_path
+ raise WptrunError(message)
class BrowserSetup(object):
diff --git a/tools/wptrunner/MANIFEST.in b/tools/wptrunner/MANIFEST.in
index 7083923..d3b530a 100644
--- a/tools/wptrunner/MANIFEST.in
+++ b/tools/wptrunner/MANIFEST.in
@@ -5,4 +5,3 @@
include wptrunner/*.js
include wptrunner/executors/*.js
include wptrunner/config.json
-include wptrunner/browsers/server-locations.txt
\ No newline at end of file
diff --git a/tools/wptrunner/setup.py b/tools/wptrunner/setup.py
index 7da5141..148a1d2 100644
--- a/tools/wptrunner/setup.py
+++ b/tools/wptrunner/setup.py
@@ -52,7 +52,6 @@
"testharness_runner.html",
"config.json",
"wptrunner.default.ini",
- "browsers/server-locations.txt",
"browsers/sauce_setup/*",
"prefs/*"]},
include_package_data=True,
diff --git a/tools/wptrunner/wptrunner/browsers/chrome.py b/tools/wptrunner/wptrunner/browsers/chrome.py
index 215fccf..7f9a21c 100644
--- a/tools/wptrunner/wptrunner/browsers/chrome.py
+++ b/tools/wptrunner/wptrunner/browsers/chrome.py
@@ -60,8 +60,7 @@
def env_options():
- return {"host": "web-platform.test",
- "bind_hostname": "true"}
+ return {"bind_hostname": "true"}
class ChromeBrowser(Browser):
diff --git a/tools/wptrunner/wptrunner/browsers/chrome_android.py b/tools/wptrunner/wptrunner/browsers/chrome_android.py
index 47090be..3e832cb 100644
--- a/tools/wptrunner/wptrunner/browsers/chrome_android.py
+++ b/tools/wptrunner/wptrunner/browsers/chrome_android.py
@@ -68,8 +68,7 @@
def env_options():
- return {"host": "web-platform.test",
- "bind_hostname": "true"}
+ return {"bind_hostname": "true"}
class ChromeAndroidBrowser(Browser):
diff --git a/tools/wptrunner/wptrunner/browsers/edge.py b/tools/wptrunner/wptrunner/browsers/edge.py
index db4ae00..094405c 100644
--- a/tools/wptrunner/wptrunner/browsers/edge.py
+++ b/tools/wptrunner/wptrunner/browsers/edge.py
@@ -38,8 +38,7 @@
return []
def env_options():
- return {"host": "web-platform.test",
- "bind_hostname": "true",
+ return {"bind_hostname": "true",
"supports_debugger": False}
class EdgeBrowser(Browser):
diff --git a/tools/wptrunner/wptrunner/browsers/firefox.py b/tools/wptrunner/wptrunner/browsers/firefox.py
index 6d1f58d..57e0527 100644
--- a/tools/wptrunner/wptrunner/browsers/firefox.py
+++ b/tools/wptrunner/wptrunner/browsers/firefox.py
@@ -3,12 +3,12 @@
import signal
import subprocess
import sys
+import tempfile
import mozinfo
import mozleak
from mozprocess import ProcessHandler
from mozprofile import FirefoxProfile, Preferences
-from mozprofile.permissions import ServerLocations
from mozrunner import FirefoxRunner
from mozrunner.utils import get_stack_fixer_function
from mozcrash import mozcrash
@@ -23,7 +23,6 @@
from ..executors.executormarionette import (MarionetteTestharnessExecutor,
MarionetteRefTestExecutor,
MarionetteWdspecExecutor)
-from ..environment import hostnames
here = os.path.join(os.path.split(__file__)[0])
@@ -80,7 +79,8 @@
**kwargs),
"leak_check": kwargs["leak_check"],
"stylo_threads": kwargs["stylo_threads"],
- "chaos_mode_flags": kwargs["chaos_mode_flags"]}
+ "chaos_mode_flags": kwargs["chaos_mode_flags"],
+ "config": kwargs["config"]}
def executor_kwargs(test_type, server_config, cache_manager, run_info_data,
@@ -102,7 +102,7 @@
if kwargs["binary_args"]:
options["args"] = kwargs["binary_args"]
options["prefs"] = {
- "network.dns.localDomains": ",".join(hostnames)
+ "network.dns.localDomains": ",".join(server_config['domains'].values())
}
capabilities["moz:firefoxOptions"] = options
if kwargs["certutil_binary"] is None:
@@ -143,7 +143,7 @@
symbols_path=None, stackwalk_binary=None, certutil_binary=None,
ca_certificate_path=None, e10s=False, stackfix_dir=None,
binary_args=None, timeout_multiplier=None, leak_check=False, stylo_threads=1,
- chaos_mode_flags=None):
+ chaos_mode_flags=None, config=None):
Browser.__init__(self, logger)
self.binary = binary
self.prefs_root = prefs_root
@@ -159,6 +159,7 @@
self.certutil_binary = certutil_binary
self.e10s = e10s
self.binary_args = binary_args
+ self.config = config
if stackfix_dir:
self.stack_fixer = get_stack_fixer_function(stackfix_dir,
self.symbols_path)
@@ -189,15 +190,12 @@
if self.chaos_mode_flags is not None:
env["MOZ_CHAOSMODE"] = str(self.chaos_mode_flags)
- locations = ServerLocations(filename=os.path.join(here, "server-locations.txt"))
-
preferences = self.load_prefs()
- self.profile = FirefoxProfile(locations=locations,
- preferences=preferences)
+ self.profile = FirefoxProfile(preferences=preferences)
self.profile.set_preferences({"marionette.port": self.marionette_port,
"dom.disable_open_during_load": False,
- "network.dns.localDomains": ",".join(hostnames),
+ "network.dns.localDomains": ",".join(self.config['domains'].values()),
"network.proxy.type": 0,
"places.history.enabled": False,
"dom.send_after_paint_to_content": True,
diff --git a/tools/wptrunner/wptrunner/browsers/ie.py b/tools/wptrunner/wptrunner/browsers/ie.py
index 13f5827..9c0007e 100644
--- a/tools/wptrunner/wptrunner/browsers/ie.py
+++ b/tools/wptrunner/wptrunner/browsers/ie.py
@@ -42,8 +42,7 @@
return []
def env_options():
- return {"host": "web-platform.test",
- "bind_hostname": "true",
+ return {"bind_hostname": "true",
"supports_debugger": False}
class InternetExplorerBrowser(Browser):
diff --git a/tools/wptrunner/wptrunner/browsers/opera.py b/tools/wptrunner/wptrunner/browsers/opera.py
index 57edfa0..693a19a 100644
--- a/tools/wptrunner/wptrunner/browsers/opera.py
+++ b/tools/wptrunner/wptrunner/browsers/opera.py
@@ -60,8 +60,7 @@
def env_options():
- return {"host": "web-platform.test",
- "bind_hostname": "true"}
+ return {"bind_hostname": "true"}
class OperaBrowser(Browser):
diff --git a/tools/wptrunner/wptrunner/browsers/sauce.py b/tools/wptrunner/wptrunner/browsers/sauce.py
index 4c1be1c..42c83c5 100644
--- a/tools/wptrunner/wptrunner/browsers/sauce.py
+++ b/tools/wptrunner/wptrunner/browsers/sauce.py
@@ -113,8 +113,7 @@
def env_options():
- return {"host": "web-platform.test",
- "bind_hostname": "true",
+ return {"bind_hostname": "true",
"supports_debugger": False}
@@ -128,6 +127,7 @@
class SauceConnect():
def __init__(self, **kwargs):
+ self.config = kwargs["config"]
self.sauce_user = kwargs["sauce_user"]
self.sauce_key = kwargs["sauce_key"]
self.sauce_tunnel_id = kwargs["sauce_tunnel_id"]
@@ -153,8 +153,7 @@
"--metrics-address=0.0.0.0:9876",
"--readyfile=./sauce_is_ready",
"--tunnel-domains",
- "web-platform.test",
- "*.web-platform.test"
+ ",".join(self.config['domains'].values())
])
# Timeout config vars
diff --git a/tools/wptrunner/wptrunner/browsers/server-locations.txt b/tools/wptrunner/wptrunner/browsers/server-locations.txt
deleted file mode 100644
index 5dcaf4b..0000000
--- a/tools/wptrunner/wptrunner/browsers/server-locations.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-http://localhost:8000 primary
-
-http://web-platform.test:8000
-http://www.web-platform.test:8000
-http://www1.web-platform.test:8000
-http://www2.web-platform.test:8000
-http://xn--n8j6ds53lwwkrqhv28a.web-platform.test:8000
-http://xn--lve-6lad.web-platform.test:8000
-
-http://web-platform.test:8001
-http://www.web-platform.test:8001
-http://www1.web-platform.test:8001
-http://www2.web-platform.test:8001
-http://xn--n8j6ds53lwwkrqhv28a.web-platform.test:8001
-http://xn--lve-6lad.web-platform.test:8001
-
-https://web-platform.test:8443
-https://www.web-platform.test:8443
-https://www1.web-platform.test:8443
-https://www2.web-platform.test:8443
-https://xn--n8j6ds53lwwkrqhv28a.web-platform.test:8443
-https://xn--lve-6lad.web-platform.test:8443
-
-# These are actually ws servers, but until mozprofile is
-# fixed we have to pretend that they are http servers
-http://web-platform.test:8888
-http://www.web-platform.test:8888
-http://www1.web-platform.test:8888
-http://www2.web-platform.test:8888
-http://xn--n8j6ds53lwwkrqhv28a.web-platform.test:8888
-http://xn--lve-6lad.web-platform.test:8888
diff --git a/tools/wptrunner/wptrunner/browsers/servodriver.py b/tools/wptrunner/wptrunner/browsers/servodriver.py
index c251de8..0986450 100644
--- a/tools/wptrunner/wptrunner/browsers/servodriver.py
+++ b/tools/wptrunner/wptrunner/browsers/servodriver.py
@@ -1,9 +1,12 @@
import os
+import shutil
import subprocess
import tempfile
from mozprocess import ProcessHandler
+from serve.serve import make_hosts_file
+
from .base import Browser, require_arg, get_free_port, browser_command, ExecutorBrowser
from ..executors import executor_kwargs as base_executor_kwargs
from ..executors.executorservodriver import (ServoWebDriverTestharnessExecutor,
@@ -26,14 +29,6 @@
"update_properties": "update_properties",
}
-hosts_text = """127.0.0.1 web-platform.test
-127.0.0.1 www.web-platform.test
-127.0.0.1 www1.web-platform.test
-127.0.0.1 www2.web-platform.test
-127.0.0.1 xn--n8j6ds53lwwkrqhv28a.web-platform.test
-127.0.0.1 xn--lve-6lad.web-platform.test
-"""
-
def check_args(**kwargs):
require_arg(kwargs, "binary")
@@ -69,10 +64,10 @@
return ["debug", "os", "version", "processor", "bits"], None
-def make_hosts_file():
+def write_hosts_file(config):
hosts_fd, hosts_path = tempfile.mkstemp()
with os.fdopen(hosts_fd, "w") as f:
- f.write(hosts_text)
+ f.write(make_hosts_file(config, "127.0.0.1"))
return hosts_path
@@ -87,7 +82,7 @@
self.webdriver_port = None
self.proc = None
self.debug_info = debug_info
- self.hosts_path = make_hosts_file()
+ self.hosts_path = write_hosts_file()
self.command = None
self.user_stylesheets = user_stylesheets if user_stylesheets else []
@@ -158,6 +153,7 @@
def cleanup(self):
self.stop()
+ shutil.rmtree(os.path.dirname(self.hosts_file))
def executor_browser(self):
assert self.webdriver_port is not None
diff --git a/tools/wptrunner/wptrunner/environment.py b/tools/wptrunner/wptrunner/environment.py
index 7115341..22b02a9 100644
--- a/tools/wptrunner/wptrunner/environment.py
+++ b/tools/wptrunner/wptrunner/environment.py
@@ -18,14 +18,6 @@
sslutils = None
-hostnames = ["web-platform.test",
- "www.web-platform.test",
- "www1.web-platform.test",
- "www2.web-platform.test",
- "xn--n8j6ds53lwwkrqhv28a.web-platform.test",
- "xn--lve-6lad.web-platform.test"]
-
-
def do_delayed_imports(logger, test_paths):
global serve, sslutils
diff --git a/tools/wptrunner/wptrunner/executors/executorservo.py b/tools/wptrunner/wptrunner/executors/executorservo.py
index ca8ec8a..ac8e92e 100644
--- a/tools/wptrunner/wptrunner/executors/executorservo.py
+++ b/tools/wptrunner/wptrunner/executors/executorservo.py
@@ -13,6 +13,8 @@
from mozprocess import ProcessHandler
+from serve.serve import make_hosts_file
+
from .base import (ExecutorException,
Protocol,
RefTestImplementation,
@@ -30,18 +32,10 @@
extra_timeout = 5 # seconds
-hosts_text = """127.0.0.1 web-platform.test
-127.0.0.1 www.web-platform.test
-127.0.0.1 www1.web-platform.test
-127.0.0.1 www2.web-platform.test
-127.0.0.1 xn--n8j6ds53lwwkrqhv28a.web-platform.test
-127.0.0.1 xn--lve-6lad.web-platform.test
-"""
-
-def make_hosts_file():
+def write_hosts_file(config):
hosts_fd, hosts_path = tempfile.mkstemp()
with os.fdopen(hosts_fd, "w") as f:
- f.write(hosts_text)
+ f.write(make_hosts_file(config, "127.0.0.1"))
return hosts_path
@@ -57,7 +51,7 @@
self.result_data = None
self.result_flag = None
self.protocol = Protocol(self, browser)
- self.hosts_path = make_hosts_file()
+ self.hosts_path = write_hosts_file(server_config)
def teardown(self):
try:
diff --git a/tools/wptrunner/wptrunner/hosts.py b/tools/wptrunner/wptrunner/hosts.py
deleted file mode 100644
index 915c17f..0000000
--- a/tools/wptrunner/wptrunner/hosts.py
+++ /dev/null
@@ -1,100 +0,0 @@
-from __future__ import unicode_literals
-
-
-class HostsLine(object):
- def __init__(self, ip_address, canonical_hostname, aliases=None, comment=None):
- self.ip_address = ip_address
- self.canonical_hostname = canonical_hostname
- self.aliases = aliases if aliases is not None else []
- self.comment = comment
- if self.ip_address is None:
- assert self.canonical_hostname is None
- assert not self.aliases
- assert self.comment is not None
-
- @classmethod
- def from_string(cls, line):
- if not line.strip():
- return
-
- line = line.strip()
-
- ip_address = None
- canonical_hostname = None
- aliases = []
- comment = None
-
- comment_parts = line.split("#", 1)
- if len(comment_parts) > 1:
- comment = comment_parts[1]
-
- data = comment_parts[0].strip()
-
- if data:
- fields = data.split()
- if len(fields) < 2:
- raise ValueError("Invalid hosts line")
-
- ip_address = fields[0]
- canonical_hostname = fields[1]
- aliases = fields[2:]
-
- return cls(ip_address, canonical_hostname, aliases, comment)
-
-
-class HostsFile(object):
- def __init__(self):
- self.data = []
- self.by_hostname = {}
-
- def set_host(self, host):
- if host.canonical_hostname is None:
- self.data.append(host)
- elif host.canonical_hostname in self.by_hostname:
- old_host = self.by_hostname[host.canonical_hostname]
- old_host.ip_address = host.ip_address
- old_host.aliases = host.aliases
- old_host.comment = host.comment
- else:
- self.data.append(host)
- self.by_hostname[host.canonical_hostname] = host
-
- @classmethod
- def from_file(cls, f):
- rv = cls()
- for line in f:
- host = HostsLine.from_string(line)
- if host is not None:
- rv.set_host(host)
- return rv
-
- def to_string(self):
- field_widths = [0, 0]
- for line in self.data:
- if line.ip_address is not None:
- field_widths[0] = max(field_widths[0], len(line.ip_address))
- field_widths[1] = max(field_widths[1], len(line.canonical_hostname))
-
- lines = []
-
- for host in self.data:
- line = ""
- if host.ip_address is not None:
- ip_string = host.ip_address.ljust(field_widths[0])
- hostname_str = host.canonical_hostname
- if host.aliases:
- hostname_str = "%s %s" % (hostname_str.ljust(field_widths[1]),
- " ".join(host.aliases))
- line = "%s %s" % (ip_string, hostname_str)
- if host.comment:
- if line:
- line += " "
- line += "#%s" % host.comment
- lines.append(line)
-
- lines.append("")
-
- return "\n".join(lines)
-
- def to_file(self, f):
- f.write(self.to_string().encode("utf8"))
diff --git a/tools/wptrunner/wptrunner/tests/browsers/__init__.py b/tools/wptrunner/wptrunner/tests/browsers/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/wptrunner/wptrunner/tests/browsers/__init__.py
diff --git a/tools/wptrunner/wptrunner/tests/browsers/test_sauce.py b/tools/wptrunner/wptrunner/tests/browsers/test_sauce.py
index bf3e487..019b538 100644
--- a/tools/wptrunner/wptrunner/tests/browsers/test_sauce.py
+++ b/tools/wptrunner/wptrunner/tests/browsers/test_sauce.py
@@ -20,6 +20,9 @@
exists.return_value = True
sauce_connect = sauce.SauceConnect(
+ config={
+ "domains": {"": "example.net"}
+ },
sauce_user="aaa",
sauce_key="bbb",
sauce_tunnel_id="ccc",
@@ -46,6 +49,9 @@
exists.return_value = readyfile
sauce_connect = sauce.SauceConnect(
+ config={
+ "domains": {"": "example.net"}
+ },
sauce_user="aaa",
sauce_key="bbb",
sauce_tunnel_id="ccc",
@@ -68,6 +74,9 @@
exists.return_value = False
sauce_connect = sauce.SauceConnect(
+ config={
+ "domains": {"": "example.net"}
+ },
sauce_user="aaa",
sauce_key="bbb",
sauce_tunnel_id="ccc",
@@ -82,3 +91,34 @@
# Check we actually kill it after termination fails
Popen.return_value.terminate.assert_called()
Popen.return_value.kill.assert_called()
+
+
+def test_sauceconnect_tunnel_domains():
+ with mock.patch.object(sauce.SauceConnect, "upload_prerun_exec"),\
+ mock.patch.object(sauce.subprocess, "Popen") as Popen,\
+ mock.patch.object(sauce.os.path, "exists") as exists:
+ Popen.return_value.poll.return_value = None
+ Popen.return_value.returncode = None
+ exists.return_value = True
+
+ sauce_connect = sauce.SauceConnect(
+ config={
+ "domains": {"foo": "foo.bar.example.com", "": "example.net"}
+ },
+ sauce_user="aaa",
+ sauce_key="bbb",
+ sauce_tunnel_id="ccc",
+ sauce_connect_binary="ddd")
+
+ sauce_connect.__enter__(None)
+
+ Popen.assert_called_once()
+ args, kwargs = Popen.call_args
+ cmd = args[0]
+ assert "--tunnel-domains" in cmd
+ i = cmd.index("--tunnel-domains")
+ rest = cmd[i+1:]
+ assert len(rest) >= 1
+ if len(rest) > 1:
+ assert rest[1].startswith("-"), "--tunnel-domains takes a comma separated list (not a space separated list)"
+ assert set(rest[0].split(",")) == {"foo.bar.example.com", "example.net"}
diff --git a/tools/wptrunner/wptrunner/tests/test_hosts.py b/tools/wptrunner/wptrunner/tests/test_hosts.py
deleted file mode 100644
index e7d41f3..0000000
--- a/tools/wptrunner/wptrunner/tests/test_hosts.py
+++ /dev/null
@@ -1,54 +0,0 @@
-import unittest
-import sys
-from os.path import join, dirname
-from cStringIO import StringIO
-
-sys.path.insert(0, join(dirname(__file__), "..", ".."))
-
-from wptrunner import hosts
-
-
-class HostsTest(unittest.TestCase):
- def do_test(self, input, expected):
- host_file = hosts.HostsFile.from_file(StringIO(input))
- self.assertEquals(host_file.to_string(), expected)
-
- def test_simple(self):
- self.do_test("""127.0.0.1 \tlocalhost alias # comment
-# Another comment""",
- """127.0.0.1 localhost alias # comment
-# Another comment
-""")
-
- def test_blank_lines(self):
- self.do_test("""127.0.0.1 \tlocalhost alias # comment
-
-\r
- \t
-# Another comment""",
- """127.0.0.1 localhost alias # comment
-# Another comment
-""")
-
- def test_whitespace(self):
- self.do_test(""" \t127.0.0.1 \tlocalhost alias # comment \r
- \t# Another comment""",
- """127.0.0.1 localhost alias # comment
-# Another comment
-""")
-
- def test_alignment(self):
- self.do_test("""127.0.0.1 \tlocalhost alias
-192.168.1.1 another_host another_alias
-""","""127.0.0.1 localhost alias
-192.168.1.1 another_host another_alias
-""")
-
- def test_multiple_same_name(self):
- # The semantics are that we overwrite earlier entries with the same name
- self.do_test("""127.0.0.1 \tlocalhost alias
-192.168.1.1 localhost another_alias""","""192.168.1.1 localhost another_alias
-""")
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/tools/wptrunner/wptrunner/wptrunner.py b/tools/wptrunner/wptrunner/wptrunner.py
index 6677902..d3d9d07 100644
--- a/tools/wptrunner/wptrunner/wptrunner.py
+++ b/tools/wptrunner/wptrunner/wptrunner.py
@@ -218,6 +218,7 @@
browser_kwargs = get_browser_kwargs(test_type,
run_info,
ssl_env=ssl_env,
+ config=test_environment.config,
**kwargs)
executor_cls = executor_classes.get(test_type)
diff --git a/tools/wptserve/wptserve/pipes.py b/tools/wptserve/wptserve/pipes.py
index b71c8af..534afed 100644
--- a/tools/wptserve/wptserve/pipes.py
+++ b/tools/wptserve/wptserve/pipes.py
@@ -392,6 +392,12 @@
value = request.headers
elif field == "GET":
value = FirstWrapper(request.GET)
+ elif field == "domains":
+ if ('not_domains' in request.server.config and
+ tokens[1][1] in request.server.config['not_domains']):
+ value = request.server.config['not_domains']
+ else:
+ value = request.server.config['domains']
elif field in request.server.config:
value = request.server.config[tokens[0][1]]
elif field == "location":
diff --git a/webauthn/createcredential-badargs-attestation.https.html b/webauthn/createcredential-badargs-attestation.https.html
new file mode 100644
index 0000000..a56f4f0
--- /dev/null
+++ b/webauthn/createcredential-badargs-attestation.https.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.create() attestation parameter Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+ "use strict";
+
+ // attestation bad values
+ new CreateCredentialsTest("options.publicKey.attestation", {}).runTest("Bad attestation parameter: attestation is empty object", new TypeError());
+ new CreateCredentialsTest("options.publicKey.attestation", []).runTest("Bad attestation parameter: attestation is empty array", new TypeError());
+ new CreateCredentialsTest("options.publicKey.attestation", null).runTest("Bad attestation parameter: attestation is null", new TypeError());
+ new CreateCredentialsTest("options.publicKey.attestation", "noneofyourbusiness").runTest("Bad attestation parameter: attestation is \"noneofyourbusiness\"", new TypeError());
+ new CreateCredentialsTest("options.publicKey.attestation", "").runTest("Bad attestation parameter: attestation is empty string", new TypeError());
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest */
+</script>
\ No newline at end of file
diff --git a/webauthn/createcredential-badargs-authnrselection.https.html b/webauthn/createcredential-badargs-authnrselection.https.html
new file mode 100644
index 0000000..2c42135
--- /dev/null
+++ b/webauthn/createcredential-badargs-authnrselection.https.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.create() authenticator selection Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+ "use strict";
+
+ var defaultAuthnrSel = {
+ authenticatorAttachment: "cross-platform",
+ requireResidentKey: false,
+ userVerification: "preferred"
+ };
+ // attachment
+ var authnrSelAttachPlatform = cloneObject(defaultAuthnrSel);
+ authnrSelAttachPlatform.authenticatorAttachment = "platform";
+ var authnrSelBadAttachEmptyStr = cloneObject(defaultAuthnrSel);
+ authnrSelBadAttachEmptyStr.authenticatorAttachment = "";
+ var authnrSelBadAttachEmptyObj = cloneObject(defaultAuthnrSel);
+ authnrSelBadAttachEmptyObj.authenticatorAttachment = {};
+ var authnrSelBadAttachNull = cloneObject(defaultAuthnrSel);
+ authnrSelBadAttachNull.authenticatorAttachment = null;
+ // resident key
+ var authnrSelRkTrue = cloneObject(defaultAuthnrSel);
+ authnrSelRkTrue.requireResidentKey = true;
+ var authnrSelRkBadString = cloneObject(defaultAuthnrSel);
+ authnrSelRkBadString.requireResidentKey = "foo";
+ // user verification
+ var authnrSelUvRequired = cloneObject(defaultAuthnrSel);
+ authnrSelUvRequired.userVerification = "required";
+ var authnrSelBadUvEmptyStr = cloneObject(defaultAuthnrSel);
+ authnrSelBadUvEmptyStr.userVerification = "";
+ var authnrSelBadUvEmptyObj = cloneObject(defaultAuthnrSel);
+ authnrSelBadUvEmptyObj.userVerification = {};
+ var authnrSelBadUvStr = cloneObject(defaultAuthnrSel);
+ authnrSelBadUvStr.userVerification = "requiredshirtshoestshirt";
+ var authnrSelBadUvNull = cloneObject(defaultAuthnrSel);
+ authnrSelBadUvNull.userVerification = null;
+
+ // authenticatorSelection bad values
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", []).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection is empty array", new TypeError());
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", null).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection is null", new TypeError());
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", "").runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection is empty string", new TypeError());
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", "none").runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection is string", new TypeError());
+
+ // authenticatorSelection bad attachment values
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadAttachEmptyStr).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection attachment is empty string", new TypeError());
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadAttachEmptyObj).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection attachment is empty object", new TypeError());
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadAttachNull).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection attachment is null", new TypeError());
+ // XXX: assumes authnr is behaving like most U2F authnrs; really depends on the authnr or mock configuration
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelAttachPlatform).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection attachment platform", "NotAllowedError");
+
+ // authenticatorSelection bad requireResidentKey values
+ // XXX: assumes authnr is behaving like most U2F authnrs; really depends on the authnr or mock configuration
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelRkTrue).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection residentKey true", "NotAllowedError");
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelRkBadString).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection residentKey is string", new TypeError());
+ // TODO: not sure if rk is "boolean" or "truthy"; add test cases if it should only accept boolean values
+
+ // authenticatorSelection bad userVerification values
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadUvEmptyStr).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection userVerification empty string", new TypeError());
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadUvEmptyObj).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection userVerification empty object", new TypeError());
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadUvStr).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection userVerification bad value", new TypeError());
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadUvNull).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection userVerification null", new TypeError());
+ // XXX: assumes this is a mock authenticator the properly reports that it is not doing userVerfication
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelUvRequired).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection userVerification required", "NotAllowedError");
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest, cloneObject */
+</script>
\ No newline at end of file
diff --git a/webauthn/createcredential-badargs-challenge.https.html b/webauthn/createcredential-badargs-challenge.https.html
new file mode 100644
index 0000000..0ad67f2
--- /dev/null
+++ b/webauthn/createcredential-badargs-challenge.https.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.create() challenge Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+ "use strict";
+
+ // bad challenge values
+ new CreateCredentialsTest({path: "options.publicKey.challenge", value: undefined}).runTest("Bad challenge: challenge missing", new TypeError());
+ new CreateCredentialsTest("options.publicKey.challenge", "hi mom").runTest("Bad challenge: challenge is string", new TypeError());
+ new CreateCredentialsTest("options.publicKey.challenge", null).runTest("Bad challenge: challenge is null", new TypeError());
+ new CreateCredentialsTest("options.publicKey.challenge", {}).runTest("Bad challenge: challenge is empty object", new TypeError());
+ new CreateCredentialsTest("options.publicKey.challenge", new Array()).runTest("Bad challenge: challenge is empty Array", new TypeError());
+ new CreateCredentialsTest("options.publicKey.challenge", new ArrayBuffer(0)).runTest("Bad challenge: challenge is empty ArrayBuffer", new TypeError());
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest */
+</script>
\ No newline at end of file
diff --git a/webauthn/createcredential-badargs-rp.https.html b/webauthn/createcredential-badargs-rp.https.html
index f06e02c..9958b2c 100644
--- a/webauthn/createcredential-badargs-rp.https.html
+++ b/webauthn/createcredential-badargs-rp.https.html
@@ -12,29 +12,29 @@
"use strict";
// rp bad values
- new CreateCredentialsTest({path: "options.publicKey.rp", value: undefined}).testBadArgs("rp missing");
- new CreateCredentialsTest("options.publicKey.rp", "hi mom").testBadArgs("rp is string");
- // new CreateCredentialsTest("options.publicKey.rp", {}).testBadArgs("rp is empty object");
+ new CreateCredentialsTest({path: "options.publicKey.rp", value: undefined}).runTest("Bad rp: rp missing", new TypeError());
+ new CreateCredentialsTest("options.publicKey.rp", "hi mom").runTest("Bad rp: rp is string", new TypeError());
+ new CreateCredentialsTest("options.publicKey.rp", {}).runTest("Bad rp: rp is empty object", new TypeError());
- // rp.id
- // new CreateCredentialsTest({path: "options.publicKey.rp.id", value: undefined}).testBadArgs("rp missing id");
- new CreateCredentialsTest("options.publicKey.rp.id", {}).testBadArgs("Bad rp: id is object");
- new CreateCredentialsTest("options.publicKey.rp.id", null).testBadArgs("Bad rp: id is null");
- new CreateCredentialsTest("options.publicKey.rp.id", "").testBadArgs("Bad rp: id is empty String");
+ // // rp.id
+ new CreateCredentialsTest("options.publicKey.rp.id", {}).runTest("Bad rp: id is object", new TypeError());
+ new CreateCredentialsTest("options.publicKey.rp.id", null).runTest("Bad rp: id is null", "SecurityError");
+ new CreateCredentialsTest("options.publicKey.rp.id", "").runTest("Bad rp: id is empty String", "SecurityError");
+ new CreateCredentialsTest("options.publicKey.rp.id", "invalid domain.com").runTest("Bad rp: id is invalid domain (has space)", "SecurityError");
+ new CreateCredentialsTest("options.publicKey.rp.id", "-invaliddomain.com").runTest("Bad rp: id is invalid domain (starts with dash)", "SecurityError");
+ new CreateCredentialsTest("options.publicKey.rp.id", "0invaliddomain.com").runTest("Bad rp: id is invalid domain (starts with number)", "SecurityError");
- // rp.name
- // new CreateCredentialsTest({path: "options.publicKey.rp.name", value: undefined}).testBadArgs("rp missing name");
- new CreateCredentialsTest("options.publicKey.rp.name", {}).testBadArgs("Bad rp: name is object");
- new CreateCredentialsTest("options.publicKey.rp.name", null).testBadArgs("Bad rp: name is null");
- new CreateCredentialsTest("options.publicKey.rp.name", "").testBadArgs("Bad rp: name is empty String");
+ // // rp.name
+ new CreateCredentialsTest({path: "options.publicKey.rp.name", value: undefined}).runTest("rp missing name", new TypeError());
+ new CreateCredentialsTest("options.publicKey.rp.name", {}).runTest("Bad rp: name is object", new TypeError());
+ new CreateCredentialsTest("options.publicKey.rp.name", null).runTest("Bad rp: name is null", new TypeError());
+ new CreateCredentialsTest("options.publicKey.rp.name", "").runTest("Bad rp: name is empty String", new TypeError());
- // rp.icon
- // new CreateCredentialsTest({path: "options.publicKey.rp.icon", value: undefined}).testBadArgs("rp missing icon");
- new CreateCredentialsTest("options.publicKey.rp.icon", {}).testBadArgs("Bad rp: icon is object");
- new CreateCredentialsTest("options.publicKey.rp.icon", null).testBadArgs("Bad rp: icon is null");
- new CreateCredentialsTest("options.publicKey.rp.icon", "").testBadArgs("Bad rp: icon is empty String");
- // TODO: see https://github.com/w3c/webauthn/issues/587 for the 'undefined' tests that are commented out above
- // TODO: unicode tests for icon URL (see also: USVString)
+ // // rp.icon
+ new CreateCredentialsTest("options.publicKey.rp.icon", {}).runTest("Bad rp: icon is object", new TypeError());
+ new CreateCredentialsTest("options.publicKey.rp.icon", null).runTest("Bad rp: icon is null", new TypeError());
+ new CreateCredentialsTest("options.publicKey.rp.icon", "").runTest("Bad rp: icon is empty String", new TypeError());
+ // // TODO: unicode tests for icon URL (see also: USVString)
});
/* JSHINT */
diff --git a/webauthn/createcredential-badargs-user.https.html b/webauthn/createcredential-badargs-user.https.html
new file mode 100644
index 0000000..dd1870a
--- /dev/null
+++ b/webauthn/createcredential-badargs-user.https.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.create() user Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+ "use strict";
+
+ // user bad values
+ new CreateCredentialsTest({path: "options.publicKey.user", value: undefined}).runTest("Bad user: user missing", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user", "hi mom").runTest("Bad user: user is string", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user", {}).runTest("Bad user: user is empty object", new TypeError());
+
+ // // user.id
+ new CreateCredentialsTest({path: "options.publicKey.user.id", value: undefined}).runTest("Bad user: id is undefined", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.id", {}).runTest("Bad user: id is object", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.id", null).runTest("Bad user: id is null", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.id", "").runTest("Bad user: id is empty String", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.id", new Array()).runTest("Bad user: id is empty Array", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.id", new ArrayBuffer(0)).runTest("Bad user: id is empty ArrayBuffer", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.id", new ArrayBuffer(65)).runTest("Bad user: ArrayBuffer id is too long (65 bytes)", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.id", new Int16Array(33)).runTest("Bad user: Int16Array id is too long (66 bytes)", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.id", new Int32Array(17)).runTest("Bad user: Int32Array id is too long (68 bytes)", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.id", new Float32Array(17)).runTest("Bad user: Float32Array id is too long (68 bytes)", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.id", new Float64Array(9)).runTest("Bad user: Float64Array id is too long (72 bytes)", new TypeError());
+ var buf = new ArrayBuffer(65);
+ new CreateCredentialsTest("options.publicKey.user.id", new DataView(buf)).runTest("Bad user: id is too long (65 bytes)", new TypeError());
+
+ // // user.name
+ new CreateCredentialsTest({path: "options.publicKey.user.name", value: undefined}).runTest("user missing name", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.name", {}).runTest("Bad user: name is object", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.name", null).runTest("Bad user: name is null", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.name", "").runTest("Bad user: name is empty String", new TypeError());
+
+ // // user.icon
+ new CreateCredentialsTest("options.publicKey.user.icon", {}).runTest("Bad user: icon is object", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.icon", null).runTest("Bad user: icon is null", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.icon", "").runTest("Bad user: icon is empty String", new TypeError());
+ // // TODO: unicode tests for icon URL (see also: USVString)
+
+ // // user.displayName
+ new CreateCredentialsTest({path: "options.publicKey.user.displayName", value: undefined}).runTest("Bad user: displayName is undefined", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.displayName", {}).runTest("Bad user: displayName is object", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.displayName", null).runTest("Bad user: displayName is null", new TypeError());
+ new CreateCredentialsTest("options.publicKey.user.displayName", "").runTest("Bad user: displayName is empty String", new TypeError());
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest */
+</script>
\ No newline at end of file
diff --git a/webauthn/createcredential-excludecredentials.https.html b/webauthn/createcredential-excludecredentials.https.html
new file mode 100644
index 0000000..a4cfb0a
--- /dev/null
+++ b/webauthn/createcredential-excludecredentials.https.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.create() excludeCredentials Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+ "use strict";
+
+ // bad excludeCredentials values
+ new CreateCredentialsTest("options.publicKey.excludeCredentials", "hi mom").runTest("Bad excludeCredentials: string", new TypeError());
+ new CreateCredentialsTest("options.publicKey.excludeCredentials", {}).runTest("Bad excludeCredentials: empty object", new TypeError());
+ // TODO: bad excludeCredentials with [{.type}] or [{.id}] or [{.transports}] wrong
+
+ // good excludeCredentials values
+ new CreateCredentialsTest({path: "options.publicKey.excludeCredentials", value: undefined}).runTest("excludeCredentials missing");
+ new CreateCredentialsTest("options.publicKey.excludeCredentials", []).runTest("excludeCredentials empty array");
+
+ // proper excludeCredentials behavior
+ // should error on excluding existing credential
+ promise_test((t) => {
+ var cred1;
+ return Promise.resolve()
+ .then(() => {
+ return createCredential();
+ })
+ .then((cred) => {
+ cred1 = cred;
+ var excludeCred = {
+ id: cred.rawId,
+ type: "public-key"
+ };
+ var args = {
+ options: {
+ publicKey: {
+ excludeCredentials: [excludeCred]
+ }
+ }
+ };
+ var p = createCredential(args);
+ return promise_rejects (t, "NotAllowedError", p, "expected to fail on excluded credenetial");
+ });
+ }, "exclude existing credential");
+
+ // should not error on excluding random credential
+ promise_test(() => {
+ return Promise.resolve()
+ .then(() => {
+ return createCredential();
+ })
+ .then(() => {
+ var randomCredId = new Uint8Array(162);
+ window.crypto.getRandomValues(randomCredId);
+
+ var excludeCred = {
+ id: randomCredId,
+ type: "public-key"
+ };
+ var args = {
+ options: {
+ publicKey: {
+ excludeCredentials: [excludeCred]
+ }
+ }
+ };
+ return createCredential(args);
+ });
+ }, "exclude random (non-existing) credential");
+
+ // TODO: exclude including transport type (USB, BLE, NFC)
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest, createCredential, promise_test, promise_rejects */
+</script>
\ No newline at end of file
diff --git a/webauthn/createcredential-extensions.https.html b/webauthn/createcredential-extensions.https.html
new file mode 100644
index 0000000..3b3c9bf
--- /dev/null
+++ b/webauthn/createcredential-extensions.https.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.create() extensions Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+ "use strict";
+
+ var dummyExtension = {
+ foo: true,
+ bar: "yup"
+ };
+
+ // bad extension values
+ new CreateCredentialsTest("options.publicKey.extensions", "hi mom").runTest("Bad extensions: extensions is string", new TypeError());
+ new CreateCredentialsTest("options.publicKey.extensions", null).runTest("Bad extensions: extensions is null", new TypeError());
+ new CreateCredentialsTest("options.publicKey.extensions", []).runTest("Bad extensions: extensions is empty Array", new TypeError());
+ new CreateCredentialsTest("options.publicKey.extensions", new ArrayBuffer(0)).runTest("Bad extensions: extensions is empty ArrayBuffer", new TypeError());
+ var badJson = '{"foo": true, "bar: "yup"}'; // missing quote after "bar"
+ new CreateCredentialsTest("options.publicKey.extensions", {foo: badJson}).runTest("Bad extensions: malformatted JSON", new TypeError());
+ new CreateCredentialsTest("options.publicKey.extensions", {foo: dummyExtension}).runTest("Bad extensions: JavaScript object", new TypeError());
+ var badExtId = {};
+ badExtId[createRandomString(65)] = dummyExtension;
+ new CreateCredentialsTest("options.publicKey.extensions", {badExtId: dummyExtension}).runTest("Bad extensions: extension ID too long", new TypeError());
+
+ // phony extensions
+ // TODO: not sure if this should pass or fail
+ // should be clarified as part of https://github.com/w3c/webauthn/pull/765
+ var randomExtId = {};
+ randomExtId[createRandomString(64)] = dummyExtension;
+ new CreateCredentialsTest("options.publicKey.extensions", {foo: JSON.stringify(randomExtId)}).runTest("extensions is a nonsensical JSON string");
+
+ // TODO
+ // defined extensions:
+ // * appid
+ // * txAuthSimple
+ // * txAuthGeneric
+ // * authnSel
+ // * exts
+ // * uvi
+ // * loc
+ // * uvm
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest, createRandomString */
+</script>
\ No newline at end of file
diff --git a/webauthn/createcredential-passing.https.html b/webauthn/createcredential-passing.https.html
index a66d3c1..25dba1d 100644
--- a/webauthn/createcredential-passing.https.html
+++ b/webauthn/createcredential-passing.https.html
@@ -12,9 +12,108 @@
"use strict";
// CreateCredentialTest passing tests
- new CreateCredentialsTest().test();
+
+ // default arguments
+ new CreateCredentialsTest().runTest("passing credentials.create() with default arguments");
+
+ // rp
+ new CreateCredentialsTest({path: "options.publicKey.rp.id", value: window.location.host}).runTest("passing credentials.create() with rpId (host and port)");
+ new CreateCredentialsTest({path: "options.publicKey.rp.id", value: window.location.hostname}).runTest("passing credentials.create() with rpId (hostname)");
+ new CreateCredentialsTest({path: "options.publicKey.rp.icon", value: undefined}).runTest("passing credentials.create() without rp.icon");
+
+ // user
+ new CreateCredentialsTest("options.publicKey.user.id", new ArrayBuffer(1)).runTest("very short user id");
+ new CreateCredentialsTest("options.publicKey.user.id", new ArrayBuffer(64)).runTest("max length user id");
+ new CreateCredentialsTest("options.publicKey.user.id", new Uint8Array(64)).runTest("Uint8Array user id");
+ new CreateCredentialsTest("options.publicKey.user.id", new Int8Array(64)).runTest("Int8Array user id");
+ new CreateCredentialsTest("options.publicKey.user.id", new Int16Array(32)).runTest("Int16Array user id");
+ new CreateCredentialsTest("options.publicKey.user.id", new Int32Array(16)).runTest("Int32Array user id");
+ new CreateCredentialsTest("options.publicKey.user.id", new Float32Array(16)).runTest("Float32Array user id");
+ var dvBuf1 = new ArrayBuffer(16);
+ new CreateCredentialsTest("options.publicKey.user.id", new DataView(dvBuf1)).runTest("DataView user id");
+ new CreateCredentialsTest({path: "options.publicKey.user.icon", value: undefined}).runTest("passing credentials.create() without user.icon");
+
+ // good challenge values
+ // all these challenges are zero-filled buffers... think anyone will complain?
+ new CreateCredentialsTest("options.publicKey.challenge", new Int16Array(33)).runTest("Int16Array challenge");
+ new CreateCredentialsTest("options.publicKey.challenge", new Int32Array(17)).runTest("Int32Array challenge");
+ new CreateCredentialsTest("options.publicKey.challenge", new Float32Array(17)).runTest("Float32Array challenge");
+ new CreateCredentialsTest("options.publicKey.challenge", new Float64Array(9)).runTest("Float64Array challenge");
+ var dvBuf2 = new ArrayBuffer(65);
+ new CreateCredentialsTest("options.publicKey.challenge", new DataView(dvBuf2)).runTest("DataView challenge");
+ new CreateCredentialsTest("options.publicKey.challenge", new ArrayBuffer(8192)).runTest("Absurdly large challenge");
+
+ // good pubKeyCredParams values
+ new CreateCredentialsTest("options.publicKey.pubKeyCredParams", []).runTest("Bad pubKeyCredParams: pubKeyCredParams is empty Array");
+ const pkParamEC256 = {
+ type: "public-key",
+ alg: cose_alg_ECDSA_w_SHA256
+ };
+ const pkParamEC512 = {
+ type: "public-key",
+ alg: cose_alg_ECDSA_w_SHA512
+ };
+ // XXX: presumes all mock authenticators support EC256
+ new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [pkParamEC256]).runTest("EC256 pubKeyCredParams");
+ new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [pkParamEC512, pkParamEC256])
+ .runTest("SelectEC256 pubKeyCredParams from a list");
+ // TODO: currently most browsers are mocking FIDO U2F, which is EC256 only
+ // new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [pkParamEC512]).runTest("EC512 pubKeyCredParams");
+
+ // NOTE: excludeCredentials parameter -- see also: createcredential-excludecredentials.https.html
+
+ // timeout
+ new CreateCredentialsTest({path: "options.publicKey.timeout", value: undefined}).runTest("passing credentials.create() with no timeout");
+
+ // valid authenticatorSelection values
+ var defaultAuthnrSel = {
+ authenticatorAttachment: "cross-platform",
+ requireResidentKey: false,
+ userVerification: "preferred"
+ };
+ // attachment
+ var authnrSelAttachUndef = cloneObject(defaultAuthnrSel);
+ authnrSelAttachUndef.authenticatorAttachment = undefined;
+ // resident key
+ var authnrSelRkUndef = cloneObject(defaultAuthnrSel);
+ authnrSelRkUndef.requireResidentKey = undefined;
+ var authnrSelRkFalse = cloneObject(defaultAuthnrSel);
+ authnrSelRkFalse.requireResidentKey = false;
+ // user verification
+ var authnrSelUvUndef = cloneObject(defaultAuthnrSel);
+ authnrSelUvUndef.userVerification = undefined;
+ var authnrSelUvDiscouraged = cloneObject(defaultAuthnrSel);
+ authnrSelUvDiscouraged.userVerification = "discouraged";
+ new CreateCredentialsTest({path: "options.publicKey.authenticatorSelection", value: undefined}).runTest("authenticatorSelection is undefined");
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", {}).runTest("authenticatorSelection is empty object");
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", cloneObject(defaultAuthnrSel)).runTest("authenticatorSelection default values");
+
+ // authnr selection attachment
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelAttachUndef).runTest("authenticatorSelection attachment undefined");
+
+ // authnr selection resident key
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelRkUndef).runTest("authenticatorSelection residentKey undefined");
+ // XXX: assumes authnr is behaving like most U2F authnrs; really depends on the authnr or mock configuration
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelRkFalse).runTest("authenticatorSelection residentKey false");
+
+ // authnr selection user verification
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelUvUndef).runTest("authenticatorSelection userVerification undefined");
+ new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelUvDiscouraged).runTest("authenticatorSelection userVerification discouraged");
+
+
+ // good attestation values
+ new CreateCredentialsTest("options.publicKey.attestation", "none").runTest("attestation parameter: attestation is \"none\"");
+ new CreateCredentialsTest("options.publicKey.attestation", "indirect").runTest("attestation parameter: attestation is \"indirect\"");
+ new CreateCredentialsTest("options.publicKey.attestation", "direct").runTest("attestation parameter: attestation is \"direct\"");
+ new CreateCredentialsTest({path: "options.publicKey.attestation", value: undefined}).runTest("attestation parameter: attestation is undefined");
+ // TODO: test this with multiple mock authenticators to make sure that the right options are chosen when available?
+
+ // good extension values
+ new CreateCredentialsTest({path: "options.publicKey.extensions", value: undefined}).runTest("extensions undefined");
+ new CreateCredentialsTest("options.publicKey.extensions", {}).runTest("extensions are empty object");
+ new CreateCredentialsTest("options.publicKey.extensions", {foo: "", bar: "", bat: ""}).runTest("extensions are dict of empty strings");
});
/* JSHINT */
-/* globals standardSetup, CreateCredentialsTest */
+/* globals standardSetup, CreateCredentialsTest, cose_alg_ECDSA_w_SHA256, cose_alg_ECDSA_w_SHA512, cloneObject */
</script>
\ No newline at end of file
diff --git a/webauthn/createcredential-pubkeycredparams.https.html b/webauthn/createcredential-pubkeycredparams.https.html
new file mode 100644
index 0000000..325191c
--- /dev/null
+++ b/webauthn/createcredential-pubkeycredparams.https.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.create() pubKeyCredParams Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+ "use strict";
+
+ var badType = {
+ type: "something-else",
+ alg: cose_alg_ECDSA_w_SHA512
+ };
+ var badTypeEmptyString = cloneObject(badType);
+ badTypeEmptyString.type = "";
+ var badTypeNull = cloneObject(badType);
+ badTypeNull.type = null;
+ var badTypeEmptyObj = cloneObject(badType);
+ badTypeEmptyObj.type = {};
+
+ var badAlg = {
+ type: "public-key",
+ alg: 42
+ };
+ var badAlgZero = cloneObject(badAlg);
+ badAlgZero.alg = 0;
+
+ // bad pubKeyCredParams values
+ new CreateCredentialsTest({path: "options.publicKey.pubKeyCredParams", value: undefined}).runTest("Bad pubKeyCredParams: pubKeyCredParams is undefined", new TypeError());
+ new CreateCredentialsTest("options.publicKey.pubKeyCredParams", "hi mom").runTest("Bad pubKeyCredParams: pubKeyCredParams is string", new TypeError());
+ new CreateCredentialsTest("options.publicKey.pubKeyCredParams", null).runTest("Bad pubKeyCredParams: pubKeyCredParams is null", new TypeError());
+ new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badType]).runTest("Bad pubKeyCredParams: first param has bad type (\"something-else\")", new TypeError());
+ new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badTypeEmptyString]).runTest("Bad pubKeyCredParams: first param has bad type (\"\")", new TypeError());
+ new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badTypeNull]).runTest("Bad pubKeyCredParams: first param has bad type (null)", new TypeError());
+ new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badTypeEmptyObj]).runTest("Bad pubKeyCredParams: first param has bad type (empty object)", new TypeError());
+ new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badAlg]).runTest("Bad pubKeyCredParams: first param has bad alg (42)", "NotSupportedError");
+ new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badAlgZero]).runTest("Bad pubKeyCredParams: first param has bad alg (0)", "NotSupportedError");
+
+ // TODO: come back to this when mock authenticators support multiple cryptos so that we can test the preference ranking
+ // function verifyEC256(res) {
+ // debug ("verifyEC256 got", res);
+ // debug ("client data JSON", ab2str(res.response.clientDataJSON));
+ // parseAuthenticatorData(res.response.attestationObject);
+ // }
+ // new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [pkParamEC256, pkParamEC512])
+ // .afterTest(verifyEC256)
+ // .runTest("EC256, EC512 pubKeyCredParams");
+ // function verifyEC512(res) {
+ // debug ("verifyEC512 got", res);
+ // debug ("client data JSON", ab2str(res.response.clientDataJSON));
+ // // parseAuthenticatorData(res.response.attestationObject);
+ // printHex ("clientDataJSON", res.response.clientDataJSON);
+ // printHex ("attestationObject", res.response.attestationObject);
+ // }
+ // new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [pkParamEC512, pkParamEC256])
+ // .afterTest(verifyEC512)
+ // .runTest("EC512, EC256 pubKeyCredParams");
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest, cose_alg_ECDSA_w_SHA512, cloneObject */
+</script>
\ No newline at end of file
diff --git a/webauthn/createcredential-timeout.https.html b/webauthn/createcredential-timeout.https.html
new file mode 100644
index 0000000..b94ae58
--- /dev/null
+++ b/webauthn/createcredential-timeout.https.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.create() timeout Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+ "use strict";
+
+ // bad timeout values
+ // TODO: there is some debate as to whether MAX_UNSIGNED_LONG + 1 and / or -1 should be disallowed since they get converted to valid values internally
+ // new CreateCredentialsTest({path: "options.publicKey.timeout", value: -1}).runTest("Bad timeout: negative", new TypeError());
+ // new CreateCredentialsTest({path: "options.publicKey.timeout", value: 4294967295 + 1}).runTest("Bad timeout: too big", new TypeError());
+
+ // timeout test
+ // XXX: this probably always passes with most mock authenticators unless
+ // some setup happens right here to make sure they don't return a credential
+ // right away. So... uhh... I guess test this with a real authenticator if you
+ // want to see if it really works.
+ promise_test(() => {
+ return new Promise((resolve, reject) => {
+ var args = {
+ options: {
+ publicKey: {
+ timeout: 1
+ }
+ }
+ };
+
+ setTimeout(() => {
+ reject(new Error ("timed out"));
+ }, 1000);
+
+ createCredential(args).then((res) => {
+ resolve(res);
+ });
+ });
+ }, "ensure create credential times out");
+ // TODO: createCredential.timeout > 1s && setTimeout < 1s
+ // TODO: createCredential.timeout < 5s && setTimeout > 5s
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest, createCredential, promise_test */
+</script>
\ No newline at end of file
diff --git a/webauthn/getcredential-badargs-rpid.https.html b/webauthn/getcredential-badargs-rpid.https.html
new file mode 100644
index 0000000..9e8da4d
--- /dev/null
+++ b/webauthn/getcredential-badargs-rpid.https.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn credential.get() rpId Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+ "use strict";
+
+ var credPromise = createCredential();
+
+ new GetCredentialsTest("options.publicKey.rpId", "")
+ .addCredential(credPromise)
+ .runTest("Bad rpId: empty string", "SecurityError");
+ new GetCredentialsTest("options.publicKey.rpId", null)
+ .addCredential(credPromise)
+ .runTest("Bad rpId: null", "SecurityError");
+ new GetCredentialsTest("options.publicKey.rpId", "invalid domain.com")
+ .addCredential(credPromise)
+ .runTest("Bad rpId: invalid domain (has space)", "SecurityError");
+ new GetCredentialsTest("options.publicKey.rpId", "-invaliddomain.com")
+ .addCredential(credPromise)
+ .runTest("Bad rpId: invalid domain (starts with dash)", "SecurityError");
+ new GetCredentialsTest("options.publicKey.rpId", "0invaliddomain.com")
+ .addCredential(credPromise)
+ .runTest("Bad rpId: invalid domain (starts with number)", "SecurityError");
+});
+
+/* JSHINT */
+/* globals standardSetup, GetCredentialsTest, createCredential */
+</script>
\ No newline at end of file
diff --git a/webauthn/getcredential-badargs-userverification.https.html b/webauthn/getcredential-badargs-userverification.https.html
new file mode 100644
index 0000000..6101540
--- /dev/null
+++ b/webauthn/getcredential-badargs-userverification.https.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.get() user verification Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+ "use strict";
+
+ var credPromise = createCredential();
+
+ // authenticatorSelection bad userVerification values
+ new GetCredentialsTest("options.publicKey.userVerification", "")
+ .addCredential(credPromise)
+ .runTest("Bad userVerification: empty string", new TypeError());
+ new GetCredentialsTest("options.publicKey.userVerification", {})
+ .addCredential(credPromise)
+ .runTest("Bad userVerification: empty object", new TypeError());
+ new GetCredentialsTest("options.publicKey.userVerification", "requiredshirtshoestshirt")
+ .addCredential(credPromise)
+ .runTest("Bad userVerification: bad value", new TypeError());
+ new GetCredentialsTest("options.publicKey.userVerification", null)
+ .addCredential(credPromise)
+ .runTest("Bad userVerification: null", new TypeError());
+ // XXX: assumes this is a mock authenticator the properly reports that it is not doing userVerfication
+ new GetCredentialsTest("options.publicKey.userVerification", "required")
+ .addCredential(credPromise)
+ .runTest("Bad userVerification: \"required\"", "NotAllowedError");
+});
+
+/* JSHINT */
+/* globals standardSetup, GetCredentialsTest, createCredential */
+</script>
\ No newline at end of file
diff --git a/webauthn/getcredential-extensions.https.html b/webauthn/getcredential-extensions.https.html
new file mode 100644
index 0000000..bad5ce4
--- /dev/null
+++ b/webauthn/getcredential-extensions.https.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.get() extensions Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+ "use strict";
+
+ var dummyExtension = {
+ foo: true,
+ bar: "yup"
+ };
+ var credPromise = createCredential();
+
+ // bad extension values
+ new GetCredentialsTest("options.publicKey.extensions", "hi mom")
+ .addCredential(credPromise)
+ .runTest("Bad extensions: extensions is string", new TypeError());
+ new GetCredentialsTest("options.publicKey.extensions", null)
+ .addCredential(credPromise)
+ .runTest("Bad extensions: extensions is null", new TypeError());
+ new GetCredentialsTest("options.publicKey.extensions", [])
+ .addCredential(credPromise)
+ .runTest("Bad extensions: extensions is empty Array", new TypeError());
+ new GetCredentialsTest("options.publicKey.extensions", new ArrayBuffer(0))
+ .addCredential(credPromise)
+ .runTest("Bad extensions: extensions is empty ArrayBuffer", new TypeError());
+ var badJson = '{"foo": true, "bar: "yup"}'; // missing quote after "bar"
+ new GetCredentialsTest("options.publicKey.extensions", {foo: badJson})
+ .addCredential(credPromise)
+ .runTest("Bad extensions: malformatted JSON", new TypeError());
+ new GetCredentialsTest("options.publicKey.extensions", {foo: dummyExtension})
+ .addCredential(credPromise)
+ .runTest("Bad extensions: JavaScript object", new TypeError());
+ var badExtId = {};
+ badExtId[createRandomString(65)] = dummyExtension;
+ new GetCredentialsTest("options.publicKey.extensions", {badExtId: dummyExtension})
+ .addCredential(credPromise)
+ .runTest("Bad extensions: extension ID too long", new TypeError());
+
+ // phony extensions
+ // TODO: not sure if this should pass or fail
+ // should be clarified as part of https://github.com/w3c/webauthn/pull/765
+ var randomExtId = {};
+ randomExtId[createRandomString(64)] = dummyExtension;
+ new GetCredentialsTest("options.publicKey.extensions", {foo: JSON.stringify(randomExtId)})
+ .addCredential(credPromise)
+ .runTest("extensions is a nonsensical JSON string");
+
+ // TODO
+ // defined extensions:
+ // * appid
+ // * txAuthSimple
+ // * txAuthGeneric
+ // * authnSel
+ // * exts
+ // * uvi
+ // * loc
+ // * uvm
+});
+
+/* JSHINT */
+/* globals standardSetup, GetCredentialsTest, createRandomString, createCredential */
+</script>
\ No newline at end of file
diff --git a/webauthn/getcredential-passing.https.html b/webauthn/getcredential-passing.https.html
index c7cf794..58b085f 100644
--- a/webauthn/getcredential-passing.https.html
+++ b/webauthn/getcredential-passing.https.html
@@ -11,11 +11,56 @@
standardSetup(function() {
"use strict";
- // GetCredentialsTest passing tests
- // new GetCredentialsTest().addCredential();
- new GetCredentialsTest().addCredential().test();
+ var credPromise = createCredential();
+
+ // GetCredentialsTest with default args
+ new GetCredentialsTest()
+ .addCredential(credPromise)
+ .runTest("passing credentials.get() with default args");
+
+ // timeout
+ new GetCredentialsTest({path: "options.publicKey.timeout", value: undefined})
+ .addCredential(credPromise)
+ .runTest("passing credentials.create() with no timeout");
+
+ // rpId
+ new GetCredentialsTest({path: "options.publicKey.rpId", value: undefined})
+ .addCredential(credPromise)
+ .runTest("rpId undefined");
+ new GetCredentialsTest({path: "options.publicKey.rpId", value: window.location.host})
+ .addCredential(credPromise)
+ .runTest("passing credentials.get() with rpId (host and port)");
+ new GetCredentialsTest({path: "options.publicKey.rpId", value: window.location.hostname})
+ .addCredential(credPromise)
+ .runTest("passing credentials.get() with rpId (hostname)");
+
+ // allowCredentials
+ new GetCredentialsTest({path: "options.publicKey.allowCredentials", value: undefined})
+ .runTest("no credential specified");
+
+ // authnr selection user verification
+ new GetCredentialsTest({path: "options.publicKey.userVerification", value: undefined})
+ .addCredential(credPromise)
+ .runTest("authenticatorSelection userVerification undefined");
+ new GetCredentialsTest("options.publicKey.userVerification", "preferred")
+ .addCredential(credPromise)
+ .runTest("authenticatorSelection userVerification preferred");
+ new GetCredentialsTest("options.publicKey.userVerification", "discouraged")
+ .addCredential(credPromise)
+ .runTest("authenticatorSelection userVerification discouraged");
+
+ // good extension values
+ new GetCredentialsTest({path: "options.publicKey.extensions", value: undefined})
+ .addCredential(credPromise)
+ .runTest("extensions undefined");
+ new GetCredentialsTest("options.publicKey.extensions", {})
+ .addCredential(credPromise)
+ .runTest("extensions are empty object");
+ new GetCredentialsTest("options.publicKey.extensions", {foo: "", bar: "", bat: ""})
+ .addCredential(credPromise)
+ .runTest("extensions are dict of empty strings");
});
/* JSHINT */
-/* globals standardSetup, GetCredentialsTest */
+/* globals standardSetup, GetCredentialsTest, createCredential */
</script>
\ No newline at end of file
diff --git a/webauthn/getcredential-timeout.https.html b/webauthn/getcredential-timeout.https.html
new file mode 100644
index 0000000..8f5c2f3
--- /dev/null
+++ b/webauthn/getcredential-timeout.https.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.get() timeout Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+ "use strict";
+
+ var credPromise = createCredential();
+
+ // bad timeout values
+ // TODO: there is some debate as to whether MAX_UNSIGNED_LONG + 1 and / or -1 should be disallowed since they get converted to valid values internally
+ // new GetCredentialsTest({path: "options.publicKey.timeout", value: -1})
+ // .addCredential(credPromise)
+ // .runTest("Bad timeout: negative", new TypeError());
+ // new GetCredentialsTest({path: "options.publicKey.timeout", value: 4294967295 + 1})
+ // .addCredential(credPromise)
+ // .runTest("Bad timeout: too big", new TypeError());
+
+ // timeout test
+ // XXX: this probably always passes with most mock authenticators unless
+ // some setup happens right here to make sure they don't return a credential
+ // right away. So... uhh... I guess test this with a real authenticator if you
+ // want to see if it really works.
+ var timer;
+ function startTimer() {
+ timer = setTimeout(() => {
+ throw new Error("Timer went off before timeout");
+ }, 1000);
+ }
+ function stopTimer() {
+ clearTimeout(timer);
+ }
+ new GetCredentialsTest({path: "options.publicKey.timeout", value: 1})
+ .addCredential(credPromise)
+ .beforeTest(startTimer)
+ .afterTest(stopTimer)
+ .runTest("ensure create credential times out");
+ // TODO: createCredential.timeout > 1s && setTimeout < 1s
+ // TODO: createCredential.timeout < 5s && setTimeout > 5s
+});
+
+/* JSHINT */
+/* globals standardSetup, GetCredentialsTest, createCredential */
+</script>
\ No newline at end of file
diff --git a/webauthn/helpers.js b/webauthn/helpers.js
index 11d0aee..568d3e2 100644
--- a/webauthn/helpers.js
+++ b/webauthn/helpers.js
@@ -1,5 +1,4 @@
-
-/* Useful constants for working with COSE key objects */
+// Useful constants for working with COSE key objects
const cose_kty = 1;
const cose_kty_ec2 = 2;
const cose_alg = 3;
@@ -11,6 +10,117 @@
const cose_crv_y = -3;
/**
+ * These are the default arguments that will be passed to navigator.credentials.create()
+ * unless modified by a specific test case
+ */
+var createCredentialDefaultArgs = {
+ options: {
+ publicKey: {
+ // Relying Party:
+ rp: {
+ name: "Acme",
+ icon: "https://www.w3.org/StyleSheets/TR/2016/logos/W3C"
+ },
+
+ // User:
+ user: {
+ id: new Uint8Array(16), // Won't survive the copy, must be rebuilt
+ name: "john.p.smith@example.com",
+ displayName: "John P. Smith",
+ icon: "https://pics.acme.com/00/p/aBjjjpqPb.png"
+ },
+
+ pubKeyCredParams: [{
+ type: "public-key",
+ alg: cose_alg_ECDSA_w_SHA256,
+ }],
+
+ timeout: 60000, // 1 minute
+ excludeCredentials: [] // No excludeList
+ }
+ }
+};
+
+/**
+ * These are the default arguments that will be passed to navigator.credentials.get()
+ * unless modified by a specific test case
+ */
+var getCredentialDefaultArgs = {
+ options: {
+ publicKey: {
+ timeout: 60000
+ // allowCredentials: [newCredential]
+ }
+ }
+};
+
+function createCredential(opts) {
+ opts = opts || {};
+
+ // set the default options
+ var createArgs = cloneObject(createCredentialDefaultArgs);
+ let challengeBytes = new Uint8Array(16);
+ window.crypto.getRandomValues(challengeBytes);
+ createArgs.options.publicKey.challenge = challengeBytes;
+ createArgs.options.publicKey.user.id = new Uint8Array(16);
+
+ // change the defaults with any options that were passed in
+ extendObject (createArgs, opts);
+
+ // create the credential, return the Promise
+ return navigator.credentials.create(createArgs.options);
+}
+
+function createRandomString(len) {
+ var text = "";
+ var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+ for(var i = 0; i < len; i++) {
+ text += possible.charAt(Math.floor(Math.random() * possible.length));
+ }
+ return text;
+}
+
+
+function ab2str(buf) {
+ return String.fromCharCode.apply(null, new Uint8Array(buf));
+}
+
+// Useful constants for working with attestation data
+const authenticator_data_user_present = 0x01;
+const authenticator_data_user_verified = 0x04;
+const authenticator_data_attested_cred_data = 0x40;
+const authenticator_data_extension_data = 0x80;
+
+function parseAuthenticatorData(buf) {
+ if (buf.byteLength < 37) {
+ throw new TypeError ("parseAuthenticatorData: buffer must be at least 37 bytes");
+ }
+
+ printHex ("authnrData", buf);
+
+ var authnrData = new DataView(buf);
+ var authnrDataObj = {};
+ authnrDataObj.length = buf.byteLength;
+
+ authnrDataObj.rpIdHash = new Uint8Array (buf.slice (0,32));
+ authnrDataObj.rawFlags = authnrData.getUint8(32);
+ authnrDataObj.counter = authnrData.getUint32(33, false);
+ authnrDataObj.rawCounter = [];
+ authnrDataObj.rawCounter[0] = authnrData.getUint8(33);
+ authnrDataObj.rawCounter[1] = authnrData.getUint8(34);
+ authnrDataObj.rawCounter[2] = authnrData.getUint8(35);
+ authnrDataObj.rawCounter[3] = authnrData.getUint8(36);
+ authnrDataObj.flags = {};
+
+ authnrDataObj.flags.userPresent = (authnrDataObj.rawFlags&authenticator_data_user_present)?true:false;
+ authnrDataObj.flags.userVerified = (authnrDataObj.rawFlags&authenticator_data_user_verified)?true:false;
+ authnrDataObj.flags.attestedCredentialData = (authnrDataObj.rawFlags&authenticator_data_attested_cred_data)?true:false;
+ authnrDataObj.flags.extensionData = (authnrDataObj.rawFlags&authenticator_data_extension_data)?true:false;
+
+ return authnrDataObj;
+}
+
+/**
* TestCase
*
* A generic template for test cases
@@ -118,66 +228,127 @@
/**
* run the test function with the top-level properties of the test object applied as arguments
+ * expects the test to pass, and then validates the results
*/
- test(desc) {
- promise_test(() => {
- return this.doIt()
- .then((ret) => {
- // check the result
- this.validateRet(ret);
- return ret;
- });
- }, desc);
+ testPasses(desc) {
+ return this.doIt()
+ .then((ret) => {
+ // check the result
+ this.validateRet(ret);
+ return ret;
+ });
+ }
+
+ /**
+ * run the test function with the top-level properties of the test object applied as arguments
+ * expects the test to fail
+ */
+ testFails(t, testDesc, expectedErr) {
+ return promise_rejects(t, expectedErr, this.doIt(), "Expected bad parameters to fail");
+ }
+
+ /**
+ * Runs the test that's implemented by the class by calling the doIt() function
+ * @param {String} desc A description of the test being run
+ * @param [Error|String] expectedErr A string matching an error type, such as "SecurityError" or an object with a .name value that is an error type string
+ */
+ runTest(desc, expectedErr) {
+ promise_test((t) => {
+ return Promise.resolve().then(() => {
+ return this.testSetup();
+ }).then(() => {
+ if (expectedErr === undefined) {
+ return this.testPasses(desc);
+ } else {
+ return this.testFails(t, desc, expectedErr);
+ }
+ }).then((res) => {
+ return this.testTeardown(res);
+ })
+ }, desc)
+ }
+
+ /**
+ * called before runTest
+ * virtual method expected to be overridden by child class if needed
+ */
+ testSetup() {
+ if (this.beforeTestFn) {
+ this.beforeTestFn.call(this);
+ }
+
+ return Promise.resolve();
+ }
+
+ /**
+ * Adds a callback function that gets called in the TestCase context
+ * and within the testing process.
+ */
+ beforeTest(fn) {
+ if (typeof fn !== "function") {
+ throw new Error ("Tried to call non-function before test");
+ }
+
+ this.beforeTestFn = fn;
+
+ return this;
+ }
+
+ /**
+ * called after runTest
+ * virtual method expected to be overridden by child class if needed
+ */
+ testTeardown(res) {
+ if (this.afterTestFn) {
+ this.afterTestFn.call(this, res);
+ }
+
+ return Promise.resolve();
+ }
+
+ /**
+ * Adds a callback function that gets called in the TestCase context
+ * and within the testing process. Good for validating results.
+ */
+ afterTest(fn) {
+ if (typeof fn !== "function") {
+ throw new Error ("Tried to call non-function after test");
+ }
+
+ this.afterTestFn = fn;
+
+ return this;
}
/**
* validates the value returned from the test function
+ * virtual method expected to be overridden by child class
*/
validateRet() {
throw new Error("Not implemented");
}
-
- /**
- * calls doIt() with testObject() and expects it to fail with a TypeError()
- */
- testBadArgs(testDesc) {
- promise_test(function(t) {
- return promise_rejects(t, new TypeError(), this.doIt(), "Expected bad parameters to fail");
- }.bind(this), testDesc);
- }
}
-var createCredentialDefaultArgs = {
- options: {
- publicKey: {
- // Relying Party:
- rp: {
- name: "Acme"
- },
-
- // User:
- user: {
- id: new Uint8Array(), // Won't survive the copy, must be rebuilt
- name: "john.p.smith@example.com",
- displayName: "John P. Smith",
- icon: "https://pics.acme.com/00/p/aBjjjpqPb.png"
- },
-
- pubKeyCredParams: [{
- type: "public-key",
- alg: cose_alg_ECDSA_w_SHA256,
- }],
-
- timeout: 60000, // 1 minute
- excludeCredentials: [] // No excludeList
- }
- }
-};
-
function cloneObject(o) {
return JSON.parse(JSON.stringify(o));
}
+function extendObject(dst, src) {
+ Object.keys(src).forEach(function(key) {
+ if (isSimpleObject(src[key])) {
+ extendObject (dst[key], src[key]);
+ } else {
+ dst[key] = src[key];
+ }
+ });
+}
+
+function isSimpleObject(o) {
+ return (typeof o === "object" &&
+ !Array.isArray(o) &&
+ !(o instanceof ArrayBuffer));
+}
+
/**
* CreateCredentialTest
*
@@ -198,7 +369,7 @@
window.crypto.getRandomValues(challengeBytes);
this.testObject = cloneObject(createCredentialDefaultArgs);
// cloneObject can't clone the BufferSource in user.id, so let's recreate it.
- this.testObject.options.publicKey.user.id = new Uint8Array();
+ this.testObject.options.publicKey.user.id = new Uint8Array(16);
this.testObject.options.publicKey.challenge = challengeBytes;
// how to order the properties of testObject when passing them to makeCredential
@@ -235,15 +406,8 @@
// default arguments
let challengeBytes = new Uint8Array(16);
window.crypto.getRandomValues(challengeBytes);
- this.testObject = {
- options: {
- publicKey: {
- challenge: challengeBytes,
- // timeout: 60000,
- // allowCredentials: [newCredential]
- }
- }
- };
+ this.testObject = cloneObject(getCredentialDefaultArgs);
+ this.testObject.options.publicKey.challenge = challengeBytes;
// how to order the properties of testObject when passing them to makeCredential
this.argOrder = [
@@ -266,33 +430,28 @@
// if a Promise was passed in, add it to the list
if (arg instanceof Promise) {
this.credentialPromiseList.push(arg);
- return;
+ return this;
}
// if a credential object was passed in, convert it to a Promise for consistency
if (typeof arg === "object") {
this.credentialPromiseList.push(Promise.resolve(arg));
- return;
+ return this;
}
- // if a credential wasn't passed in, create one
- let challengeBytes = new Uint8Array(16);
- window.crypto.getRandomValues(challengeBytes);
- var createArgs = cloneObject(createCredentialDefaultArgs);
- createArgs.options.publicKey.challenge = challengeBytes;
- createArgs.options.publicKey.user.id = new Uint8Array();
- var p = navigator.credentials.create(createArgs.options);
+ // if no credential specified then create one
+ var p = createCredential();
this.credentialPromiseList.push(p);
return this;
}
- test() {
+ testSetup(desc) {
if (!this.credentialPromiseList.length) {
throw new Error("Attempting list without defining credential to test");
}
- Promise.all(this.credentialPromiseList)
+ return Promise.all(this.credentialPromiseList)
.then((credList) => {
var idList = credList.map((cred) => {
return {
@@ -302,12 +461,15 @@
};
});
this.testObject.options.publicKey.allowCredentials = idList;
- return super.test();
+ // return super.test(desc);
+ })
+ .catch((err) => {
+ throw Error(err);
});
}
validateRet(ret) {
- validatePublicKeyCredential (ret);
+ validatePublicKeyCredential(ret);
validateAuthenticatorAssertionResponse(ret.response);
}
}
@@ -335,12 +497,16 @@
function validateAuthenticatorAttestationResponse(attr) {
// class
assert_class_string(attr, "AuthenticatorAttestationResponse", "Expected credentials.create() to return instance of 'AuthenticatorAttestationResponse' class");
+
// clientDataJSON
assert_idl_attribute(attr, "clientDataJSON", "credentials.create() should return AuthenticatorAttestationResponse with clientDataJSON attribute");
assert_readonly(attr, "clientDataJSON", "credentials.create() should return AuthenticatorAttestationResponse with readonly clientDataJSON attribute");
+ // TODO: clientDataJSON() and make sure fields are correct
+
// attestationObject
assert_idl_attribute(attr, "attestationObject", "credentials.create() should return AuthenticatorAttestationResponse with attestationObject attribute");
assert_readonly(attr, "attestationObject", "credentials.create() should return AuthenticatorAttestationResponse with readonly attestationObject attribute");
+ // TODO: parseAuthenticatorData() and make sure flags are correct
}
/**
@@ -349,15 +515,20 @@
function validateAuthenticatorAssertionResponse(assert) {
// class
assert_class_string(assert, "AuthenticatorAssertionResponse", "Expected credentials.create() to return instance of 'AuthenticatorAssertionResponse' class");
+
// clientDataJSON
assert_idl_attribute(assert, "clientDataJSON", "credentials.get() should return AuthenticatorAssertionResponse with clientDataJSON attribute");
assert_readonly(assert, "clientDataJSON", "credentials.get() should return AuthenticatorAssertionResponse with readonly clientDataJSON attribute");
+ // TODO: clientDataJSON() and make sure fields are correct
+
// signature
assert_idl_attribute(assert, "signature", "credentials.get() should return AuthenticatorAssertionResponse with signature attribute");
assert_readonly(assert, "signature", "credentials.get() should return AuthenticatorAssertionResponse with readonly signature attribute");
+
// authenticatorData
assert_idl_attribute(assert, "authenticatorData", "credentials.get() should return AuthenticatorAssertionResponse with authenticatorData attribute");
assert_readonly(assert, "authenticatorData", "credentials.get() should return AuthenticatorAssertionResponse with readonly authenticatorData attribute");
+ // TODO: parseAuthenticatorData() and make sure flags are correct
}
//************* BEGIN DELETE AFTER 1/1/2018 *************** //
@@ -370,8 +541,8 @@
// note that the polyfill only gets loaded if navigator.credentials create doesn't exist
// AND if the polyfill script is found at the right path (i.e. - the polyfill is opt-in)
function ensureInterface() {
- if (typeof navigator.credentials.create !== "function") {
- debug = console.log;
+ if (typeof navigator.credentials === "object" && typeof navigator.credentials.create !== "function") {
+ // debug = onsole.log;
return loadJavaScript("/webauthn/webauthn-polyfill/webauthn-polyfill.js")
.then(() => {
diff --git a/webauthn/securecontext.http.html b/webauthn/securecontext.http.html
index 82464bd..5278695 100644
--- a/webauthn/securecontext.http.html
+++ b/webauthn/securecontext.http.html
@@ -17,7 +17,7 @@
// Example 1
// http://example.com/ opened in a top-level browsing context is not a secure context, as it was not delivered over an authenticated and encrypted channel.
test (() => {
- assert_false (typeof navigator.credentials.create === "function");
+ assert_false (typeof navigator.credentials === "object" && typeof navigator.credentials.create === "function");
}, "no navigator.credentials.create in non-secure context");
// Example 4: TODO
diff --git a/webauthn/securecontext.https.html b/webauthn/securecontext.https.html
index 9810a7f..6c9aabd 100644
--- a/webauthn/securecontext.https.html
+++ b/webauthn/securecontext.https.html
@@ -17,7 +17,7 @@
// Example 2
// https://example.com/ opened in a top-level browsing context is a secure context, as it was delivered over an authenticated and encrypted channel.
test (() => {
- assert_true (typeof navigator.credentials.create === "function");
+ assert_true (typeof navigator.credentials === "object" && typeof navigator.credentials.create === "function");
}, "navigator.credentials.create exists in secure context");
// Example 3: TODO