summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/infrastructure/testdriver
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/infrastructure/testdriver')
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/actions/actionsWithKeyPressed.html66
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/actions/crossOrigin.sub.html20
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/actions/crossOriginChild.html32
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/actions/elementPosition.html43
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/actions/elementTiming.html69
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/actions/eventOrder.html61
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/actions/iframe.html35
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/actions/iframeChild.html2
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/actions/mouseClickCount.html54
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/actions/multiDevice.html36
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/actions/multiTouchPoints.html68
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/actions/multiTouchPointsReleaseFirstPoint.html56
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/actions/multiTouchPointsReleaseSecondPoint.html69
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/actions/multiTouchPointsSimultaneousMove.html58
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/actions/multiTouchPointsTwoTouchStarts.html58
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/actions/multiTouchPointsWithPause.html67
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/actions/pause.html19
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/actions/penPointerEventProperties.html71
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/actions/penPointerEvents.html159
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/actions/textEditCommands.html61
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/actions/touchEvents.js11
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/actions/touchPointerEventProperties.html71
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/actions/wheelScroll.html44
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/bless.html114
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/click-multiple.html38
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/click.html19
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/click_child.html7
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/click_child_crossorigin.html18
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/click_child_testdriver.html18
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/click_iframe.html24
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/click_iframe_crossorigin.sub.html23
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/click_nested.html31
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/click_nested_crossorigin.sub.html25
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/click_outer_child.html4
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/click_outer_child.sub.html4
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/click_window.html24
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/delete_all_cookies.html30
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/file_upload.py2
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/file_upload.sub.html26
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/file_upload_data.txt1
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/generate_test_report.html16
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/get_all_cookies.sub.html95
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/get_all_cookies.sub.html.headers1
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/get_all_cookies.sub.https.html112
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/get_all_cookies.sub.https.html.headers1
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/get_named_cookie.sub.html105
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/get_named_cookie.sub.html.headers1
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/get_named_cookie.sub.https.html114
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/get_named_cookie.sub.https.html.headers1
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/send_keys.html23
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/set_permission.https.html23
-rw-r--r--testing/web-platform/tests/infrastructure/testdriver/virtual_authenticator.html88
52 files changed, 2218 insertions, 0 deletions
diff --git a/testing/web-platform/tests/infrastructure/testdriver/actions/actionsWithKeyPressed.html b/testing/web-platform/tests/infrastructure/testdriver/actions/actionsWithKeyPressed.html
new file mode 100644
index 0000000000..3e0795b14a
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/actions/actionsWithKeyPressed.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver actions: actions with key pressed</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<style>
+div#test1, div#test2 {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100px;
+ height: 100px;
+ background-color: blue;
+}
+
+div#test2 {
+ position: fixed;
+ top: 100px;
+ left: 0;
+ width: 100px;
+ height: 100px;
+ background-color: green;
+}
+</style>
+
+<div id="test1">
+</div>
+
+<div id="test2">
+</div>
+
+<script>
+let keys = [];
+
+promise_test(async t => {
+ let test1 = document.getElementById("test1");
+ let test2 = document.getElementById("test2");
+ document.getElementById("test1").addEventListener("click",
+ e => {keys.push(e.getModifierState("Shift"))});
+ document.getElementById("test2").addEventListener("click",
+ e => {keys.push(e.getModifierState("Shift"))});
+
+ let actions = new test_driver.Actions()
+ .keyDown("\uE008")
+ .addTick()
+ .pointerMove(0, 0, {origin: test1})
+ .pointerDown()
+ .pointerUp()
+ .pointerMove(0, 0, {origin: test2})
+ .pointerDown()
+ .pointerUp()
+ .addTick()
+ .keyUp("\uE008")
+ .addTick()
+ .pointerMove(0, 0, {origin: test1})
+ .pointerDown()
+ .pointerUp();
+
+ await actions.send();
+ assert_array_equals(keys, [true, true, false]);
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/actions/crossOrigin.sub.html b/testing/web-platform/tests/infrastructure/testdriver/actions/crossOrigin.sub.html
new file mode 100644
index 0000000000..38b3610af6
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/actions/crossOrigin.sub.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Actions in cross-origin iframe</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<iframe src="https://{{host}}:{{ports[https][1]}}/infrastructure/testdriver/actions/crossOriginChild.html"></iframe>
+
+<script>
+setup({single_test: true});
+addEventListener("message", (msg) => {
+ if (msg.data === "PASS") {
+ done();
+ } else if (msg.data === "FAIL") {
+ assert_unreached("actions failed")
+ }
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/actions/crossOriginChild.html b/testing/web-platform/tests/infrastructure/testdriver/actions/crossOriginChild.html
new file mode 100644
index 0000000000..48e37e233e
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/actions/crossOriginChild.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+
+<input type=text>
+<script>
+let input = document.getElementsByTagName("input")[0];
+addEventListener("load", async () => {
+ test_driver.set_test_context(parent);
+ await new test_driver.Actions()
+ .pointerMove(0, 0, {origin: input})
+ .pointerDown()
+ .pointerUp()
+ .send();
+ await new test_driver.Actions()
+ .keyDown("P")
+ .keyUp("P")
+ .keyDown("A")
+ .keyUp("A")
+ .keyDown("S")
+ .keyUp("S")
+ .keyDown("S")
+ .keyUp("S")
+ .send();
+ if (input.value === "PASS") {
+ test_driver.message_test("PASS", "*")
+ } else {
+ test_driver.message_test("FAIL", "*")
+ }
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/actions/elementPosition.html b/testing/web-platform/tests/infrastructure/testdriver/actions/elementPosition.html
new file mode 100644
index 0000000000..145852e7b5
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/actions/elementPosition.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver actions: element position</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<style>
+div#test {
+ position: fixed;
+ left: -100px;
+ top: -25px;
+ width: 200px;
+ height: 75px;
+ background-color:blue;
+}
+</style>
+
+<div id="test">
+</div>
+
+<script>
+let events = [];
+
+async_test(t => {
+ let test = document.getElementById("test");
+ test.addEventListener("click", e => {
+ events.push(e.clientX);
+ events.push(e.clientY)
+ });
+
+ let div = document.getElementById("test");
+ let actions = new test_driver.Actions()
+ .pointerMove(0, 0, {origin: test})
+ .pointerDown()
+ .pointerUp()
+ .send()
+ .then(t.step_func_done(() => assert_array_equals(events, [50, 25])))
+ .catch(e => t.step_func(() => assert_unreached("Actions sequence failed " + e)));
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/actions/elementTiming.html b/testing/web-platform/tests/infrastructure/testdriver/actions/elementTiming.html
new file mode 100644
index 0000000000..33731e9299
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/actions/elementTiming.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver actions: element timing</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<style>
+div#test1, div#test2 {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100px;
+ height: 100px;
+ background-color: blue;
+}
+
+div#test2 {
+ display: none;
+ left: -100px;
+ background-color: green;
+}
+</style>
+
+<div id="test1">
+</div>
+
+<div id="test2">
+</div>
+
+<script>
+let events = [];
+
+promise_test(async t => {
+ let test1 = document.getElementById("test1");
+ let test2 = document.getElementById("test2");
+ test1.addEventListener("click",
+ () => {
+ test2.style.display = "block";
+ test2.style.top = "100px";
+ test2.style.left = "0"
+ });
+ test2.addEventListener("click",
+ e => {
+ events.push(e.clientX);
+ events.push(e.clientY);
+ });
+
+ const waitCondition = new Promise((resolve, reject)=>{setTimeout(resolve, 5000);});
+ const test1ClickWatcher = new EventWatcher(t, test1, ["click"], ()=>waitCondition);
+ const test2ClickWatcher = new EventWatcher(t, test2, ["click"], ()=>waitCondition);
+ let waitForClicks = Promise.all([test1ClickWatcher.wait_for(["click"]), test2ClickWatcher.wait_for(["click"])]);
+
+ await new test_driver.Actions()
+ .pointerMove(0, 0, {origin: test1})
+ .pointerDown()
+ .pointerUp()
+ .send();
+ await new test_driver.Actions()
+ .pointerMove(0, 0, {origin: test2})
+ .pointerDown()
+ .pointerUp()
+ .send();
+ await waitForClicks;
+ assert_array_equals(events, [50, 150])
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/actions/eventOrder.html b/testing/web-platform/tests/infrastructure/testdriver/actions/eventOrder.html
new file mode 100644
index 0000000000..1fed285a27
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/actions/eventOrder.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver actions: event order</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<button id="a">Button a</button>
+<button id="b">Button b</button>
+<input id="text-input">
+
+<script>
+// Pointer 1 is added before Pointer 2 so it comes first in the list of sources
+// Therefore its actions happen first
+let events = [];
+
+promise_test(() => {
+ Array.prototype.forEach.call(document.getElementsByTagName("button"),
+ (x) => x.addEventListener("mousedown", () => {events.push(x.id)}));
+
+ let button_a = document.getElementById("a");
+ let button_b = document.getElementById("b");
+ return new test_driver.Actions()
+ .addPointer("pointer1")
+ .addPointer("pointer2")
+ .pointerMove(0, 0, {origin: button_a, sourceName: "pointer1"})
+ .pointerMove(0, 0, {origin: button_b, sourceName: "pointer2"})
+ .pointerDown({sourceName: "pointer2"})
+ .pointerDown({sourceName: "pointer1"})
+ .pointerUp({sourceName: "pointer2"})
+ .pointerUp({sourceName: "pointer1"})
+ .send()
+ .then(() => assert_array_equals(events, ["a", "b"]));
+});
+
+// This test uses a large number of keyboard sources to force race conditions
+// in implementations which incorrectly dispatch events. Despite belonging to
+// the same "tick," each action's initial event should be dispatched in series.
+promise_test(() => {
+ const input = document.getElementById("text-input");
+ const actions = new test_driver.Actions();
+ const code_for_a = "a".charCodeAt(0);
+ const keys = Array.from(Array(26))
+ .map((_, index) => ({
+ sourceName: "keyboard" + index,
+ code: String.fromCharCode(code_for_a + index)
+ }));
+
+ keys.forEach(({sourceName}) => actions.addKeyboard(sourceName));
+ keys.forEach(({code, sourceName}) => actions.keyDown(code, {sourceName}));
+ keys.forEach(({code, sourceName}) => actions.keyUp(code,{sourceName}));
+
+ return test_driver.click(input)
+ .then(() => actions.send())
+ .then(() => {
+ assert_equals(input.value, "abcdefghijklmnopqrstuvwxyz");
+ });
+}, "indivisible actions on the same track dispatch events in series");
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/actions/iframe.html b/testing/web-platform/tests/infrastructure/testdriver/actions/iframe.html
new file mode 100644
index 0000000000..6c64d6f49a
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/actions/iframe.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver actions on a document in an iframe</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+
+<iframe src="iframeChild.html"></iframe>
+
+<script>
+setup({single_test: true});
+addEventListener("load", async () => {
+ let input = frames[0].document.getElementsByTagName("input")[0];
+ await new test_driver.Actions()
+ .pointerMove(0, 0, {origin: input})
+ .pointerDown()
+ .pointerUp()
+ .send();
+ await new test_driver.Actions()
+ .setContext(frames[0])
+ .keyDown("P")
+ .keyUp("P")
+ .keyDown("A")
+ .keyUp("A")
+ .keyDown("S")
+ .keyUp("S")
+ .keyDown("S")
+ .keyUp("S")
+ .send();
+ assert_equals(input.value, "PASS");
+ done();
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/actions/iframeChild.html b/testing/web-platform/tests/infrastructure/testdriver/actions/iframeChild.html
new file mode 100644
index 0000000000..a46c54a7b7
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/actions/iframeChild.html
@@ -0,0 +1,2 @@
+<!doctype html>
+<input type=text>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/actions/mouseClickCount.html b/testing/web-platform/tests/infrastructure/testdriver/actions/mouseClickCount.html
new file mode 100644
index 0000000000..4f02088c5a
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/actions/mouseClickCount.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver actions: test the mouse click counts at different cases</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<style>
+div#test {
+ position: fixed;
+ touch-action: none;
+ top: 5px;
+ left: 5px;
+ width: 100px;
+ height: 100px;
+ background-color: blue;
+}
+</style>
+
+<div id="test">
+</div>
+
+<script>
+let clickCountList = [];
+
+async_test(t => {
+ let test = document.getElementById("test");
+ test.addEventListener("click", e => {
+ clickCountList.push(e.detail);
+ });
+
+ let div = document.getElementById("test");
+ var actions = new test_driver.Actions();
+ actions.pointerMove(0, 0, {origin: test})
+ .pointerDown()
+ .pointerUp()
+ .pointerDown()
+ .pointerUp()
+ .pointerMove(15, 15, {origin: test})
+ .pointerDown()
+ .pointerUp()
+ .pointerDown()
+ .pointerUp()
+ .pointerDown()
+ .pointerUp()
+ .send()
+ .then(t.step_func_done(() => {
+ let expectedClickCountList = [1, 2, 1, 2, 3];
+ assert_array_equals(clickCountList, expectedClickCountList);
+ })).catch(e => t.step_func(() => assert_unreached("Actions sequence failed " + e)));
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/actions/multiDevice.html b/testing/web-platform/tests/infrastructure/testdriver/actions/multiDevice.html
new file mode 100644
index 0000000000..6bc0fa218d
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/actions/multiDevice.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver actions: multiple devices</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<input type="text" id="text"></input>
+
+<script>
+async_test(t => {
+ let text_box = document.getElementById("text");
+ let actions = new test_driver.Actions()
+ .pointerMove(0, 0, {origin: text_box})
+ .pointerDown()
+ .pointerUp()
+ .addTick()
+ .keyDown("p")
+ .keyUp("p")
+ .keyDown("a")
+ .keyUp("a")
+ .keyDown("s")
+ .keyUp("s")
+ .keyDown("s")
+ .keyUp("s");
+
+ actions.send()
+ .then(() => {
+ assert_equals(text_box.value, "pass");
+ t.done();
+ })
+ .catch(t.unreached_func("Actions sequence failed"));
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/actions/multiTouchPoints.html b/testing/web-platform/tests/infrastructure/testdriver/actions/multiTouchPoints.html
new file mode 100644
index 0000000000..64aa429631
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/actions/multiTouchPoints.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver actions: two touch points with one moving one pause</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="touchEvents.js"></script>
+
+<style>
+div#test1{
+ position: fixed;
+ touch-action: none;
+ top: 0;
+ left: 0;
+ width: 100px;
+ height: 100px;
+ background-color: blue;
+}
+
+</style>
+
+<div id="test1">
+</div>
+
+<script>
+promise_test(async t => {
+ const test1 = document.getElementById("test1");
+
+ const events = [];
+ addPointerEventListeners(t, test1, events);
+
+ const actions = new test_driver.Actions()
+ .addPointer("touchPointer1", "touch")
+ .addPointer("touchPointer2", "touch")
+ .pointerMove(0, 0, {origin: test1, sourceName: "touchPointer1"})
+ .pointerMove(10, 0, {origin: test1, sourceName: "touchPointer2"})
+ .pointerDown({sourceName: "touchPointer1"})
+ .pointerDown({sourceName: "touchPointer2"})
+ .pointerMove(0, 10, {origin: test1, sourceName: "touchPointer1"})
+ .pointerUp({sourceName: "touchPointer1"})
+ .pointerUp({sourceName: "touchPointer2"});
+
+ await actions.send()
+
+ eventEquals(events[0], {type: "pointerdown", pointerId: 2, clientX: 50, clientY: 50});
+ eventEquals(events[1], {type: "pointerdown", pointerId: 3, clientX: 60, clientY: 50});
+ // Allow one or two pointermove events
+ let index = 3;
+ const moveEvents = [events[2]];
+ if (events[3].type === "pointermove") {
+ index += 1;
+ moveEvents.push(events[3]);
+ }
+ for (const event of moveEvents) {
+ if (event.pointerId === 2) {
+ eventEquals(event, {type: "pointermove", clientX: 50, clientY: 60});
+ } else {
+ eventEquals(event, {type: "pointermove", pointerId: 3, clientX: 60, clientY: 50});
+ }
+ }
+ let remainingEvents = events.slice(index);
+ assert_equals(remainingEvents.length, 2);
+ eventEquals(remainingEvents[0], {type: "pointerup", pointerId: 2, clientX: 50, clientY: 60});
+ eventEquals(remainingEvents[1], {type: "pointerup", pointerId: 3, clientX: 60, clientY: 50});
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/actions/multiTouchPointsReleaseFirstPoint.html b/testing/web-platform/tests/infrastructure/testdriver/actions/multiTouchPointsReleaseFirstPoint.html
new file mode 100644
index 0000000000..41027beb67
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/actions/multiTouchPointsReleaseFirstPoint.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver actions: two touch points with one moving one pause</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="touchEvents.js"></script>
+
+<style>
+div#test1{
+ position: fixed;
+ touch-action: none;
+ top: 0;
+ left: 0;
+ width: 100px;
+ height: 100px;
+ background-color: blue;
+}
+
+</style>
+
+<div id="test1">
+</div>
+
+<script>
+promise_test(async t => {
+ let test1 = document.getElementById("test1");
+ const events = [];
+ addPointerEventListeners(t, test1, events);
+
+ await new test_driver.Actions()
+ .addPointer("touchPointer1", "touch")
+ .addPointer("touchPointer2", "touch")
+ .pointerMove(0, 0, {origin: test1, sourceName: "touchPointer1"})
+ .pointerMove(10, 0, {origin: test1, sourceName: "touchPointer2"})
+ .pointerDown({sourceName: "touchPointer1"})
+ .pointerDown({sourceName: "touchPointer2"})
+ .pointerUp({sourceName: "touchPointer1"})
+ .pointerMove(10, 10, {origin: test1, sourceName: "touchPointer2"})
+ .pointerUp({sourceName: "touchPointer2"})
+ .send();
+
+ const expected = [{type: "pointerdown", pointerId: 2, clientX: 50, clientY: 50},
+ {type: "pointerdown", pointerId: 3, clientX: 60, clientY: 50},
+ {type: "pointerup", pointerId: 2},
+ {type: "pointermove", pointerId: 3, clientX: 60, clientY:60},
+ {type: "pointerup", pointerId: 3}];
+
+ assert_equals(events.length, expected.length, "Expected number of events");
+ for (let i=0; i<expected.length; i++) {
+ eventEquals(events[i], expected[i]);
+ }
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/actions/multiTouchPointsReleaseSecondPoint.html b/testing/web-platform/tests/infrastructure/testdriver/actions/multiTouchPointsReleaseSecondPoint.html
new file mode 100644
index 0000000000..58a2263f5b
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/actions/multiTouchPointsReleaseSecondPoint.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver actions: two touch points with one moving one pause</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="touchEvents.js"></script>
+
+<style>
+div#test1{
+ position: fixed;
+ touch-action: none;
+ top: 0;
+ left: 0;
+ width: 100px;
+ height: 100px;
+ background-color: blue;
+}
+
+</style>
+
+<div id="test1">
+</div>
+
+<script>
+promise_test(async t => {
+ let test1 = document.getElementById("test1");
+
+ const events = [];
+ addPointerEventListeners(t, test1, events);
+
+ await new test_driver.Actions()
+ .addPointer("touchPointer1", "touch")
+ .addPointer("touchPointer2", "touch")
+ .pointerMove(0, 0, {origin: test1, sourceName: "touchPointer1"})
+ .pointerMove(10, 0, {origin: test1, sourceName: "touchPointer2"})
+ .pointerDown({sourceName: "touchPointer1"})
+ .pointerDown({sourceName: "touchPointer2"})
+ .pointerMove(10, 10, {origin: test1, sourceName: "touchPointer1"})
+ .addTick()
+ .pointerUp({sourceName: "touchPointer2"})
+ .addTick()
+ .pointerUp({sourceName: "touchPointer1"})
+ .send();
+
+ eventEquals(events[0], {type: "pointerdown", pointerId: 2, clientX: 50, clientY: 50});
+ eventEquals(events[1], {type: "pointerdown", pointerId: 3, clientX: 60, clientY: 50});
+ // Allow one or two pointermove events
+ let index = 3;
+ const moveEvents = [events[2]];
+ if (events[3].type === "pointermove") {
+ index += 1;
+ moveEvents.push(events[3]);
+ }
+ for (const event of moveEvents) {
+ if (event.pointerId === 2) {
+ eventEquals(event, {type: "pointermove", clientX: 60, clientY: 60});
+ } else {
+ eventEquals(event, {type: "pointermove", pointerId: 3, clientX: 60, clientY: 50});
+ }
+ }
+ let remainingEvents = events.slice(index);
+ assert_equals(remainingEvents.length, 2);
+ eventEquals(remainingEvents[0], {type: "pointerup", pointerId: 3, clientX: 60, clientY: 50});
+ eventEquals(remainingEvents[1], {type: "pointerup", pointerId: 2, clientX: 60, clientY: 60});
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/actions/multiTouchPointsSimultaneousMove.html b/testing/web-platform/tests/infrastructure/testdriver/actions/multiTouchPointsSimultaneousMove.html
new file mode 100644
index 0000000000..5be5b44896
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/actions/multiTouchPointsSimultaneousMove.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver actions: two touch points with both moving</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="touchEvents.js"></script>
+
+<style>
+div#test1{
+ position: fixed;
+ touch-action: none;
+ top: 0;
+ left: 0;
+ width: 100px;
+ height: 100px;
+ background-color: blue;
+}
+
+</style>
+
+<div id="test1">
+</div>
+
+<script>
+promise_test(async t => {
+ let test1 = document.getElementById("test1");
+
+ const events = [];
+ addPointerEventListeners(t, test1, events);
+
+ await new test_driver.Actions()
+ .addPointer("touchPointer1", "touch")
+ .addPointer("touchPointer2", "touch")
+ .pointerMove(0, 0, {origin: test1, sourceName: "touchPointer1"})
+ .pointerMove(10, 0, {origin: test1, sourceName: "touchPointer2"})
+ .pointerDown({sourceName: "touchPointer1"})
+ .pointerDown({sourceName: "touchPointer2"})
+ .pointerMove(0, 10, {origin: test1, sourceName: "touchPointer1"})
+ .pointerMove(10, 10, {origin: test1, sourceName: "touchPointer2"})
+ .pointerUp({sourceName: "touchPointer1"})
+ .pointerUp({sourceName: "touchPointer2"})
+ .send();
+
+ const expected = [{type: "pointerdown", pointerId: 2, clientX: 50, clientY: 50},
+ {type: "pointerdown", pointerId: 3, clientX: 60, clientY: 50},
+ {type: "pointermove", pointerId: 2, clientX: 50, clientY: 60},
+ {type: "pointermove", pointerId: 3, clientX: 60, clientY: 60},
+ {type: "pointerup", pointerId: 2, clientX: 50, clientY: 60},
+ {type: "pointerup", pointerId: 3, clientX: 60, clientY: 60}];
+ assert_equals(events.length, expected.length);
+ for (let i=0; i<expected.length; i++) {
+ eventEquals(events[i], expected[i]);
+ }
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/actions/multiTouchPointsTwoTouchStarts.html b/testing/web-platform/tests/infrastructure/testdriver/actions/multiTouchPointsTwoTouchStarts.html
new file mode 100644
index 0000000000..06f48ebc38
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/actions/multiTouchPointsTwoTouchStarts.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver actions: two touch points with one moving one pause</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<style>
+div#test1{
+ position: fixed;
+ touch-action: none;
+ top: 0;
+ left: 0;
+ width: 100px;
+ height: 100px;
+ background-color: blue;
+}
+
+</style>
+
+<div id="test1">
+</div>
+
+<script>
+let event_type = [];
+let event_id = [];
+
+promise_test(async t => {
+ const test1 = document.getElementById("test1");
+ const handleEvent = e => {
+ event_type.push(e.type);
+ event_id.push(e.pointerId);
+ }
+ test1.addEventListener("pointerdown", handleEvent);
+ test1.addEventListener("pointerup", handleEvent);
+ test1.addEventListener("pointermove", handleEvent);
+
+ let actions = new test_driver.Actions()
+ .addPointer("touchPointer1", "touch")
+ .addPointer("touchPointer2", "touch")
+ .pointerMove(0, 0, {origin: test1, sourceName: "touchPointer1"})
+ .pointerMove(10, 0, {origin: test1, sourceName: "touchPointer2"})
+ .pointerDown({sourceName: "touchPointer1"})
+ .pointerMove(0, 5, {origin: test1, sourceName: "touchPointer1"})
+ .addTick()
+ .pointerDown({sourceName: "touchPointer2"})
+ .addTick()
+ .pointerUp({sourceName: "touchPointer1"})
+ .pointerUp({sourceName: "touchPointer2"});
+
+ await actions.send()
+
+ assert_array_equals(event_type, ["pointerdown", "pointermove", "pointerdown", "pointerup", "pointerup"]);
+ assert_array_equals(event_id, [2, 2, 3, 2, 3]);
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/actions/multiTouchPointsWithPause.html b/testing/web-platform/tests/infrastructure/testdriver/actions/multiTouchPointsWithPause.html
new file mode 100644
index 0000000000..6b89d74c65
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/actions/multiTouchPointsWithPause.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver actions: two touch points with one moving one pause</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="touchEvents.js"></script>
+
+<style>
+div#test1{
+ position: fixed;
+ touch-action: none;
+ top: 0;
+ left: 0;
+ width: 100px;
+ height: 100px;
+ background-color: blue;
+}
+
+</style>
+
+<div id="test1">
+</div>
+
+<script>
+
+promise_test(async t => {
+ const test1 = document.getElementById("test1");
+ const events = [];
+ addPointerEventListeners(t, test1, events);
+ await new test_driver.Actions()
+ .addPointer("touchPointer1", "touch")
+ .addPointer("touchPointer2", "touch")
+ .pointerMove(0, 0, {origin: test1, sourceName: "touchPointer1"})
+ .pointerMove(10, 0, {origin: test1, sourceName: "touchPointer2"})
+ .pointerDown({sourceName: "touchPointer1"})
+ .pointerDown({sourceName: "touchPointer2"})
+ .pause(0, "pointer", {sourceName: "touchPointer1"})
+ .pointerMove(0, 10, {origin: test1, sourceName: "touchPointer2"})
+ .pointerUp({sourceName: "touchPointer1"})
+ .pointerUp({sourceName: "touchPointer2"})
+ .send();
+
+ eventEquals(events[0], {type: "pointerdown", pointerId: 2, clientX: 50, clientY: 50});
+ eventEquals(events[1], {type: "pointerdown", pointerId: 3, clientX: 60, clientY: 50});
+ // Allow one or two pointermove events
+ let index = 3;
+ const moveEvents = [events[2]];
+ if (events[3].type === "pointermove") {
+ index += 1;
+ moveEvents.push(events[3]);
+ }
+ for (const event of moveEvents) {
+ if (event.pointerId === 2) {
+ eventEquals(event, {type: "pointermove", clientX: 50, clientY: 50});
+ } else {
+ eventEquals(event, {type: "pointermove", pointerId: 3, clientX: 50, clientY: 60});
+ }
+ }
+ let remainingEvents = events.slice(index);
+ assert_equals(remainingEvents.length, 2);
+ eventEquals(remainingEvents[0], {type: "pointerup", pointerId: 2, clientX: 50, clientY: 50});
+ eventEquals(remainingEvents[1], {type: "pointerup", pointerId: 3, clientX: 50, clientY: 60});
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/actions/pause.html b/testing/web-platform/tests/infrastructure/testdriver/actions/pause.html
new file mode 100644
index 0000000000..ec33c51102
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/actions/pause.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>TestDriver actions: pause</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<script>
+promise_test(() => {
+ let t0 = performance.now();
+ return new test_driver.Actions()
+ .addTick(1000)
+ .send()
+ .then(() => assert_greater_than(performance.now() - t0, 1000));
+})
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/actions/penPointerEventProperties.html b/testing/web-platform/tests/infrastructure/testdriver/actions/penPointerEventProperties.html
new file mode 100644
index 0000000000..ba6c15f022
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/actions/penPointerEventProperties.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver actions: pointerevent properties of pen type</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<style>
+div#test {
+ position: fixed;
+ touch-action: none;
+ top: 5px;
+ left: 5px;
+ width: 100px;
+ height: 100px;
+ background-color: blue;
+}
+</style>
+
+<div id="test">
+</div>
+
+<script>
+let pointerDownEvent;
+let pointerMoveEvent;
+let receivedPointerDown = false;
+
+async_test(t => {
+ let test = document.getElementById("test");
+ var eventList = ['pointermove', 'pointerdown'];
+ for (eventType of eventList) {
+ test.addEventListener(eventType, e => {
+ if (e.type == 'pointerdown') {
+ receivedPointerDown = true;
+ pointerDownEvent = e;
+ }
+ if (e.type == 'pointermove' && receivedPointerDown)
+ pointerMoveEvent = e;
+ });
+ }
+
+ let div = document.getElementById("test");
+ let actions = new test_driver.Actions()
+ .addPointer("penPointer1", "pen")
+ .pointerMove(0, 0, {origin: test})
+ .pointerDown({pressure:0.36, tiltX:-72, tiltY:9, twist:86})
+ .pointerMove(15, 0, {origin: test})
+ .pointerUp()
+ .send()
+ .then(t.step_func_done(() => {
+ assert_equals(pointerDownEvent.type, "pointerdown");
+ assert_equals(pointerDownEvent.pointerType, "pen");
+ assert_equals(pointerDownEvent.width, 1);
+ assert_equals(pointerDownEvent.height, 1);
+ assert_equals(Math.round(pointerDownEvent.pressure * 100) / 100, 0.36);
+ assert_equals(pointerDownEvent.tiltX, -72);
+ assert_equals(pointerDownEvent.tiltY, 9);
+ assert_equals(pointerDownEvent.twist, 86);
+ assert_equals(pointerMoveEvent.type, "pointermove");
+ assert_equals(pointerMoveEvent.pointerType, "pen");
+ assert_equals(pointerMoveEvent.width, 1);
+ assert_equals(pointerMoveEvent.height, 1);
+ assert_equals(Math.round(pointerMoveEvent.pressure * 100) / 100, 0.5);
+ assert_equals(pointerMoveEvent.tiltX, 0);
+ assert_equals(pointerMoveEvent.tiltY, 0);
+ assert_equals(pointerMoveEvent.twist, 0);
+ })).catch(e => t.step_func(() => assert_unreached("Actions sequence failed " + e)));
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/actions/penPointerEvents.html b/testing/web-platform/tests/infrastructure/testdriver/actions/penPointerEvents.html
new file mode 100644
index 0000000000..7141fb5655
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/actions/penPointerEvents.html
@@ -0,0 +1,159 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver actions: pointerevent properties of pen type</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/pointerevents/pointerevent_support.js"></script>
+
+<style>
+div#test {
+ position: fixed;
+ touch-action: none;
+ top: 5px;
+ left: 5px;
+ width: 100px;
+ height: 100px;
+ background-color: blue;
+}
+</style>
+
+<div id="test">
+</div>
+
+<script>
+let eventList = [];
+
+async_test(t => {
+ let test = document.getElementById("test");
+ [
+ 'pointerover', 'pointerenter', 'pointermove', 'pointerdown', 'pointerup',
+ 'pointerout', 'pointerleave'
+ ].forEach(eventType => {
+ test.addEventListener(eventType, e => {
+ eventList.push(e);
+ });
+ });
+
+ let div = document.getElementById("test");
+ let actions = new test_driver.Actions()
+ .addPointer("penPointer1", "pen")
+ // Force initial position to be outside the test element
+ .pointerMove(0, 0)
+ // Prevent coalescence of move events.
+ .pointerDown()
+ .pointerUp()
+ // Trigger over and enter events.
+ .pointerMove(10, 10)
+ // Toggle of pen-contact state between each move to prevent coalescence of
+ // move events.
+ .pointerDown()
+ .pointerMove(0, 0, {origin: test})
+ .pointerUp()
+ .pointerMove(15, 0, {origin: test})
+ .pointerDown()
+ .pointerMove(30, 0, {origin: test})
+ .pointerUp()
+ .pointerMove(0, 0)
+ .send()
+ .then(t.step_func_done(() => {
+ const expectedEvents = [
+ {
+ type: 'pointerover',
+ button: ButtonChange.NONE,
+ buttons: ButtonsBitfield.NONE
+ },
+ {
+ type: 'pointerenter',
+ button: ButtonChange.NONE,
+ buttons: ButtonsBitfield.NONE
+ },
+ { type: 'pointermove',
+ button: ButtonChange.NONE,
+ buttons: ButtonsBitfield.NONE,
+ clientX: 10,
+ clientY: 10
+ },
+ {
+ type: 'pointerdown',
+ button: ButtonChange.PEN_CONTACT,
+ buttons: ButtonsBitfield.PEN_CONTACT,
+ clientX: 10,
+ clientY: 10
+ },
+ {
+ type: 'pointermove',
+ button: ButtonChange.NONE,
+ buttons: ButtonsBitfield.PEN_CONTACT,
+ clientX: 55,
+ clientY: 55
+ },
+ {
+ type: 'pointerup',
+ button: ButtonChange.PEN_CONTACT,
+ buttons: ButtonsBitfield.NONE,
+ clientX: 55,
+ clientY: 55
+ },
+ {
+ type: 'pointermove',
+ button: ButtonChange.NONE,
+ buttons: ButtonsBitfield.NONE,
+ clientX: 70,
+ clientY: 55
+ },
+ {
+ type: 'pointerdown',
+ button: ButtonChange.PEN_CONTACT,
+ buttons: ButtonsBitfield.PEN_CONTACT,
+ clientX: 70,
+ clientY: 55
+ },
+ {
+ type: 'pointermove',
+ button: ButtonChange.NONE,
+ buttons: ButtonsBitfield.PEN_CONTACT,
+ clientX: 85,
+ clientY: 55
+ },
+ {
+ type: 'pointerup',
+ button: ButtonChange.PEN_CONTACT,
+ buttons: ButtonsBitfield.NONE,
+ clientX: 85,
+ clientY: 55
+ },
+ {
+ type: 'pointerout',
+ button: ButtonChange.NONE,
+ buttons: ButtonsBitfield.NONE,
+ clientX: 0,
+ clientY: 0
+ },
+ {
+ type: 'pointerleave',
+ button: ButtonChange.NONE,
+ buttons: ButtonsBitfield.NONE,
+ clientX: 0,
+ clientY: 0
+ },
+ ];
+
+ for (let i = 0; i < expectedEvents.length; i++) {
+ const expectedValue = expectedEvents[i];
+ const actualValue = eventList[i];
+ assert_true(!!actualValue, `Missing $[i}-th event`);
+ assert_equals(actualValue.pointerType, 'pen', 'Unexpected pointer type');
+ for (key in expectedValue) {
+ assert_equals(actualValue[key], expectedValue[key],
+ `Mismatch in event[${i}].${key}`);
+ }
+ }
+
+ assert_equals(eventList.length, expectedEvents.length,
+ 'Unexpected number of events');
+ })).catch(e => t.step_func(() => assert_unreached("Actions sequence failed " + e)));
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/actions/textEditCommands.html b/testing/web-platform/tests/infrastructure/testdriver/actions/textEditCommands.html
new file mode 100644
index 0000000000..0bc533ecb0
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/actions/textEditCommands.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver actions: text edit commands</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<style>
+div { padding:0px; margin: 0px; }
+</style>
+<body>
+ <div>
+ <input type="text" id="text1" value="Hello World" />
+ <input type="text" id="text2">
+ </div>
+</body>
+<script>
+async_test(t => {
+ let text1 = document.getElementById("text1");
+ let text2 = document.getElementById("text2");
+ text1.addEventListener("click", function() {
+ let text1 = document.getElementById("text1");
+ text1.value="new text";
+ });
+
+ const ctrl_key = "\uE009";
+ const cmd_key = "\uE03D";
+ let edit_command_key = ctrl_key;
+ if(navigator.platform.includes('Mac'))
+ edit_command_key = cmd_key;
+
+ let actions = new test_driver.Actions()
+ .pointerMove(0, 0, {origin: text1})
+ .pointerDown()
+ .pointerUp()
+ .addTick()
+ .keyDown(edit_command_key)
+ .keyDown("a")
+ .keyUp("a")
+ .keyDown("x")
+ .keyUp("x")
+ .keyUp(edit_command_key)
+ .addTick()
+ .pointerMove(0, 0, {origin: text2})
+ .pointerDown()
+ .pointerUp()
+ .keyDown(edit_command_key)
+ .keyDown("v")
+ .keyUp("v")
+ .keyUp(edit_command_key);
+
+ actions.send()
+ .then(t.step_func_done(() => {
+ assert_equals(text1.value, "");
+ assert_equals(text2.value, "new text");
+ }))
+ .catch(e => t.step_func(() => assert_unreached("Actions sequence failed " + e)));
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/actions/touchEvents.js b/testing/web-platform/tests/infrastructure/testdriver/actions/touchEvents.js
new file mode 100644
index 0000000000..c1213b6693
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/actions/touchEvents.js
@@ -0,0 +1,11 @@
+function eventEquals(e, expected) {
+ for (const prop of Object.keys(expected)) {
+ assert_equals(e[prop], expected[prop], `Event ${e.type} pointerId ${e.pointerId} property ${prop}`);
+ }
+}
+
+function addPointerEventListeners(test, target, events) {
+ for (const event of ["pointerup", "pointerdown", "pointermove"]) {
+ target.addEventListener(event, test.step_func(e => events.push(e)));
+ }
+}
diff --git a/testing/web-platform/tests/infrastructure/testdriver/actions/touchPointerEventProperties.html b/testing/web-platform/tests/infrastructure/testdriver/actions/touchPointerEventProperties.html
new file mode 100644
index 0000000000..085889949e
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/actions/touchPointerEventProperties.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver actions: pointerevent properties of touch type</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<style>
+div#test {
+ position: fixed;
+ touch-action: none;
+ top: 5px;
+ left: 5px;
+ width: 100px;
+ height: 100px;
+ background-color: blue;
+}
+</style>
+
+<div id="test">
+</div>
+
+<script>
+let pointerDownEvent;
+let pointerMoveEvent;
+let receivedPointerDown = false;
+
+async_test(t => {
+ let test = document.getElementById("test");
+ var eventList = ['pointermove', 'pointerdown'];
+ for (eventType of eventList) {
+ test.addEventListener(eventType, e => {
+ if (e.type == 'pointerdown') {
+ receivedPointerDown = true;
+ pointerDownEvent = e;
+ }
+ if (e.type == 'pointermove' && receivedPointerDown)
+ pointerMoveEvent = e;
+ });
+ }
+
+ let div = document.getElementById("test");
+ let actions = new test_driver.Actions()
+ .addPointer("touchPointer1", "touch")
+ .pointerMove(0, 0, {origin: test})
+ .pointerDown({width:23, height:31, pressure:0.78})
+ .pointerMove(15, 0, {origin: test, width:39, height:35, pressure:0.91})
+ .pointerUp()
+ .send()
+ .then(t.step_func_done(() => {
+ assert_equals(pointerDownEvent.type, "pointerdown");
+ assert_equals(pointerDownEvent.pointerType, "touch");
+ assert_equals(pointerDownEvent.width, 23);
+ assert_equals(pointerDownEvent.height, 31);
+ assert_equals(Math.round(pointerDownEvent.pressure * 100) / 100, 0.78);
+ assert_equals(pointerDownEvent.tiltX, 0);
+ assert_equals(pointerDownEvent.tiltY, 0);
+ assert_equals(pointerDownEvent.twist, 0);
+ assert_equals(pointerMoveEvent.type, "pointermove");
+ assert_equals(pointerMoveEvent.pointerType, "touch");
+ assert_equals(pointerMoveEvent.width, 39);
+ assert_equals(pointerMoveEvent.height, 35);
+ assert_equals(Math.round(pointerMoveEvent.pressure * 100) / 100, 0.91);
+ assert_equals(pointerMoveEvent.tiltX, 0);
+ assert_equals(pointerMoveEvent.tiltY, 0);
+ assert_equals(pointerMoveEvent.twist, 0);
+ })).catch(e => t.step_func(() => assert_unreached("Actions sequence failed " + e)));
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/actions/wheelScroll.html b/testing/web-platform/tests/infrastructure/testdriver/actions/wheelScroll.html
new file mode 100644
index 0000000000..0447c17ef9
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/actions/wheelScroll.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver actions: wheel scroll</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<style>
+#container {
+ width: 200px;
+ height: 200px;
+ overflow: scroll;
+}
+
+#content {
+ width: 600px;
+ height: 1000px;
+ background-color: blue;
+}
+
+</style>
+
+<div id="container">
+ <div id="content"></div>
+</div>
+
+<script>
+let event_type = [];
+let event_id = [];
+
+promise_test(async t => {
+ let container = document.getElementById("container");
+ container.addEventListener("wheel",
+ e => {event_type.push(e.type);});
+
+ let actions = new test_driver.Actions()
+ .scroll(0, 0, 0, 50, {origin: container});
+
+ await actions.send()
+ assert_array_equals(event_type, ["wheel"]);
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/bless.html b/testing/web-platform/tests/infrastructure/testdriver/bless.html
new file mode 100644
index 0000000000..12257df01b
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/bless.html
@@ -0,0 +1,114 @@
+<!DOCTYPE html>
+<head>
+ <meta charset="utf-8">
+ <title>TestDriver bless method</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <script>
+promise_test(() => {
+ return test_driver.bless('empty', () => {});
+}, 'functions in the absence of a `body` element');
+ </script>
+</head>
+<body>
+<script>
+// At the time of this writing, the only standard requirement for user
+// activation concerns the interaction between iframe elements and their parent
+// browsing contexts [1]. Because testdriver.js currently cannot operate within
+// an iframe, the standard requirement cannot be used to verify the correctness
+// of the `bless` method. Instead, rely on the optional behavior of early exit
+// and rejecting in `video.play()` if the media is not "allowed to play". [2]
+// Browsers which don't implement this will pass this test spuriously.
+//
+// [1] https://html.spec.whatwg.org/multipage/origin.html#attr-iframe-sandbox-allow-top-navigation-by-user-activation
+// [2] https://html.spec.whatwg.org/multipage/media.html#allowed-to-play
+promise_test(t => {
+ const video = document.createElement('video');
+ document.body.appendChild(video);
+ t.add_cleanup(() => video.remove());
+ return test_driver.bless('start video playback', () => {
+ // `paused` changes before `play()` returns when "allowed to play", so the
+ // promise, if any, is ignored.
+ assert_true(video.paused);
+ const playPromise = video.play();
+ assert_false(video.paused);
+ if (playPromise) {
+ playPromise.catch(() => {});
+ }
+ });
+}, 'user activation');
+
+promise_test(() => {
+ return test_driver.bless('demonstrates return value without action')
+ .then((value) => {
+ assert_equals(value, null);
+ });
+}, 'no action function provided');
+
+promise_test(() => {
+ const expectedValue = {};
+
+ return test_driver.bless('demonstrate a synchronous return value', () => {
+ return expectedValue;
+ }).then((actualValue) => {
+ assert_equals(
+ actualValue,
+ expectedValue,
+ 'the promise should be fulfilled with the returned value'
+ );
+ });
+
+}, 'synchronous return value');
+
+promise_test(() => {
+ const expectedError = new Error();
+
+ return test_driver.bless('demonstrates a synchronous error', () => {
+ throw expectedError;
+ })
+ .then(() => {
+ assert_unreached('the promise should be rejected');
+ }, (actualError) => {
+ assert_equals(
+ actualError,
+ expectedError,
+ 'the promise should be rejected with the thrown value'
+ );
+ });
+}, 'synchronous error');
+
+promise_test(() => {
+ const expectedValue = {};
+
+ return test_driver.bless('demonstrate an asynchronous return value', () => {
+ return Promise.resolve(expectedValue);
+ }).then((actualValue) => {
+ assert_equals(
+ actualValue,
+ expectedValue,
+ 'the promise should be fulfilled with the fulfillment value'
+ );
+ });
+
+}, 'asynchronous return value');
+
+promise_test(() => {
+ const expectedError = new Error();
+
+ return test_driver.bless('demonstrates an asynchronous error', () => {
+ return Promise.reject(expectedError);
+ })
+ .then(() => {
+ assert_unreached('the promise should be rejected');
+ }, (actualError) => {
+ assert_equals(
+ actualError,
+ expectedError,
+ 'the promise should be rejected with the rejected value'
+ );
+ });
+}, 'asynchronous error');
+</script>
+</body>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/click-multiple.html b/testing/web-platform/tests/infrastructure/testdriver/click-multiple.html
new file mode 100644
index 0000000000..ed834c5571
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/click-multiple.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver multiple consecutive clicks</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<button type="button" id="button1">Button 1</button>
+<button type="button" id="button2">Button 2</button>
+<button type="button" id="button3">Button 3</button>
+
+<script>
+buttons = [
+ document.getElementById("button1"),
+ document.getElementById("button2"),
+ document.getElementById("button3"),
+];
+
+promise_test(async t => {
+ clicked = [false, false, false];
+ for (let i = 0; i < buttons.length; i++) {
+ buttons[i].addEventListener("click", () => {
+ clicked[i] = true;
+ });
+ }
+
+ await Promise.all([
+ test_driver.click(buttons[0]),
+ test_driver.click(buttons[1]),
+ test_driver.click(buttons[2]),
+ ]);
+
+ assert_true(clicked[0]);
+ assert_true(clicked[1]);
+ assert_true(clicked[2]);
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/click.html b/testing/web-platform/tests/infrastructure/testdriver/click.html
new file mode 100644
index 0000000000..37721ad9ef
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/click.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver click method</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<button type="button" id="button">Button</button>
+
+<script>
+async_test(t => {
+ let button = document.getElementById("button");
+ test_driver
+ .click(button)
+ .then(() => t.done())
+ .catch(t.unreached_func("click failed"));
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/click_child.html b/testing/web-platform/tests/infrastructure/testdriver/click_child.html
new file mode 100644
index 0000000000..5899841c4c
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/click_child.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<button id="button">Button</button>
+<div id="log">FAIL</div>
+<script>
+document.getElementById("button").addEventListener("click", () =>
+ document.getElementById("log").textContent = "PASS");
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/click_child_crossorigin.html b/testing/web-platform/tests/infrastructure/testdriver/click_child_crossorigin.html
new file mode 100644
index 0000000000..6a8c6840a2
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/click_child_crossorigin.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<button id="button">Button</button>
+<div id="log">FAIL</div>
+<script>
+let button = document.getElementById("button");
+button.addEventListener("click", () =>
+ document.getElementById("log").textContent = "PASS");
+
+addEventListener("load", () => {
+ test_driver.set_test_context(parent.opener);
+ test_driver.click(button)
+ .then(() => test_driver.message_test("PASS", "*"))
+ .catch(() => test_driver.message_test("FAIL", "*"));
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/click_child_testdriver.html b/testing/web-platform/tests/infrastructure/testdriver/click_child_testdriver.html
new file mode 100644
index 0000000000..2c26a963f4
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/click_child_testdriver.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<button id="button">Button</button>
+<div id="log">FAIL</div>
+<script>
+let button = document.getElementById("button");
+button.addEventListener("click", () =>
+ document.getElementById("log").textContent = "PASS");
+
+addEventListener("load", () => {
+ test_driver.set_test_context(parent);
+ test_driver.click(button)
+ .then(() => test_driver.message_test("PASS", "*"))
+ .catch(() => test_driver.message_test("FAIL", "*"));
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/click_iframe.html b/testing/web-platform/tests/infrastructure/testdriver/click_iframe.html
new file mode 100644
index 0000000000..167a91afcf
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/click_iframe.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver click on a document in an iframe</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<iframe src="click_child.html"></iframe>
+
+<script>
+setup({single_test: true});
+addEventListener("load", () => {
+ let child = frames[0];
+ let button = child.document.getElementById("button");
+ test_driver
+ .click(button)
+ .then(() => {
+ assert_equals(child.document.getElementById("log").textContent, "PASS");
+ done();
+ })
+ .catch(() => assert_unreached("click failed"));
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/click_iframe_crossorigin.sub.html b/testing/web-platform/tests/infrastructure/testdriver/click_iframe_crossorigin.sub.html
new file mode 100644
index 0000000000..df2b4477ca
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/click_iframe_crossorigin.sub.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver click on a document in an iframe</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<script>
+setup({single_test: true});
+addEventListener("message", (msg) => {
+ if (msg.data === "PASS") {
+ done();
+ } else if (msg.data === "FAIL") {
+ assert_unreached("click failed")
+ }
+});
+</script>
+
+<!-- Make sure we add the event listener before loading the iframe, to avoid
+potentially missing messages from the child. -->
+<iframe src="https://{{host}}:{{ports[https][1]}}/infrastructure/testdriver/click_child_testdriver.html"></iframe>
+
diff --git a/testing/web-platform/tests/infrastructure/testdriver/click_nested.html b/testing/web-platform/tests/infrastructure/testdriver/click_nested.html
new file mode 100644
index 0000000000..378b9e8c0f
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/click_nested.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver click method with multiple windows and nested iframe</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<iframe src="about:blank"></iframe>
+
+<script>
+setup({single_test: true});
+
+window.open("about:blank")
+var child = window.open("click_outer_child.html")
+window.open("about:blank")
+
+addEventListener("load",() => {
+ child.addEventListener("load", () => {
+ let doc = child.frames[2].document;
+ let button = doc.getElementById("button");
+ test_driver
+ .click(button)
+ .then(() => {
+ assert_equals(doc.getElementById("log").textContent, "PASS");
+ done();
+ })
+ .catch(() => assert_unreached("click failed"));
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/click_nested_crossorigin.sub.html b/testing/web-platform/tests/infrastructure/testdriver/click_nested_crossorigin.sub.html
new file mode 100644
index 0000000000..af90951df1
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/click_nested_crossorigin.sub.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver click method with multiple windows and nested iframe</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<iframe src="about:blank"></iframe>
+
+<script>
+setup({single_test: true});
+
+window.open("about:blank")
+var child = window.open("https://{{host}}:{{ports[https][0]}}/infrastructure/testdriver/click_outer_child.sub.html")
+window.open("about:blank")
+
+addEventListener("message", (msg) => {
+ if (msg.data === "PASS") {
+ done();
+ } else if (msg.data === "FAIL") {
+ assert_unreached("click failed")
+ }
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/click_outer_child.html b/testing/web-platform/tests/infrastructure/testdriver/click_outer_child.html
new file mode 100644
index 0000000000..ae4944635f
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/click_outer_child.html
@@ -0,0 +1,4 @@
+<!doctype html>
+<iframe src="about:blank"></iframe>
+<iframe src="about:blank"></iframe>
+<iframe src="click_child.html"></iframe>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/click_outer_child.sub.html b/testing/web-platform/tests/infrastructure/testdriver/click_outer_child.sub.html
new file mode 100644
index 0000000000..8e72223f91
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/click_outer_child.sub.html
@@ -0,0 +1,4 @@
+<!doctype html>
+<iframe src="about:blank"></iframe>
+<iframe src="about:blank"></iframe>
+<iframe src="https://{{host}}:{{ports[https][1]}}/infrastructure/testdriver/click_child_crossorigin.html"></iframe>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/click_window.html b/testing/web-platform/tests/infrastructure/testdriver/click_window.html
new file mode 100644
index 0000000000..614a92478e
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/click_window.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver click method in window</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<script>
+setup({single_test: true});
+addEventListener("load", () => {
+ let child = window.open("click_child.html");
+ child.addEventListener("load", () => {
+ let button = child.document.getElementById("button");
+ test_driver
+ .click(button)
+ .then(() => {
+ assert_equals(child.document.getElementById("log").textContent, "PASS");
+ done();
+ })
+ .catch(() => assert_unreached("click failed"));
+ });
+})
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/delete_all_cookies.html b/testing/web-platform/tests/infrastructure/testdriver/delete_all_cookies.html
new file mode 100644
index 0000000000..8d7b82ab04
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/delete_all_cookies.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver delete_all_cookies method</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script>
+promise_test(async t => {
+ document.cookie = "test1=1";
+ document.cookie = "test2=2; path=/";
+ document.cookie = "test3=3; path=/cookies/resources";
+
+ return test_driver.delete_all_cookies().then(() => {
+ assert_true(document.cookie === "");
+ });
+}, "DOM-set cookies get deleted");
+
+promise_test(async t => {
+ const cookies = ["test1=1", "test2=2; path=/", "test3=3; path=/cookies/resources", "test4=4; HttpOnly"];
+ for (const cookie of cookies) {
+ const encoded = encodeURIComponent(JSON.stringify(cookie));
+ await fetch(`/cookies/resources/cookie.py?set=${encoded}`)
+ }
+
+ return test_driver.delete_all_cookies().then(() => {
+ assert_true(document.cookie === "");
+ });
+}, "HTTP-set cookies get deleted");
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/file_upload.py b/testing/web-platform/tests/infrastructure/testdriver/file_upload.py
new file mode 100644
index 0000000000..9c4dd75438
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/file_upload.py
@@ -0,0 +1,2 @@
+def main(request, response):
+ return b"PASS" if request.POST[b"file_input"].file.read() == b"File to upload\n" else b"FAIL"
diff --git a/testing/web-platform/tests/infrastructure/testdriver/file_upload.sub.html b/testing/web-platform/tests/infrastructure/testdriver/file_upload.sub.html
new file mode 100644
index 0000000000..0490e89c42
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/file_upload.sub.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<meta charset=utf8>
+<title>File upload using testdriver</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<form id="form">
+ <input id="file_input" name="file_input" type="file">
+</form>
+<script>
+promise_test(() => {
+ let form = document.getElementById("form");
+ let input = document.getElementById("file_input");
+ return test_driver
+ .send_keys(input, String.raw`{{fs_path(file_upload_data.txt)}}`)
+ .then(() =>
+ fetch("file_upload.py",
+ {method: "POST",
+ body: new FormData(form)}))
+ .then(response => response.text())
+ .then(data => {
+ assert_equals(data, "PASS");
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/file_upload_data.txt b/testing/web-platform/tests/infrastructure/testdriver/file_upload_data.txt
new file mode 100644
index 0000000000..097d2a3a3f
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/file_upload_data.txt
@@ -0,0 +1 @@
+File to upload
diff --git a/testing/web-platform/tests/infrastructure/testdriver/generate_test_report.html b/testing/web-platform/tests/infrastructure/testdriver/generate_test_report.html
new file mode 100644
index 0000000000..168c9e9956
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/generate_test_report.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver generate_test_report method</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<script>
+async_test(t => {
+ test_driver
+ .generate_test_report("Test message.")
+ .then(() => t.done())
+ .catch(t.unreached_func("generate_test_report failed"));
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/get_all_cookies.sub.html b/testing/web-platform/tests/infrastructure/testdriver/get_all_cookies.sub.html
new file mode 100644
index 0000000000..84f93af0a3
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/get_all_cookies.sub.html
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver get_all_cookies method in HTTP</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script>
+promise_test(async t => {
+ t.add_cleanup(test_driver.delete_all_cookies);
+ const kTenDaysFromNow = new Date(Date.now() + 10 * 24 * 60 * 60 * 1000);
+ document.cookie = "test0=0";
+ document.cookie = `test1=1; Expires=${kTenDaysFromNow.toUTCString()}`;
+ document.cookie = "test2=2; Path=/";
+ // document.cookie = "test3=3; HttpOnly"; This is set in the headers file.
+ document.cookie = "test4=4; Secure";
+ document.cookie = "test5=5; SameSite=Strict";
+ document.cookie = "test6=6; SameSite=None; Secure";
+ document.cookie = "test7=7; SameSite=Lax";
+ const cookies = await test_driver.get_all_cookies();
+ assert_equals(cookies.length, 6);
+ let cookieMap = new Map();
+ for (const cookie of cookies) {
+ cookieMap.set(cookie["name"], cookie);
+ }
+
+ // test0
+ assert_equals(cookieMap.get("test0")["name"], "test0");
+ assert_equals(cookieMap.get("test0")["value"], "0");
+ assert_equals(cookieMap.get("test0")["path"], "/infrastructure/testdriver");
+ assert_equals(cookieMap.get("test0")["domain"], "{{host}}");
+ assert_equals(cookieMap.get("test0")["secure"], false);
+ assert_equals(cookieMap.get("test0")["httpOnly"], false);
+ assert_equals(cookieMap.get("test0")["expiry"], undefined);
+ // The 'default lax' behavior varies by browser.
+ // assert_equals(cookieMap.get("test0")["sameSite"], "Lax");
+
+ // test1 [Expires in 10 days]
+ assert_equals(cookieMap.get("test1")["name"], "test1");
+ assert_equals(cookieMap.get("test1")["value"], "1");
+ assert_equals(cookieMap.get("test1")["path"], "/infrastructure/testdriver");
+ assert_equals(cookieMap.get("test1")["domain"], "{{host}}");
+ assert_equals(cookieMap.get("test1")["secure"], false);
+ assert_equals(cookieMap.get("test1")["httpOnly"], false);
+ assert_equals(cookieMap.get("test1")["expiry"], Math.floor(kTenDaysFromNow.getTime()/1000));
+ // The 'default lax' behavior varies by browser.
+ // assert_equals(cookieMap.get("test0")["sameSite"], "Lax");
+
+ // test2 [Path /]
+ assert_equals(cookieMap.get("test2")["name"], "test2");
+ assert_equals(cookieMap.get("test2")["value"], "2");
+ assert_equals(cookieMap.get("test2")["path"], "/");
+ assert_equals(cookieMap.get("test2")["domain"], "{{host}}");
+ assert_equals(cookieMap.get("test2")["secure"], false);
+ assert_equals(cookieMap.get("test2")["httpOnly"], false);
+ assert_equals(cookieMap.get("test2")["expiry"], undefined);
+ // The 'default lax' behavior varies by browser.
+ // assert_equals(cookieMap.get("test0")["sameSite"], "Lax");
+
+ // test3 [HttpOnly]
+ assert_equals(cookieMap.get("test3")["name"], "test3");
+ assert_equals(cookieMap.get("test3")["value"], "3");
+ assert_equals(cookieMap.get("test3")["path"], "/infrastructure/testdriver");
+ assert_equals(cookieMap.get("test3")["domain"], "{{host}}");
+ assert_equals(cookieMap.get("test3")["secure"], false);
+ assert_equals(cookieMap.get("test3")["httpOnly"], true);
+ assert_equals(cookieMap.get("test3")["expiry"], undefined);
+ // The 'default lax' behavior varies by browser.
+ // assert_equals(cookieMap.get("test0")["sameSite"], "Lax");
+
+ // test4 [Secure] Omitted
+
+ // test5 [SameSite Strict]
+ assert_equals(cookieMap.get("test5")["name"], "test5");
+ assert_equals(cookieMap.get("test5")["value"], "5");
+ assert_equals(cookieMap.get("test5")["path"], "/infrastructure/testdriver");
+ assert_equals(cookieMap.get("test5")["domain"], "{{host}}");
+ assert_equals(cookieMap.get("test5")["secure"], false);
+ assert_equals(cookieMap.get("test5")["httpOnly"], false);
+ assert_equals(cookieMap.get("test5")["expiry"], undefined);
+ assert_equals(cookieMap.get("test5")["sameSite"], "Strict");
+
+ // test6 [SameSite None] Omitted
+
+ // test7 [SameSite Lax]
+ assert_equals(cookieMap.get("test7")["name"], "test7");
+ assert_equals(cookieMap.get("test7")["value"], "7");
+ assert_equals(cookieMap.get("test7")["path"], "/infrastructure/testdriver");
+ assert_equals(cookieMap.get("test7")["domain"], "{{host}}");
+ assert_equals(cookieMap.get("test7")["secure"], false);
+ assert_equals(cookieMap.get("test7")["httpOnly"], false);
+ assert_equals(cookieMap.get("test7")["expiry"], undefined);
+ assert_equals(cookieMap.get("test7")["sameSite"], "Lax");
+}, "Get all HTTP cookies");
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/get_all_cookies.sub.html.headers b/testing/web-platform/tests/infrastructure/testdriver/get_all_cookies.sub.html.headers
new file mode 100644
index 0000000000..3dc39a5673
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/get_all_cookies.sub.html.headers
@@ -0,0 +1 @@
+Set-Cookie: test3=3; HttpOnly
diff --git a/testing/web-platform/tests/infrastructure/testdriver/get_all_cookies.sub.https.html b/testing/web-platform/tests/infrastructure/testdriver/get_all_cookies.sub.https.html
new file mode 100644
index 0000000000..e94167133b
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/get_all_cookies.sub.https.html
@@ -0,0 +1,112 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver get_all_cookies method in HTTPS</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script>
+promise_test(async t => {
+ t.add_cleanup(test_driver.delete_all_cookies);
+ const kTenDaysFromNow = new Date(Date.now() + 10 * 24 * 60 * 60 * 1000);
+ document.cookie = "test0=0";
+ document.cookie = `test1=1; Expires=${kTenDaysFromNow.toUTCString()}`;
+ document.cookie = "test2=2; Path=/";
+ // document.cookie = "test3=3; HttpOnly"; This is set in the headers file.
+ document.cookie = "test4=4; Secure";
+ document.cookie = "test5=5; SameSite=Strict";
+ document.cookie = "test6=6; SameSite=None; Secure";
+ document.cookie = "test7=7; SameSite=Lax";
+ const cookies = await test_driver.get_all_cookies();
+ assert_equals(cookies.length, 8);
+ let cookieMap = new Map();
+ for (const cookie of cookies) {
+ cookieMap.set(cookie["name"], cookie);
+ }
+
+ // test0
+ assert_equals(cookieMap.get("test0")["name"], "test0");
+ assert_equals(cookieMap.get("test0")["value"], "0");
+ assert_equals(cookieMap.get("test0")["path"], "/infrastructure/testdriver");
+ assert_equals(cookieMap.get("test0")["domain"], "{{host}}");
+ assert_equals(cookieMap.get("test0")["secure"], false);
+ assert_equals(cookieMap.get("test0")["httpOnly"], false);
+ assert_equals(cookieMap.get("test0")["expiry"], undefined);
+ // The 'default lax' behavior varies by browser.
+ // assert_equals(cookieMap.get("test0")["sameSite"], "Lax");
+
+ // test1 [Expires in 10 days]
+ assert_equals(cookieMap.get("test1")["name"], "test1");
+ assert_equals(cookieMap.get("test1")["value"], "1");
+ assert_equals(cookieMap.get("test1")["path"], "/infrastructure/testdriver");
+ assert_equals(cookieMap.get("test1")["domain"], "{{host}}");
+ assert_equals(cookieMap.get("test1")["secure"], false);
+ assert_equals(cookieMap.get("test1")["httpOnly"], false);
+ assert_equals(cookieMap.get("test1")["expiry"], Math.floor(kTenDaysFromNow.getTime()/1000));
+ // The 'default lax' behavior varies by browser.
+ // assert_equals(cookieMap.get("test0")["sameSite"], "Lax");
+
+ // test2 [Path /]
+ assert_equals(cookieMap.get("test2")["name"], "test2");
+ assert_equals(cookieMap.get("test2")["value"], "2");
+ assert_equals(cookieMap.get("test2")["path"], "/");
+ assert_equals(cookieMap.get("test2")["domain"], "{{host}}");
+ assert_equals(cookieMap.get("test2")["secure"], false);
+ assert_equals(cookieMap.get("test2")["httpOnly"], false);
+ assert_equals(cookieMap.get("test2")["expiry"], undefined);
+ // The 'default lax' behavior varies by browser.
+ // assert_equals(cookieMap.get("test0")["sameSite"], "Lax");
+
+ // test3 [HttpOnly]
+ assert_equals(cookieMap.get("test3")["name"], "test3");
+ assert_equals(cookieMap.get("test3")["value"], "3");
+ assert_equals(cookieMap.get("test3")["path"], "/infrastructure/testdriver");
+ assert_equals(cookieMap.get("test3")["domain"], "{{host}}");
+ assert_equals(cookieMap.get("test3")["secure"], false);
+ assert_equals(cookieMap.get("test3")["httpOnly"], true);
+ assert_equals(cookieMap.get("test3")["expiry"], undefined);
+ // The 'default lax' behavior varies by browser.
+ // assert_equals(cookieMap.get("test0")["sameSite"], "Lax");
+
+ // test4 [Secure]
+ assert_equals(cookieMap.get("test4")["name"], "test4");
+ assert_equals(cookieMap.get("test4")["value"], "4");
+ assert_equals(cookieMap.get("test4")["path"], "/infrastructure/testdriver");
+ assert_equals(cookieMap.get("test4")["domain"], "{{host}}");
+ assert_equals(cookieMap.get("test4")["secure"], true);
+ assert_equals(cookieMap.get("test4")["httpOnly"], false);
+ assert_equals(cookieMap.get("test4")["expiry"], undefined);
+ // The 'default lax' behavior varies by browser.
+ // assert_equals(cookieMap.get("test0")["sameSite"], "Lax");
+
+ // test5 [SameSite Strict]
+ assert_equals(cookieMap.get("test5")["name"], "test5");
+ assert_equals(cookieMap.get("test5")["value"], "5");
+ assert_equals(cookieMap.get("test5")["path"], "/infrastructure/testdriver");
+ assert_equals(cookieMap.get("test5")["domain"], "{{host}}");
+ assert_equals(cookieMap.get("test5")["secure"], false);
+ assert_equals(cookieMap.get("test5")["httpOnly"], false);
+ assert_equals(cookieMap.get("test5")["expiry"], undefined);
+ assert_equals(cookieMap.get("test5")["sameSite"], "Strict");
+
+ // test6 [SameSite None]
+ assert_equals(cookieMap.get("test6")["name"], "test6");
+ assert_equals(cookieMap.get("test6")["value"], "6");
+ assert_equals(cookieMap.get("test6")["path"], "/infrastructure/testdriver");
+ assert_equals(cookieMap.get("test6")["domain"], "{{host}}");
+ assert_equals(cookieMap.get("test6")["secure"], true);
+ assert_equals(cookieMap.get("test6")["httpOnly"], false);
+ assert_equals(cookieMap.get("test6")["expiry"], undefined);
+ assert_equals(cookieMap.get("test6")["sameSite"], "None");
+
+ // test7 [SameSite Lax]
+ assert_equals(cookieMap.get("test7")["name"], "test7");
+ assert_equals(cookieMap.get("test7")["value"], "7");
+ assert_equals(cookieMap.get("test7")["path"], "/infrastructure/testdriver");
+ assert_equals(cookieMap.get("test7")["domain"], "{{host}}");
+ assert_equals(cookieMap.get("test7")["secure"], false);
+ assert_equals(cookieMap.get("test7")["httpOnly"], false);
+ assert_equals(cookieMap.get("test7")["expiry"], undefined);
+ assert_equals(cookieMap.get("test7")["sameSite"], "Lax");
+}, "Get all HTTPS cookies");
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/get_all_cookies.sub.https.html.headers b/testing/web-platform/tests/infrastructure/testdriver/get_all_cookies.sub.https.html.headers
new file mode 100644
index 0000000000..3dc39a5673
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/get_all_cookies.sub.https.html.headers
@@ -0,0 +1 @@
+Set-Cookie: test3=3; HttpOnly
diff --git a/testing/web-platform/tests/infrastructure/testdriver/get_named_cookie.sub.html b/testing/web-platform/tests/infrastructure/testdriver/get_named_cookie.sub.html
new file mode 100644
index 0000000000..28950e2536
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/get_named_cookie.sub.html
@@ -0,0 +1,105 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver get_named_cookie method HTTP</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script>
+promise_test(async t => {
+ t.add_cleanup(test_driver.delete_all_cookies);
+ const kTenDaysFromNow = new Date(Date.now() + 10 * 24 * 60 * 60 * 1000);
+ document.cookie = "test0=0";
+ document.cookie = `test1=1; Expires=${kTenDaysFromNow.toUTCString()}`;
+ document.cookie = "test2=2; Path=/";
+ // document.cookie = "test3=3; HttpOnly"; This is set in the headers file.
+ document.cookie = "test4=4; Secure";
+ document.cookie = "test5=5; SameSite=Strict";
+ document.cookie = "test6=6; SameSite=None; Secure";
+ document.cookie = "test7=7; SameSite=Lax";
+
+ // test0
+ let cookie = await test_driver.get_named_cookie("test0");
+ assert_equals(cookie["name"], "test0");
+ assert_equals(cookie["value"], "0");
+ assert_equals(cookie["path"], "/infrastructure/testdriver");
+ assert_equals(cookie["domain"], "{{host}}");
+ assert_equals(cookie["secure"], false);
+ assert_equals(cookie["httpOnly"], false);
+ assert_equals(cookie["expiry"], undefined);
+ // The 'default lax' behavior varies by browser.
+ // assert_equals(cookie["sameSite"], "Lax");
+
+ // test1 [Expires in 10 days]
+ cookie = await test_driver.get_named_cookie("test1");
+ assert_equals(cookie["name"], "test1");
+ assert_equals(cookie["value"], "1");
+ assert_equals(cookie["path"], "/infrastructure/testdriver");
+ assert_equals(cookie["domain"], "{{host}}");
+ assert_equals(cookie["secure"], false);
+ assert_equals(cookie["httpOnly"], false);
+ assert_equals(cookie["expiry"], Math.floor(kTenDaysFromNow.getTime()/1000));
+ // The 'default lax' behavior varies by browser.
+ // assert_equals(cookie["sameSite"], "Lax");
+
+ // test2 [Path /]
+ cookie = await test_driver.get_named_cookie("test2");
+ assert_equals(cookie["name"], "test2");
+ assert_equals(cookie["value"], "2");
+ assert_equals(cookie["path"], "/");
+ assert_equals(cookie["domain"], "{{host}}");
+ assert_equals(cookie["secure"], false);
+ assert_equals(cookie["httpOnly"], false);
+ assert_equals(cookie["expiry"], undefined);
+ // The 'default lax' behavior varies by browser.
+ // assert_equals(cookie["sameSite"], "Lax");
+
+ // test3 [HttpOnly]
+ cookie = await test_driver.get_named_cookie("test3");
+ assert_equals(cookie["name"], "test3");
+ assert_equals(cookie["value"], "3");
+ assert_equals(cookie["path"], "/infrastructure/testdriver");
+ assert_equals(cookie["domain"], "{{host}}");
+ assert_equals(cookie["secure"], false);
+ assert_equals(cookie["httpOnly"], true);
+ assert_equals(cookie["expiry"], undefined);
+ // The 'default lax' behavior varies by browser.
+ // assert_equals(cookie["sameSite"], "Lax");
+
+ // test4 [Secure] Omitted
+ try {
+ await test_driver.get_named_cookie("test4");
+ } catch(e) {
+ assert_equals(e.message, "no such cookie");
+ }
+
+ // test5 [SameSite Strict]
+ cookie = await test_driver.get_named_cookie("test5");
+ assert_equals(cookie["name"], "test5");
+ assert_equals(cookie["value"], "5");
+ assert_equals(cookie["path"], "/infrastructure/testdriver");
+ assert_equals(cookie["domain"], "{{host}}");
+ assert_equals(cookie["secure"], false);
+ assert_equals(cookie["httpOnly"], false);
+ assert_equals(cookie["expiry"], undefined);
+ assert_equals(cookie["sameSite"], "Strict");
+
+ // test6 [SameSite None] Omitted
+ try {
+ await test_driver.get_named_cookie("test6");
+ } catch(e) {
+ assert_equals(e.message, "no such cookie");
+ }
+
+ // test7 [SameSite Strict]
+ cookie = await test_driver.get_named_cookie("test7");
+ assert_equals(cookie["name"], "test7");
+ assert_equals(cookie["value"], "7");
+ assert_equals(cookie["path"], "/infrastructure/testdriver");
+ assert_equals(cookie["domain"], "{{host}}");
+ assert_equals(cookie["secure"], false);
+ assert_equals(cookie["httpOnly"], false);
+ assert_equals(cookie["expiry"], undefined);
+ assert_equals(cookie["sameSite"], "Lax");
+}, "Get Named HTTP cookie");
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/get_named_cookie.sub.html.headers b/testing/web-platform/tests/infrastructure/testdriver/get_named_cookie.sub.html.headers
new file mode 100644
index 0000000000..3dc39a5673
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/get_named_cookie.sub.html.headers
@@ -0,0 +1 @@
+Set-Cookie: test3=3; HttpOnly
diff --git a/testing/web-platform/tests/infrastructure/testdriver/get_named_cookie.sub.https.html b/testing/web-platform/tests/infrastructure/testdriver/get_named_cookie.sub.https.html
new file mode 100644
index 0000000000..8e8f443381
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/get_named_cookie.sub.https.html
@@ -0,0 +1,114 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver get_named_cookie method HTTPS</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script>
+promise_test(async t => {
+ t.add_cleanup(test_driver.delete_all_cookies);
+ const kTenDaysFromNow = new Date(Date.now() + 10 * 24 * 60 * 60 * 1000);
+ document.cookie = "test0=0";
+ document.cookie = `test1=1; Expires=${kTenDaysFromNow.toUTCString()}`;
+ document.cookie = "test2=2; Path=/";
+ // document.cookie = "test3=3; HttpOnly"; This is set in the headers file.
+ document.cookie = "test4=4; Secure";
+ document.cookie = "test5=5; SameSite=Strict";
+ document.cookie = "test6=6; SameSite=None; Secure";
+ document.cookie = "test7=7; SameSite=Lax";
+
+ // test0
+ let cookie = await test_driver.get_named_cookie("test0");
+ assert_equals(cookie["name"], "test0");
+ assert_equals(cookie["value"], "0");
+ assert_equals(cookie["path"], "/infrastructure/testdriver");
+ assert_equals(cookie["domain"], "{{host}}");
+ assert_equals(cookie["secure"], false);
+ assert_equals(cookie["httpOnly"], false);
+ assert_equals(cookie["expiry"], undefined);
+ // The 'default lax' behavior varies by browser.
+ // assert_equals(cookie["sameSite"], "Lax");
+
+ // test1 [Expires in 10 days]
+ cookie = await test_driver.get_named_cookie("test1");
+ assert_equals(cookie["name"], "test1");
+ assert_equals(cookie["value"], "1");
+ assert_equals(cookie["path"], "/infrastructure/testdriver");
+ assert_equals(cookie["domain"], "{{host}}");
+ assert_equals(cookie["secure"], false);
+ assert_equals(cookie["httpOnly"], false);
+ assert_equals(cookie["expiry"], Math.floor(kTenDaysFromNow.getTime()/1000));
+ // The 'default lax' behavior varies by browser.
+ // assert_equals(cookie["sameSite"], "Lax");
+
+ // test2 [Path /]
+ cookie = await test_driver.get_named_cookie("test2");
+ assert_equals(cookie["name"], "test2");
+ assert_equals(cookie["value"], "2");
+ assert_equals(cookie["path"], "/");
+ assert_equals(cookie["domain"], "{{host}}");
+ assert_equals(cookie["secure"], false);
+ assert_equals(cookie["httpOnly"], false);
+ assert_equals(cookie["expiry"], undefined);
+ // The 'default lax' behavior varies by browser.
+ // assert_equals(cookie["sameSite"], "Lax");
+
+ // test3 [HttpOnly]
+ cookie = await test_driver.get_named_cookie("test3");
+ assert_equals(cookie["name"], "test3");
+ assert_equals(cookie["value"], "3");
+ assert_equals(cookie["path"], "/infrastructure/testdriver");
+ assert_equals(cookie["domain"], "{{host}}");
+ assert_equals(cookie["secure"], false);
+ assert_equals(cookie["httpOnly"], true);
+ assert_equals(cookie["expiry"], undefined);
+ // The 'default lax' behavior varies by browser.
+ // assert_equals(cookie["sameSite"], "Lax");
+
+ // test4 [Secure]
+ cookie = await test_driver.get_named_cookie("test4");
+ assert_equals(cookie["name"], "test4");
+ assert_equals(cookie["value"], "4");
+ assert_equals(cookie["path"], "/infrastructure/testdriver");
+ assert_equals(cookie["domain"], "{{host}}");
+ assert_equals(cookie["secure"], true);
+ assert_equals(cookie["httpOnly"], false);
+ assert_equals(cookie["expiry"], undefined);
+ // The 'default lax' behavior varies by browser.
+ // assert_equals(cookie["sameSite"], "Lax");
+
+ // test5 [SameSite Strict]
+ cookie = await test_driver.get_named_cookie("test5");
+ assert_equals(cookie["name"], "test5");
+ assert_equals(cookie["value"], "5");
+ assert_equals(cookie["path"], "/infrastructure/testdriver");
+ assert_equals(cookie["domain"], "{{host}}");
+ assert_equals(cookie["secure"], false);
+ assert_equals(cookie["httpOnly"], false);
+ assert_equals(cookie["expiry"], undefined);
+ assert_equals(cookie["sameSite"], "Strict");
+
+ // test6 [SameSite None]
+ cookie = await test_driver.get_named_cookie("test6");
+ assert_equals(cookie["name"], "test6");
+ assert_equals(cookie["value"], "6");
+ assert_equals(cookie["path"], "/infrastructure/testdriver");
+ assert_equals(cookie["domain"], "{{host}}");
+ assert_equals(cookie["secure"], true);
+ assert_equals(cookie["httpOnly"], false);
+ assert_equals(cookie["expiry"], undefined);
+ assert_equals(cookie["sameSite"], "None");
+
+ // test7 [SameSite Strict]
+ cookie = await test_driver.get_named_cookie("test7");
+ assert_equals(cookie["name"], "test7");
+ assert_equals(cookie["value"], "7");
+ assert_equals(cookie["path"], "/infrastructure/testdriver");
+ assert_equals(cookie["domain"], "{{host}}");
+ assert_equals(cookie["secure"], false);
+ assert_equals(cookie["httpOnly"], false);
+ assert_equals(cookie["expiry"], undefined);
+ assert_equals(cookie["sameSite"], "Lax");
+}, "Get Named HTTPS cookie");
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/get_named_cookie.sub.https.html.headers b/testing/web-platform/tests/infrastructure/testdriver/get_named_cookie.sub.https.html.headers
new file mode 100644
index 0000000000..3dc39a5673
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/get_named_cookie.sub.https.html.headers
@@ -0,0 +1 @@
+Set-Cookie: test3=3; HttpOnly
diff --git a/testing/web-platform/tests/infrastructure/testdriver/send_keys.html b/testing/web-platform/tests/infrastructure/testdriver/send_keys.html
new file mode 100644
index 0000000000..71ca4405f4
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/send_keys.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver send keys method</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<input type="text" id="text">Text Input</button>
+
+<script>
+async_test(t => {
+ let input_text = "Hello, wpt!";
+ let text_box = document.getElementById("text");
+ test_driver
+ .send_keys(text_box, input_text)
+ .then(() => {
+ assert_equals(text_box.value, input_text);
+ t.done();
+ })
+ .catch(t.unreached_func("send keys failed"));
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/set_permission.https.html b/testing/web-platform/tests/infrastructure/testdriver/set_permission.https.html
new file mode 100644
index 0000000000..7bc42a8538
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/set_permission.https.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>TestDriver set_permission method</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<script>
+ const descriptor = { name: "geolocation" };
+
+ promise_test(async (t) => {
+ await test_driver.set_permission(descriptor, "granted");
+ permission = await navigator.permissions.query(descriptor);
+ assert_equals(permission.state, "granted");
+ }, "Grant Permission");
+
+ promise_test(async (t) => {
+ await test_driver.set_permission(descriptor, "denied");
+ permission = await navigator.permissions.query(descriptor);
+ assert_equals(permission.state, "denied");
+ }, "Deny Permission");
+</script>
diff --git a/testing/web-platform/tests/infrastructure/testdriver/virtual_authenticator.html b/testing/web-platform/tests/infrastructure/testdriver/virtual_authenticator.html
new file mode 100644
index 0000000000..04c14719d4
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testdriver/virtual_authenticator.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver virtual authenticator methods</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script>
+"use strict";
+
+// Encodes |data| into a base64url string. There is no '=' padding, and the
+// characters '-' and '_' must be used instead of '+' and '/', respectively.
+function base64urlEncode(data) {
+ let result = btoa(data);
+ return result.replaceAll("=", "").replaceAll("+", "-").replaceAll("/", "_");
+}
+
+// The example attestation private key from the U2F spec at
+// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html#registration-example
+// PKCS.8 encoded without encryption, as a base64url string.
+const private_key =
+ "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg8_zMDQDYAxlU-Q"
+ + "hk1Dwkf0v18GZca1DMF3SaJ9HPdmShRANCAASNYX5lyVCOZLzFZzrIKmeZ2jwU"
+ + "RmgsJYxGP__fWN_S-j5sN4tT15XEpN_7QZnt14YvI6uvAgO0uJEboFaZlOEB";
+let credential_id = base64urlEncode("cred-1");
+let credential = {
+ credentialId: credential_id,
+ rpId: window.location.hostname,
+ privateKey: private_key,
+ signCount: 0,
+ isResidentCredential: false,
+};
+
+let authenticator_id = null;
+
+promise_test(async t => {
+ authenticator_id = await test_driver.add_virtual_authenticator({
+ protocol: "ctap1/u2f",
+ transport: "usb",
+ });
+}, "Can create an authenticator");
+
+promise_test(async t => {
+ return test_driver.add_credential(authenticator_id, credential);
+}, "Can add a credential");
+
+promise_test(async t => {
+ let credentials = await test_driver.get_credentials(authenticator_id);
+ assert_equals(credentials.length, 1);
+ // The U2F REGISTER operation stores the hash of the rpId, so the rpId
+ // itself may not be available on the returned credential.
+ assert_equals(credentials[0].credentialId, credential.credentialId);
+ assert_equals(credentials[0].privateKey, credential.privateKey);
+ assert_equals(credentials[0].signCount, credential.signCount);
+ assert_equals(credentials[0].isResidentCredential,
+ credential.isResidentCredential);
+}, "Can get the credentials");
+
+promise_test(async t => {
+ await test_driver.remove_credential(authenticator_id, credential_id);
+ let credentials = await test_driver.get_credentials(authenticator_id);
+ assert_equals(credentials.length, 0);
+}, "Can remove a credential");
+
+promise_test(async t => {
+ let credential1 = credential;
+ let credential2 =
+ Object.assign({}, credential, {credentialId: base64urlEncode("cred-2")});
+ await test_driver.add_credential(authenticator_id, credential1);
+ await test_driver.add_credential(authenticator_id, credential2);
+
+ let credentials = await test_driver.get_credentials(authenticator_id);
+ assert_equals(credentials.length, 2);
+
+ await test_driver.remove_all_credentials(authenticator_id);
+ credentials = await test_driver.get_credentials(authenticator_id);
+ assert_equals(credentials.length, 0);
+}, "Can remove all credentials");
+
+promise_test(async t => {
+ await test_driver.set_user_verified(authenticator_id, {isUserVerified: true});
+ await test_driver.set_user_verified(authenticator_id, {isUserVerified: false});
+}, "Can set user verified");
+
+promise_test(async t => {
+ await test_driver.remove_virtual_authenticator(authenticator_id);
+}, "Can remove a virtual authenticator");
+</script>