summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/infrastructure
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/infrastructure')
-rw-r--r--testing/web-platform/tests/infrastructure/META.yml2
-rw-r--r--testing/web-platform/tests/infrastructure/README.md14
-rw-r--r--testing/web-platform/tests/infrastructure/assumptions/README.md1
-rw-r--r--testing/web-platform/tests/infrastructure/assumptions/ahem-notref.html316
-rw-r--r--testing/web-platform/tests/infrastructure/assumptions/ahem-ref.html320
-rw-r--r--testing/web-platform/tests/infrastructure/assumptions/ahem.html316
-rw-r--r--testing/web-platform/tests/infrastructure/assumptions/allowed-to-play.html23
-rw-r--r--testing/web-platform/tests/infrastructure/assumptions/blank.html2
-rw-r--r--testing/web-platform/tests/infrastructure/assumptions/canvas-background-ref.html8
-rw-r--r--testing/web-platform/tests/infrastructure/assumptions/canvas-background.html4
-rw-r--r--testing/web-platform/tests/infrastructure/assumptions/cookie.html18
-rw-r--r--testing/web-platform/tests/infrastructure/assumptions/document-fonts-ready.html32
-rw-r--r--testing/web-platform/tests/infrastructure/assumptions/html-elements.html133
-rw-r--r--testing/web-platform/tests/infrastructure/assumptions/initial-color-ref.html12
-rw-r--r--testing/web-platform/tests/infrastructure/assumptions/initial-color.html9
-rw-r--r--testing/web-platform/tests/infrastructure/assumptions/medium-font-size-ref.html8
-rw-r--r--testing/web-platform/tests/infrastructure/assumptions/medium-font-size.html9
-rw-r--r--testing/web-platform/tests/infrastructure/assumptions/min-font-size-ref.html8
-rw-r--r--testing/web-platform/tests/infrastructure/assumptions/min-font-size.html9
-rw-r--r--testing/web-platform/tests/infrastructure/assumptions/non-local-ports.sub.window.js111
-rw-r--r--testing/web-platform/tests/infrastructure/assumptions/non-secure-context.any.js9
-rw-r--r--testing/web-platform/tests/infrastructure/assumptions/resources/fetch-and-post-result.html12
-rw-r--r--testing/web-platform/tests/infrastructure/assumptions/tools/ahem-generate-table.py127
-rw-r--r--testing/web-platform/tests/infrastructure/browsers/firefox/prefs.html9
-rw-r--r--testing/web-platform/tests/infrastructure/channels/child_message.html13
-rw-r--r--testing/web-platform/tests/infrastructure/channels/child_script.html10
-rw-r--r--testing/web-platform/tests/infrastructure/channels/serialize-data.js37
-rw-r--r--testing/web-platform/tests/infrastructure/channels/serialize_child.html173
-rw-r--r--testing/web-platform/tests/infrastructure/channels/test_call.html22
-rw-r--r--testing/web-platform/tests/infrastructure/channels/test_postMessage.html23
-rw-r--r--testing/web-platform/tests/infrastructure/channels/test_serialize.html38
-rw-r--r--testing/web-platform/tests/infrastructure/crashtests/example.html1
-rw-r--r--testing/web-platform/tests/infrastructure/expected-fail/failing-test.html10
-rw-r--r--testing/web-platform/tests/infrastructure/expected-fail/timeout.html8
-rw-r--r--testing/web-platform/tests/infrastructure/expected-fail/uncaught-exception-following-subtest.html9
-rw-r--r--testing/web-platform/tests/infrastructure/expected-fail/uncaught-exception-single-test.html9
-rw-r--r--testing/web-platform/tests/infrastructure/expected-fail/uncaught-exception.html8
-rw-r--r--testing/web-platform/tests/infrastructure/expected-fail/unhandled-rejection-following-subtest.html11
-rw-r--r--testing/web-platform/tests/infrastructure/expected-fail/unhandled-rejection-single-test.html9
-rw-r--r--testing/web-platform/tests/infrastructure/expected-fail/unhandled-rejection.html8
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/assumptions/ahem.html.ini3
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/assumptions/allowed-to-play.html.ini9
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/assumptions/document-fonts-ready.html.ini4
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/assumptions/non-local-ports.sub.window.js.ini4
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/browsers/firefox/__dir__.ini2
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/browsers/firefox/prefs.html.ini2
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/failing-test.html.ini4
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/timeout.html.ini4
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/uncaught-exception-following-subtest.html.ini6
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/uncaught-exception-single-test.html.ini4
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/uncaught-exception.html.ini2
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/unhandled-rejection-following-subtest.html.ini6
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/unhandled-rejection-single-test.html.ini4
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/unhandled-rejection.html.ini2
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/window-onload-test.html.ini16
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/legacy/fuzzy-ref-2.html.ini4
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/legacy/reftest_and_fail_0-ref.html.ini2
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/legacy/reftest_cycle_fail_0-ref.html.ini2
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/legacy/reftest_fuzzy_chain_ini.html.ini4
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_1.html.ini3
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_full.html.ini6
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_ref_only.html.ini8
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_short.html.ini4
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_and_mismatch-0.html.ini2
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_and_mismatch-1.html.ini2
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_and_mismatch-4.html.ini2
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_and_mismatch-5.html.ini2
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_and_mismatch-6.html.ini2
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_and_mismatch-7.html.ini2
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_fail-print.html.ini2
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_fail.html.ini3
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_mismatch_fail-print.html.ini2
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_mismatch_fail.html.ini3
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_multiple_mismatch-0.html.ini2
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_multiple_mismatch-1.html.ini2
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_ref_timeout.html.ini3
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_timeout.html.ini3
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/server/context.any.js.ini8
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/server/http2-context.sub.h2.any.js.ini1
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/server/http2-websocket.sub.h2.any.js.ini16
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/server/secure-context.https.any.js.ini6
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/server/test-pac.html.ini4
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/server/webtransport-h3.https.sub.any.js.ini29
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/server/wpt-server-http.sub.html.ini20
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/server/wpt-server-websocket.sub.html.ini41
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/crossOrigin.sub.html.ini4
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/eventOrder.html.ini3
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/mouseClickCount.html.ini4
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/multiTouchPoints.html.ini7
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/multiTouchPointsReleaseFirstPoint.html.ini4
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/multiTouchPointsReleaseSecondPoint.html.ini5
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/multiTouchPointsSimultaneousMove.html.ini5
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/multiTouchPointsTwoTouchStarts.html.ini4
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/multiTouchPointsWithPause.html.ini4
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/pause.html.ini3
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/penPointerEventProperties.html.ini6
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/penPointerEvents.html.ini6
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/touchPointerEventProperties.html.ini4
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/wheelScroll.html.ini3
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/click_iframe_crossorigin.sub.html.ini4
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/file_upload.sub.html.ini6
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/generate_test_report.html.ini4
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/set_permission.https.html.ini8
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/virtual_authenticator.html.ini31
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/infrastructure/testharness/lone-surrogates.html.ini7
-rw-r--r--testing/web-platform/tests/infrastructure/metadata/update_properties.json1
-rw-r--r--testing/web-platform/tests/infrastructure/reftest-wait-ref.html13
-rw-r--r--testing/web-platform/tests/infrastructure/reftest-wait.html21
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/fuzzy-ref-1.html9
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/green-ref.html4
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/green.html3
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/legacy/README.md5
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/legacy/fuzzy-ref-2.html11
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/legacy/fuzzy-ref-2a.html9
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/legacy/reftest_and_fail.html5
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/legacy/reftest_and_fail_0-ref.html5
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/legacy/reftest_and_mismatch.html5
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/legacy/reftest_and_mismatch_0.html5
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/legacy/reftest_and_mismatch_1.html4
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/legacy/reftest_cycle.html5
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/legacy/reftest_cycle_0-ref.html5
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/legacy/reftest_cycle_1-ref.html5
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/legacy/reftest_cycle_fail.html5
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/legacy/reftest_cycle_fail_0-ref.html5
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/legacy/reftest_fuzzy_chain_ini.html11
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/red.html3
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest.https.html9
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest.www.sub.html10
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_fuzzy_1.html12
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_fuzzy_ini_full.html13
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_fuzzy_ini_ref_only.html13
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_fuzzy_ini_short.html13
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_fuzzy_no_differences.html13
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_fuzzy_no_differences_1.html13
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_match-print-ref.html13
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_match-print.html12
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_match.html5
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-0.html6
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-1.html6
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-2.html7
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-3.html7
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-4.html7
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-5.html7
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-6.html8
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-7.html8
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_match_fail-print.html12
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_match_fail.html5
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_mismatch-num-pages-print.html3
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_mismatch-print.html13
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_mismatch.html5
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_mismatch_fail-print.html13
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_mismatch_fail.html5
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_mismatch_page_margins-print.html13
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_multiple_match-0.html6
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_multiple_match-1.html6
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_multiple_mismatch-0.html6
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_multiple_mismatch-1.html6
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_ref_timeout-ref.html5
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_ref_timeout.html6
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_timeout.html6
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_wait_0.html13
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/reftest_wait_TestRendered.html14
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/size-ref.html2
-rw-r--r--testing/web-platform/tests/infrastructure/reftest/size.html6
-rw-r--r--testing/web-platform/tests/infrastructure/resources/ok.txt1
-rw-r--r--testing/web-platform/tests/infrastructure/resources/ok.txt.headers1
-rw-r--r--testing/web-platform/tests/infrastructure/server/context.any.js13
-rw-r--r--testing/web-platform/tests/infrastructure/server/http2-context.sub.h2.any.js12
-rw-r--r--testing/web-platform/tests/infrastructure/server/http2-websocket.sub.h2.any.js20
-rw-r--r--testing/web-platform/tests/infrastructure/server/order-of-metas.any.js10
-rw-r--r--testing/web-platform/tests/infrastructure/server/order-of-metas.window.js8
-rw-r--r--testing/web-platform/tests/infrastructure/server/resources/expect-global.js5
-rw-r--r--testing/web-platform/tests/infrastructure/server/resources/expect-seen-testharness.js5
-rw-r--r--testing/web-platform/tests/infrastructure/server/resources/expect-title-meta.js11
-rw-r--r--testing/web-platform/tests/infrastructure/server/resources/proxy.sub.pac7
-rw-r--r--testing/web-platform/tests/infrastructure/server/secure-context.https.any.js10
-rw-r--r--testing/web-platform/tests/infrastructure/server/subdomain-flag.www.sub.window.js5
-rw-r--r--testing/web-platform/tests/infrastructure/server/test-pac.html12
-rw-r--r--testing/web-platform/tests/infrastructure/server/title.any.js13
-rw-r--r--testing/web-platform/tests/infrastructure/server/webtransport-h3.https.sub.any.js26
-rw-r--r--testing/web-platform/tests/infrastructure/server/wpt-server-http.sub.html262
-rw-r--r--testing/web-platform/tests/infrastructure/server/wpt-server-websocket.sub.html122
-rw-r--r--testing/web-platform/tests/infrastructure/server/wpt-server-wpt-flags.sub.html32
-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
-rw-r--r--testing/web-platform/tests/infrastructure/testharness/lone-surrogates.html10
-rw-r--r--testing/web-platform/tests/infrastructure/webdriver/tests/conftest.py7
-rw-r--r--testing/web-platform/tests/infrastructure/webdriver/tests/test_load_file.py2
238 files changed, 5563 insertions, 0 deletions
diff --git a/testing/web-platform/tests/infrastructure/META.yml b/testing/web-platform/tests/infrastructure/META.yml
new file mode 100644
index 0000000000..64a240ccbe
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/META.yml
@@ -0,0 +1,2 @@
+suggested_reviewers:
+ - jgraham
diff --git a/testing/web-platform/tests/infrastructure/README.md b/testing/web-platform/tests/infrastructure/README.md
new file mode 100644
index 0000000000..7d0ec556aa
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/README.md
@@ -0,0 +1,14 @@
+This directory contains a number of tests to ensure test running
+infrastructure is operating correctly:
+
+ * The tests in assumptions/ are designed to test UA assumptions
+ documented in [assumptions.md](/docs/_writing-tests/assumptions.md).
+
+ * The tests in server/ are designed to test the WPT server configuration
+
+ * The tests in expected-fail/ should all fail.
+
+To update the expectations stored in metadata/, you want to use the `wpt`
+tool with an invocation such as `./wpt update-expectations --metadata
+infrastructure/metadata --manifest MANIFEST.json [wptreport.json]` with one
+or more wptreport.json files.
diff --git a/testing/web-platform/tests/infrastructure/assumptions/README.md b/testing/web-platform/tests/infrastructure/assumptions/README.md
new file mode 100644
index 0000000000..51902b8899
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/assumptions/README.md
@@ -0,0 +1 @@
+To update the generated tests, run `wpt update-built --include infrastructure`.
diff --git a/testing/web-platform/tests/infrastructure/assumptions/ahem-notref.html b/testing/web-platform/tests/infrastructure/assumptions/ahem-notref.html
new file mode 100644
index 0000000000..51767c26ea
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/assumptions/ahem-notref.html
@@ -0,0 +1,316 @@
+<!doctype html>
+<title>Ahem checker</title>
+<style>
+* {
+ padding: 0;
+ margin: 0;
+ border: none;
+}
+td {
+ width: 34px;
+}
+table {
+ font-size: 15px;
+ line-height: 1;
+ border-collapse: separate;
+ border-spacing: 1px;
+ table-layout: fixed;
+}
+</style>
+<table>
+ <tr>
+ <td>&#x0020;x <!-- U+0020: SPACE -->
+ <td>&#x0021;x <!-- U+0021: EXCLAMATION MARK -->
+ <td>&#x0022;x <!-- U+0022: QUOTATION MARK -->
+ <td>&#x0023;x <!-- U+0023: NUMBER SIGN -->
+ <td>&#x0024;x <!-- U+0024: DOLLAR SIGN -->
+ <td>&#x0025;x <!-- U+0025: PERCENT SIGN -->
+ <td>&#x0026;x <!-- U+0026: AMPERSAND -->
+ <td>&#x0028;x <!-- U+0028: LEFT PARENTHESIS -->
+ <td>&#x0029;x <!-- U+0029: RIGHT PARENTHESIS -->
+ <td>&#x002A;x <!-- U+002A: ASTERISK -->
+ <td>&#x002B;x <!-- U+002B: PLUS SIGN -->
+ <td>&#x002C;x <!-- U+002C: COMMA -->
+ <td>&#x002D;x <!-- U+002D: HYPHEN-MINUS -->
+ <td>&#x002E;x <!-- U+002E: FULL STOP -->
+ <td>&#x002F;x <!-- U+002F: SOLIDUS -->
+ <td>&#x0030;x <!-- U+0030: DIGIT ZERO -->
+ <td>&#x0031;x <!-- U+0031: DIGIT ONE -->
+ <tr>
+ <td>&#x0032;x <!-- U+0032: DIGIT TWO -->
+ <td>&#x0033;x <!-- U+0033: DIGIT THREE -->
+ <td>&#x0034;x <!-- U+0034: DIGIT FOUR -->
+ <td>&#x0035;x <!-- U+0035: DIGIT FIVE -->
+ <td>&#x0036;x <!-- U+0036: DIGIT SIX -->
+ <td>&#x0037;x <!-- U+0037: DIGIT SEVEN -->
+ <td>&#x0038;x <!-- U+0038: DIGIT EIGHT -->
+ <td>&#x0039;x <!-- U+0039: DIGIT NINE -->
+ <td>&#x003A;x <!-- U+003A: COLON -->
+ <td>&#x003B;x <!-- U+003B: SEMICOLON -->
+ <td>&#x003C;x <!-- U+003C: LESS-THAN SIGN -->
+ <td>&#x003D;x <!-- U+003D: EQUALS SIGN -->
+ <td>&#x003E;x <!-- U+003E: GREATER-THAN SIGN -->
+ <td>&#x003F;x <!-- U+003F: QUESTION MARK -->
+ <td>&#x0040;x <!-- U+0040: COMMERCIAL AT -->
+ <td>&#x0041;x <!-- U+0041: LATIN CAPITAL LETTER A -->
+ <td>&#x0042;x <!-- U+0042: LATIN CAPITAL LETTER B -->
+ <tr>
+ <td>&#x0043;x <!-- U+0043: LATIN CAPITAL LETTER C -->
+ <td>&#x0044;x <!-- U+0044: LATIN CAPITAL LETTER D -->
+ <td>&#x0045;x <!-- U+0045: LATIN CAPITAL LETTER E -->
+ <td>&#x0046;x <!-- U+0046: LATIN CAPITAL LETTER F -->
+ <td>&#x0047;x <!-- U+0047: LATIN CAPITAL LETTER G -->
+ <td>&#x0048;x <!-- U+0048: LATIN CAPITAL LETTER H -->
+ <td>&#x0049;x <!-- U+0049: LATIN CAPITAL LETTER I -->
+ <td>&#x004A;x <!-- U+004A: LATIN CAPITAL LETTER J -->
+ <td>&#x004B;x <!-- U+004B: LATIN CAPITAL LETTER K -->
+ <td>&#x004C;x <!-- U+004C: LATIN CAPITAL LETTER L -->
+ <td>&#x004D;x <!-- U+004D: LATIN CAPITAL LETTER M -->
+ <td>&#x004E;x <!-- U+004E: LATIN CAPITAL LETTER N -->
+ <td>&#x004F;x <!-- U+004F: LATIN CAPITAL LETTER O -->
+ <td>&#x0050;x <!-- U+0050: LATIN CAPITAL LETTER P -->
+ <td>&#x0051;x <!-- U+0051: LATIN CAPITAL LETTER Q -->
+ <td>&#x0052;x <!-- U+0052: LATIN CAPITAL LETTER R -->
+ <td>&#x0053;x <!-- U+0053: LATIN CAPITAL LETTER S -->
+ <tr>
+ <td>&#x0054;x <!-- U+0054: LATIN CAPITAL LETTER T -->
+ <td>&#x0055;x <!-- U+0055: LATIN CAPITAL LETTER U -->
+ <td>&#x0056;x <!-- U+0056: LATIN CAPITAL LETTER V -->
+ <td>&#x0057;x <!-- U+0057: LATIN CAPITAL LETTER W -->
+ <td>&#x0058;x <!-- U+0058: LATIN CAPITAL LETTER X -->
+ <td>&#x0059;x <!-- U+0059: LATIN CAPITAL LETTER Y -->
+ <td>&#x005A;x <!-- U+005A: LATIN CAPITAL LETTER Z -->
+ <td>&#x005B;x <!-- U+005B: LEFT SQUARE BRACKET -->
+ <td>&#x005C;x <!-- U+005C: REVERSE SOLIDUS -->
+ <td>&#x005D;x <!-- U+005D: RIGHT SQUARE BRACKET -->
+ <td>&#x005E;x <!-- U+005E: CIRCUMFLEX ACCENT -->
+ <td>&#x005F;x <!-- U+005F: LOW LINE -->
+ <td>&#x0060;x <!-- U+0060: GRAVE ACCENT -->
+ <td>&#x0061;x <!-- U+0061: LATIN SMALL LETTER A -->
+ <td>&#x0062;x <!-- U+0062: LATIN SMALL LETTER B -->
+ <td>&#x0063;x <!-- U+0063: LATIN SMALL LETTER C -->
+ <td>&#x0064;x <!-- U+0064: LATIN SMALL LETTER D -->
+ <tr>
+ <td>&#x0065;x <!-- U+0065: LATIN SMALL LETTER E -->
+ <td>&#x0066;x <!-- U+0066: LATIN SMALL LETTER F -->
+ <td>&#x0067;x <!-- U+0067: LATIN SMALL LETTER G -->
+ <td>&#x0068;x <!-- U+0068: LATIN SMALL LETTER H -->
+ <td>&#x0069;x <!-- U+0069: LATIN SMALL LETTER I -->
+ <td>&#x006A;x <!-- U+006A: LATIN SMALL LETTER J -->
+ <td>&#x006B;x <!-- U+006B: LATIN SMALL LETTER K -->
+ <td>&#x006C;x <!-- U+006C: LATIN SMALL LETTER L -->
+ <td>&#x006D;x <!-- U+006D: LATIN SMALL LETTER M -->
+ <td>&#x006E;x <!-- U+006E: LATIN SMALL LETTER N -->
+ <td>&#x006F;x <!-- U+006F: LATIN SMALL LETTER O -->
+ <td>&#x0070;x <!-- U+0070: LATIN SMALL LETTER P -->
+ <td>&#x0071;x <!-- U+0071: LATIN SMALL LETTER Q -->
+ <td>&#x0072;x <!-- U+0072: LATIN SMALL LETTER R -->
+ <td>&#x0073;x <!-- U+0073: LATIN SMALL LETTER S -->
+ <td>&#x0074;x <!-- U+0074: LATIN SMALL LETTER T -->
+ <td>&#x0075;x <!-- U+0075: LATIN SMALL LETTER U -->
+ <tr>
+ <td>&#x0076;x <!-- U+0076: LATIN SMALL LETTER V -->
+ <td>&#x0077;x <!-- U+0077: LATIN SMALL LETTER W -->
+ <td>&#x0078;x <!-- U+0078: LATIN SMALL LETTER X -->
+ <td>&#x0079;x <!-- U+0079: LATIN SMALL LETTER Y -->
+ <td>&#x007A;x <!-- U+007A: LATIN SMALL LETTER Z -->
+ <td>&#x007B;x <!-- U+007B: LEFT CURLY BRACKET -->
+ <td>&#x007C;x <!-- U+007C: VERTICAL LINE -->
+ <td>&#x007D;x <!-- U+007D: RIGHT CURLY BRACKET -->
+ <td>&#x007E;x <!-- U+007E: TILDE -->
+ <td>&#x00A0;x <!-- U+00A0: NO-BREAK SPACE -->
+ <td>&#x00A1;x <!-- U+00A1: INVERTED EXCLAMATION MARK -->
+ <td>&#x00A2;x <!-- U+00A2: CENT SIGN -->
+ <td>&#x00A3;x <!-- U+00A3: POUND SIGN -->
+ <td>&#x00A4;x <!-- U+00A4: CURRENCY SIGN -->
+ <td>&#x00A5;x <!-- U+00A5: YEN SIGN -->
+ <td>&#x00A6;x <!-- U+00A6: BROKEN BAR -->
+ <td>&#x00A7;x <!-- U+00A7: SECTION SIGN -->
+ <tr>
+ <td>&#x00A8;x <!-- U+00A8: DIAERESIS -->
+ <td>&#x00A9;x <!-- U+00A9: COPYRIGHT SIGN -->
+ <td>&#x00AA;x <!-- U+00AA: FEMININE ORDINAL INDICATOR -->
+ <td>&#x00AB;x <!-- U+00AB: LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -->
+ <td>&#x00AC;x <!-- U+00AC: NOT SIGN -->
+ <td>&#x00AD;x <!-- U+00AD: SOFT HYPHEN -->
+ <td>&#x00AE;x <!-- U+00AE: REGISTERED SIGN -->
+ <td>&#x00AF;x <!-- U+00AF: MACRON -->
+ <td>&#x00B0;x <!-- U+00B0: DEGREE SIGN -->
+ <td>&#x00B1;x <!-- U+00B1: PLUS-MINUS SIGN -->
+ <td>&#x00B2;x <!-- U+00B2: SUPERSCRIPT TWO -->
+ <td>&#x00B3;x <!-- U+00B3: SUPERSCRIPT THREE -->
+ <td>&#x00B4;x <!-- U+00B4: ACUTE ACCENT -->
+ <td>&#x00B5;x <!-- U+00B5: MICRO SIGN -->
+ <td>&#x00B6;x <!-- U+00B6: PILCROW SIGN -->
+ <td>&#x00B7;x <!-- U+00B7: MIDDLE DOT -->
+ <td>&#x00B8;x <!-- U+00B8: CEDILLA -->
+ <tr>
+ <td>&#x00B9;x <!-- U+00B9: SUPERSCRIPT ONE -->
+ <td>&#x00BA;x <!-- U+00BA: MASCULINE ORDINAL INDICATOR -->
+ <td>&#x00BB;x <!-- U+00BB: RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -->
+ <td>&#x00BC;x <!-- U+00BC: VULGAR FRACTION ONE QUARTER -->
+ <td>&#x00BD;x <!-- U+00BD: VULGAR FRACTION ONE HALF -->
+ <td>&#x00BE;x <!-- U+00BE: VULGAR FRACTION THREE QUARTERS -->
+ <td>&#x00BF;x <!-- U+00BF: INVERTED QUESTION MARK -->
+ <td>&#x00C0;x <!-- U+00C0: LATIN CAPITAL LETTER A WITH GRAVE -->
+ <td>&#x00C1;x <!-- U+00C1: LATIN CAPITAL LETTER A WITH ACUTE -->
+ <td>&#x00C2;x <!-- U+00C2: LATIN CAPITAL LETTER A WITH CIRCUMFLEX -->
+ <td>&#x00C3;x <!-- U+00C3: LATIN CAPITAL LETTER A WITH TILDE -->
+ <td>&#x00C4;x <!-- U+00C4: LATIN CAPITAL LETTER A WITH DIAERESIS -->
+ <td>&#x00C5;x <!-- U+00C5: LATIN CAPITAL LETTER A WITH RING ABOVE -->
+ <td>&#x00C6;x <!-- U+00C6: LATIN CAPITAL LETTER AE -->
+ <td>&#x00C7;x <!-- U+00C7: LATIN CAPITAL LETTER C WITH CEDILLA -->
+ <td>&#x00C8;x <!-- U+00C8: LATIN CAPITAL LETTER E WITH GRAVE -->
+ <td>&#x00C9;x <!-- U+00C9: LATIN CAPITAL LETTER E WITH ACUTE -->
+ <tr>
+ <td>&#x00CA;x <!-- U+00CA: LATIN CAPITAL LETTER E WITH CIRCUMFLEX -->
+ <td>&#x00CB;x <!-- U+00CB: LATIN CAPITAL LETTER E WITH DIAERESIS -->
+ <td>&#x00CC;x <!-- U+00CC: LATIN CAPITAL LETTER I WITH GRAVE -->
+ <td>&#x00CD;x <!-- U+00CD: LATIN CAPITAL LETTER I WITH ACUTE -->
+ <td>&#x00CE;x <!-- U+00CE: LATIN CAPITAL LETTER I WITH CIRCUMFLEX -->
+ <td>&#x00CF;x <!-- U+00CF: LATIN CAPITAL LETTER I WITH DIAERESIS -->
+ <td>&#x00D0;x <!-- U+00D0: LATIN CAPITAL LETTER ETH -->
+ <td>&#x00D1;x <!-- U+00D1: LATIN CAPITAL LETTER N WITH TILDE -->
+ <td>&#x00D2;x <!-- U+00D2: LATIN CAPITAL LETTER O WITH GRAVE -->
+ <td>&#x00D3;x <!-- U+00D3: LATIN CAPITAL LETTER O WITH ACUTE -->
+ <td>&#x00D4;x <!-- U+00D4: LATIN CAPITAL LETTER O WITH CIRCUMFLEX -->
+ <td>&#x00D5;x <!-- U+00D5: LATIN CAPITAL LETTER O WITH TILDE -->
+ <td>&#x00D6;x <!-- U+00D6: LATIN CAPITAL LETTER O WITH DIAERESIS -->
+ <td>&#x00D7;x <!-- U+00D7: MULTIPLICATION SIGN -->
+ <td>&#x00D8;x <!-- U+00D8: LATIN CAPITAL LETTER O WITH STROKE -->
+ <td>&#x00D9;x <!-- U+00D9: LATIN CAPITAL LETTER U WITH GRAVE -->
+ <td>&#x00DA;x <!-- U+00DA: LATIN CAPITAL LETTER U WITH ACUTE -->
+ <tr>
+ <td>&#x00DB;x <!-- U+00DB: LATIN CAPITAL LETTER U WITH CIRCUMFLEX -->
+ <td>&#x00DC;x <!-- U+00DC: LATIN CAPITAL LETTER U WITH DIAERESIS -->
+ <td>&#x00DD;x <!-- U+00DD: LATIN CAPITAL LETTER Y WITH ACUTE -->
+ <td>&#x00DE;x <!-- U+00DE: LATIN CAPITAL LETTER THORN -->
+ <td>&#x00DF;x <!-- U+00DF: LATIN SMALL LETTER SHARP S -->
+ <td>&#x00E0;x <!-- U+00E0: LATIN SMALL LETTER A WITH GRAVE -->
+ <td>&#x00E1;x <!-- U+00E1: LATIN SMALL LETTER A WITH ACUTE -->
+ <td>&#x00E2;x <!-- U+00E2: LATIN SMALL LETTER A WITH CIRCUMFLEX -->
+ <td>&#x00E3;x <!-- U+00E3: LATIN SMALL LETTER A WITH TILDE -->
+ <td>&#x00E4;x <!-- U+00E4: LATIN SMALL LETTER A WITH DIAERESIS -->
+ <td>&#x00E5;x <!-- U+00E5: LATIN SMALL LETTER A WITH RING ABOVE -->
+ <td>&#x00E6;x <!-- U+00E6: LATIN SMALL LETTER AE -->
+ <td>&#x00E7;x <!-- U+00E7: LATIN SMALL LETTER C WITH CEDILLA -->
+ <td>&#x00E8;x <!-- U+00E8: LATIN SMALL LETTER E WITH GRAVE -->
+ <td>&#x00E9;x <!-- U+00E9: LATIN SMALL LETTER E WITH ACUTE -->
+ <td>&#x00EA;x <!-- U+00EA: LATIN SMALL LETTER E WITH CIRCUMFLEX -->
+ <td>&#x00EB;x <!-- U+00EB: LATIN SMALL LETTER E WITH DIAERESIS -->
+ <tr>
+ <td>&#x00EC;x <!-- U+00EC: LATIN SMALL LETTER I WITH GRAVE -->
+ <td>&#x00ED;x <!-- U+00ED: LATIN SMALL LETTER I WITH ACUTE -->
+ <td>&#x00EE;x <!-- U+00EE: LATIN SMALL LETTER I WITH CIRCUMFLEX -->
+ <td>&#x00EF;x <!-- U+00EF: LATIN SMALL LETTER I WITH DIAERESIS -->
+ <td>&#x00F0;x <!-- U+00F0: LATIN SMALL LETTER ETH -->
+ <td>&#x00F1;x <!-- U+00F1: LATIN SMALL LETTER N WITH TILDE -->
+ <td>&#x00F2;x <!-- U+00F2: LATIN SMALL LETTER O WITH GRAVE -->
+ <td>&#x00F3;x <!-- U+00F3: LATIN SMALL LETTER O WITH ACUTE -->
+ <td>&#x00F4;x <!-- U+00F4: LATIN SMALL LETTER O WITH CIRCUMFLEX -->
+ <td>&#x00F5;x <!-- U+00F5: LATIN SMALL LETTER O WITH TILDE -->
+ <td>&#x00F6;x <!-- U+00F6: LATIN SMALL LETTER O WITH DIAERESIS -->
+ <td>&#x00F7;x <!-- U+00F7: DIVISION SIGN -->
+ <td>&#x00F8;x <!-- U+00F8: LATIN SMALL LETTER O WITH STROKE -->
+ <td>&#x00F9;x <!-- U+00F9: LATIN SMALL LETTER U WITH GRAVE -->
+ <td>&#x00FA;x <!-- U+00FA: LATIN SMALL LETTER U WITH ACUTE -->
+ <td>&#x00FB;x <!-- U+00FB: LATIN SMALL LETTER U WITH CIRCUMFLEX -->
+ <td>&#x00FC;x <!-- U+00FC: LATIN SMALL LETTER U WITH DIAERESIS -->
+ <tr>
+ <td>&#x00FD;x <!-- U+00FD: LATIN SMALL LETTER Y WITH ACUTE -->
+ <td>&#x00FE;x <!-- U+00FE: LATIN SMALL LETTER THORN -->
+ <td>&#x00FF;x <!-- U+00FF: LATIN SMALL LETTER Y WITH DIAERESIS -->
+ <td>&#x0131;x <!-- U+0131: LATIN SMALL LETTER DOTLESS I -->
+ <td>&#x0152;x <!-- U+0152: LATIN CAPITAL LIGATURE OE -->
+ <td>&#x0153;x <!-- U+0153: LATIN SMALL LIGATURE OE -->
+ <td>&#x0178;x <!-- U+0178: LATIN CAPITAL LETTER Y WITH DIAERESIS -->
+ <td>&#x0192;x <!-- U+0192: LATIN SMALL LETTER F WITH HOOK -->
+ <td>&#x02C6;x <!-- U+02C6: MODIFIER LETTER CIRCUMFLEX ACCENT -->
+ <td>&#x02C7;x <!-- U+02C7: CARON -->
+ <td>&#x02C9;x <!-- U+02C9: MODIFIER LETTER MACRON -->
+ <td>&#x02D8;x <!-- U+02D8: BREVE -->
+ <td>&#x02D9;x <!-- U+02D9: DOT ABOVE -->
+ <td>&#x02DA;x <!-- U+02DA: RING ABOVE -->
+ <td>&#x02DB;x <!-- U+02DB: OGONEK -->
+ <td>&#x02DC;x <!-- U+02DC: SMALL TILDE -->
+ <td>&#x02DD;x <!-- U+02DD: DOUBLE ACUTE ACCENT -->
+ <tr>
+ <td>&#x0394;x <!-- U+0394: GREEK CAPITAL LETTER DELTA -->
+ <td>&#x03A5;x <!-- U+03A5: GREEK CAPITAL LETTER UPSILON -->
+ <td>&#x03A7;x <!-- U+03A7: GREEK CAPITAL LETTER CHI -->
+ <td>&#x03A9;x <!-- U+03A9: GREEK CAPITAL LETTER OMEGA -->
+ <td>&#x03BC;x <!-- U+03BC: GREEK SMALL LETTER MU -->
+ <td>&#x03C0;x <!-- U+03C0: GREEK SMALL LETTER PI -->
+ <td>&#x2002;x <!-- U+2002: EN SPACE -->
+ <td>&#x2003;x <!-- U+2003: EM SPACE -->
+ <td>&#x2004;x <!-- U+2004: THREE-PER-EM SPACE -->
+ <td>&#x2005;x <!-- U+2005: FOUR-PER-EM SPACE -->
+ <td>&#x2006;x <!-- U+2006: SIX-PER-EM SPACE -->
+ <td>&#x2009;x <!-- U+2009: THIN SPACE -->
+ <td>&#x200A;x <!-- U+200A: HAIR SPACE -->
+ <td>&#x200B;x <!-- U+200B: ZERO WIDTH SPACE -->
+ <td>&#x200C;x <!-- U+200C: ZERO WIDTH NON-JOINER -->
+ <td>&#x200D;x <!-- U+200D: ZERO WIDTH JOINER -->
+ <td>&#x2010;x <!-- U+2010: HYPHEN -->
+ <tr>
+ <td>&#x2013;x <!-- U+2013: EN DASH -->
+ <td>&#x2014;x <!-- U+2014: EM DASH -->
+ <td>&#x2018;x <!-- U+2018: LEFT SINGLE QUOTATION MARK -->
+ <td>&#x2019;x <!-- U+2019: RIGHT SINGLE QUOTATION MARK -->
+ <td>&#x201A;x <!-- U+201A: SINGLE LOW-9 QUOTATION MARK -->
+ <td>&#x201C;x <!-- U+201C: LEFT DOUBLE QUOTATION MARK -->
+ <td>&#x201D;x <!-- U+201D: RIGHT DOUBLE QUOTATION MARK -->
+ <td>&#x201E;x <!-- U+201E: DOUBLE LOW-9 QUOTATION MARK -->
+ <td>&#x2020;x <!-- U+2020: DAGGER -->
+ <td>&#x2021;x <!-- U+2021: DOUBLE DAGGER -->
+ <td>&#x2022;x <!-- U+2022: BULLET -->
+ <td>&#x2026;x <!-- U+2026: HORIZONTAL ELLIPSIS -->
+ <td>&#x2030;x <!-- U+2030: PER MILLE SIGN -->
+ <td>&#x2039;x <!-- U+2039: SINGLE LEFT-POINTING ANGLE QUOTATION MARK -->
+ <td>&#x203A;x <!-- U+203A: SINGLE RIGHT-POINTING ANGLE QUOTATION MARK -->
+ <td>&#x2044;x <!-- U+2044: FRACTION SLASH -->
+ <td>&#x2122;x <!-- U+2122: TRADE MARK SIGN -->
+ <tr>
+ <td>&#x2126;x <!-- U+2126: OHM SIGN -->
+ <td>&#x2202;x <!-- U+2202: PARTIAL DIFFERENTIAL -->
+ <td>&#x2206;x <!-- U+2206: INCREMENT -->
+ <td>&#x220F;x <!-- U+220F: N-ARY PRODUCT -->
+ <td>&#x2211;x <!-- U+2211: N-ARY SUMMATION -->
+ <td>&#x2212;x <!-- U+2212: MINUS SIGN -->
+ <td>&#x2219;x <!-- U+2219: BULLET OPERATOR -->
+ <td>&#x221A;x <!-- U+221A: SQUARE ROOT -->
+ <td>&#x221E;x <!-- U+221E: INFINITY -->
+ <td>&#x222B;x <!-- U+222B: INTEGRAL -->
+ <td>&#x2248;x <!-- U+2248: ALMOST EQUAL TO -->
+ <td>&#x2260;x <!-- U+2260: NOT EQUAL TO -->
+ <td>&#x2264;x <!-- U+2264: LESS-THAN OR EQUAL TO -->
+ <td>&#x2265;x <!-- U+2265: GREATER-THAN OR EQUAL TO -->
+ <td>&#x22F2;x <!-- U+22F2: ELEMENT OF WITH LONG HORIZONTAL STROKE -->
+ <td>&#x25CA;x <!-- U+25CA: LOZENGE -->
+ <td>&#x3000;x <!-- U+3000: IDEOGRAPHIC SPACE -->
+ <tr>
+ <td>&#x3007;x <!-- U+3007: IDEOGRAPHIC NUMBER ZERO -->
+ <td>&#x4E00;x <!-- U+4E00: CJK UNIFIED IDEOGRAPH-4E00 -->
+ <td>&#x4E03;x <!-- U+4E03: CJK UNIFIED IDEOGRAPH-4E03 -->
+ <td>&#x4E09;x <!-- U+4E09: CJK UNIFIED IDEOGRAPH-4E09 -->
+ <td>&#x4E5D;x <!-- U+4E5D: CJK UNIFIED IDEOGRAPH-4E5D -->
+ <td>&#x4E8C;x <!-- U+4E8C: CJK UNIFIED IDEOGRAPH-4E8C -->
+ <td>&#x4E94;x <!-- U+4E94: CJK UNIFIED IDEOGRAPH-4E94 -->
+ <td>&#x516B;x <!-- U+516B: CJK UNIFIED IDEOGRAPH-516B -->
+ <td>&#x516D;x <!-- U+516D: CJK UNIFIED IDEOGRAPH-516D -->
+ <td>&#x5341;x <!-- U+5341: CJK UNIFIED IDEOGRAPH-5341 -->
+ <td>&#x56D7;x <!-- U+56D7: CJK UNIFIED IDEOGRAPH-56D7 -->
+ <td>&#x56DB;x <!-- U+56DB: CJK UNIFIED IDEOGRAPH-56DB -->
+ <td>&#x571F;x <!-- U+571F: CJK UNIFIED IDEOGRAPH-571F -->
+ <td>&#x6728;x <!-- U+6728: CJK UNIFIED IDEOGRAPH-6728 -->
+ <td>&#x6A2A;x <!-- U+6A2A: CJK UNIFIED IDEOGRAPH-6A2A -->
+ <td>&#x6C34;x <!-- U+6C34: CJK UNIFIED IDEOGRAPH-6C34 -->
+ <td>&#x706B;x <!-- U+706B: CJK UNIFIED IDEOGRAPH-706B -->
+ <tr>
+ <td>&#x7EB5;x <!-- U+7EB5: CJK UNIFIED IDEOGRAPH-7EB5 -->
+ <td>&#x91D1;x <!-- U+91D1: CJK UNIFIED IDEOGRAPH-91D1 -->
+ <td>&#xF000;x <!-- U+F000 -->
+ <td>&#xF001;x <!-- U+F001 -->
+ <td>&#xF002;x <!-- U+F002 -->
+ <td>&#xFEFF;x <!-- U+FEFF: ZERO WIDTH NO-BREAK SPACE -->
+</table>
diff --git a/testing/web-platform/tests/infrastructure/assumptions/ahem-ref.html b/testing/web-platform/tests/infrastructure/assumptions/ahem-ref.html
new file mode 100644
index 0000000000..9116232620
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/assumptions/ahem-ref.html
@@ -0,0 +1,320 @@
+<!doctype html>
+<title>Ahem checker</title>
+<link rel="mismatch" href="ahem-notref.html">
+<style>
+* {
+ padding: 0;
+ margin: 0;
+ border: none;
+}
+td {
+ width: 34px;
+}
+@font-face {
+ font-family: Ahem;
+ src: url("../../fonts/Ahem.ttf");
+}
+table {
+ font: 15px/1 Ahem;
+ border-collapse: separate;
+ border-spacing: 1px;
+ table-layout: fixed;
+}
+</style>
+<table>
+ <tr>
+ <td>&#x0020;x <!-- U+0020: SPACE -->
+ <td>&#x0021;x <!-- U+0021: EXCLAMATION MARK -->
+ <td>&#x0022;x <!-- U+0022: QUOTATION MARK -->
+ <td>&#x0023;x <!-- U+0023: NUMBER SIGN -->
+ <td>&#x0024;x <!-- U+0024: DOLLAR SIGN -->
+ <td>&#x0025;x <!-- U+0025: PERCENT SIGN -->
+ <td>&#x0026;x <!-- U+0026: AMPERSAND -->
+ <td>&#x0028;x <!-- U+0028: LEFT PARENTHESIS -->
+ <td>&#x0029;x <!-- U+0029: RIGHT PARENTHESIS -->
+ <td>&#x002A;x <!-- U+002A: ASTERISK -->
+ <td>&#x002B;x <!-- U+002B: PLUS SIGN -->
+ <td>&#x002C;x <!-- U+002C: COMMA -->
+ <td>&#x002D;x <!-- U+002D: HYPHEN-MINUS -->
+ <td>&#x002E;x <!-- U+002E: FULL STOP -->
+ <td>&#x002F;x <!-- U+002F: SOLIDUS -->
+ <td>&#x0030;x <!-- U+0030: DIGIT ZERO -->
+ <td>&#x0031;x <!-- U+0031: DIGIT ONE -->
+ <tr>
+ <td>&#x0032;x <!-- U+0032: DIGIT TWO -->
+ <td>&#x0033;x <!-- U+0033: DIGIT THREE -->
+ <td>&#x0034;x <!-- U+0034: DIGIT FOUR -->
+ <td>&#x0035;x <!-- U+0035: DIGIT FIVE -->
+ <td>&#x0036;x <!-- U+0036: DIGIT SIX -->
+ <td>&#x0037;x <!-- U+0037: DIGIT SEVEN -->
+ <td>&#x0038;x <!-- U+0038: DIGIT EIGHT -->
+ <td>&#x0039;x <!-- U+0039: DIGIT NINE -->
+ <td>&#x003A;x <!-- U+003A: COLON -->
+ <td>&#x003B;x <!-- U+003B: SEMICOLON -->
+ <td>&#x003C;x <!-- U+003C: LESS-THAN SIGN -->
+ <td>&#x003D;x <!-- U+003D: EQUALS SIGN -->
+ <td>&#x003E;x <!-- U+003E: GREATER-THAN SIGN -->
+ <td>&#x003F;x <!-- U+003F: QUESTION MARK -->
+ <td>&#x0040;x <!-- U+0040: COMMERCIAL AT -->
+ <td>&#x0041;x <!-- U+0041: LATIN CAPITAL LETTER A -->
+ <td>&#x0042;x <!-- U+0042: LATIN CAPITAL LETTER B -->
+ <tr>
+ <td>&#x0043;x <!-- U+0043: LATIN CAPITAL LETTER C -->
+ <td>&#x0044;x <!-- U+0044: LATIN CAPITAL LETTER D -->
+ <td>&#x0045;x <!-- U+0045: LATIN CAPITAL LETTER E -->
+ <td>&#x0046;x <!-- U+0046: LATIN CAPITAL LETTER F -->
+ <td>&#x0047;x <!-- U+0047: LATIN CAPITAL LETTER G -->
+ <td>&#x0048;x <!-- U+0048: LATIN CAPITAL LETTER H -->
+ <td>&#x0049;x <!-- U+0049: LATIN CAPITAL LETTER I -->
+ <td>&#x004A;x <!-- U+004A: LATIN CAPITAL LETTER J -->
+ <td>&#x004B;x <!-- U+004B: LATIN CAPITAL LETTER K -->
+ <td>&#x004C;x <!-- U+004C: LATIN CAPITAL LETTER L -->
+ <td>&#x004D;x <!-- U+004D: LATIN CAPITAL LETTER M -->
+ <td>&#x004E;x <!-- U+004E: LATIN CAPITAL LETTER N -->
+ <td>&#x004F;x <!-- U+004F: LATIN CAPITAL LETTER O -->
+ <td>&#x0050;x <!-- U+0050: LATIN CAPITAL LETTER P -->
+ <td>&#x0051;x <!-- U+0051: LATIN CAPITAL LETTER Q -->
+ <td>&#x0052;x <!-- U+0052: LATIN CAPITAL LETTER R -->
+ <td>&#x0053;x <!-- U+0053: LATIN CAPITAL LETTER S -->
+ <tr>
+ <td>&#x0054;x <!-- U+0054: LATIN CAPITAL LETTER T -->
+ <td>&#x0055;x <!-- U+0055: LATIN CAPITAL LETTER U -->
+ <td>&#x0056;x <!-- U+0056: LATIN CAPITAL LETTER V -->
+ <td>&#x0057;x <!-- U+0057: LATIN CAPITAL LETTER W -->
+ <td>&#x0058;x <!-- U+0058: LATIN CAPITAL LETTER X -->
+ <td>&#x0059;x <!-- U+0059: LATIN CAPITAL LETTER Y -->
+ <td>&#x005A;x <!-- U+005A: LATIN CAPITAL LETTER Z -->
+ <td>&#x005B;x <!-- U+005B: LEFT SQUARE BRACKET -->
+ <td>&#x005C;x <!-- U+005C: REVERSE SOLIDUS -->
+ <td>&#x005D;x <!-- U+005D: RIGHT SQUARE BRACKET -->
+ <td>&#x005E;x <!-- U+005E: CIRCUMFLEX ACCENT -->
+ <td>&#x005F;x <!-- U+005F: LOW LINE -->
+ <td>&#x0060;x <!-- U+0060: GRAVE ACCENT -->
+ <td>&#x0061;x <!-- U+0061: LATIN SMALL LETTER A -->
+ <td>&#x0062;x <!-- U+0062: LATIN SMALL LETTER B -->
+ <td>&#x0063;x <!-- U+0063: LATIN SMALL LETTER C -->
+ <td>&#x0064;x <!-- U+0064: LATIN SMALL LETTER D -->
+ <tr>
+ <td>&#x0065;x <!-- U+0065: LATIN SMALL LETTER E -->
+ <td>&#x0066;x <!-- U+0066: LATIN SMALL LETTER F -->
+ <td>&#x0067;x <!-- U+0067: LATIN SMALL LETTER G -->
+ <td>&#x0068;x <!-- U+0068: LATIN SMALL LETTER H -->
+ <td>&#x0069;x <!-- U+0069: LATIN SMALL LETTER I -->
+ <td>&#x006A;x <!-- U+006A: LATIN SMALL LETTER J -->
+ <td>&#x006B;x <!-- U+006B: LATIN SMALL LETTER K -->
+ <td>&#x006C;x <!-- U+006C: LATIN SMALL LETTER L -->
+ <td>&#x006D;x <!-- U+006D: LATIN SMALL LETTER M -->
+ <td>&#x006E;x <!-- U+006E: LATIN SMALL LETTER N -->
+ <td>&#x006F;x <!-- U+006F: LATIN SMALL LETTER O -->
+ <td>&#x0070;x <!-- U+0070: LATIN SMALL LETTER P -->
+ <td>&#x0071;x <!-- U+0071: LATIN SMALL LETTER Q -->
+ <td>&#x0072;x <!-- U+0072: LATIN SMALL LETTER R -->
+ <td>&#x0073;x <!-- U+0073: LATIN SMALL LETTER S -->
+ <td>&#x0074;x <!-- U+0074: LATIN SMALL LETTER T -->
+ <td>&#x0075;x <!-- U+0075: LATIN SMALL LETTER U -->
+ <tr>
+ <td>&#x0076;x <!-- U+0076: LATIN SMALL LETTER V -->
+ <td>&#x0077;x <!-- U+0077: LATIN SMALL LETTER W -->
+ <td>&#x0078;x <!-- U+0078: LATIN SMALL LETTER X -->
+ <td>&#x0079;x <!-- U+0079: LATIN SMALL LETTER Y -->
+ <td>&#x007A;x <!-- U+007A: LATIN SMALL LETTER Z -->
+ <td>&#x007B;x <!-- U+007B: LEFT CURLY BRACKET -->
+ <td>&#x007C;x <!-- U+007C: VERTICAL LINE -->
+ <td>&#x007D;x <!-- U+007D: RIGHT CURLY BRACKET -->
+ <td>&#x007E;x <!-- U+007E: TILDE -->
+ <td>&#x00A0;x <!-- U+00A0: NO-BREAK SPACE -->
+ <td>&#x00A1;x <!-- U+00A1: INVERTED EXCLAMATION MARK -->
+ <td>&#x00A2;x <!-- U+00A2: CENT SIGN -->
+ <td>&#x00A3;x <!-- U+00A3: POUND SIGN -->
+ <td>&#x00A4;x <!-- U+00A4: CURRENCY SIGN -->
+ <td>&#x00A5;x <!-- U+00A5: YEN SIGN -->
+ <td>&#x00A6;x <!-- U+00A6: BROKEN BAR -->
+ <td>&#x00A7;x <!-- U+00A7: SECTION SIGN -->
+ <tr>
+ <td>&#x00A8;x <!-- U+00A8: DIAERESIS -->
+ <td>&#x00A9;x <!-- U+00A9: COPYRIGHT SIGN -->
+ <td>&#x00AA;x <!-- U+00AA: FEMININE ORDINAL INDICATOR -->
+ <td>&#x00AB;x <!-- U+00AB: LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -->
+ <td>&#x00AC;x <!-- U+00AC: NOT SIGN -->
+ <td>&#x00AD;x <!-- U+00AD: SOFT HYPHEN -->
+ <td>&#x00AE;x <!-- U+00AE: REGISTERED SIGN -->
+ <td>&#x00AF;x <!-- U+00AF: MACRON -->
+ <td>&#x00B0;x <!-- U+00B0: DEGREE SIGN -->
+ <td>&#x00B1;x <!-- U+00B1: PLUS-MINUS SIGN -->
+ <td>&#x00B2;x <!-- U+00B2: SUPERSCRIPT TWO -->
+ <td>&#x00B3;x <!-- U+00B3: SUPERSCRIPT THREE -->
+ <td>&#x00B4;x <!-- U+00B4: ACUTE ACCENT -->
+ <td>&#x00B5;x <!-- U+00B5: MICRO SIGN -->
+ <td>&#x00B6;x <!-- U+00B6: PILCROW SIGN -->
+ <td>&#x00B7;x <!-- U+00B7: MIDDLE DOT -->
+ <td>&#x00B8;x <!-- U+00B8: CEDILLA -->
+ <tr>
+ <td>&#x00B9;x <!-- U+00B9: SUPERSCRIPT ONE -->
+ <td>&#x00BA;x <!-- U+00BA: MASCULINE ORDINAL INDICATOR -->
+ <td>&#x00BB;x <!-- U+00BB: RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -->
+ <td>&#x00BC;x <!-- U+00BC: VULGAR FRACTION ONE QUARTER -->
+ <td>&#x00BD;x <!-- U+00BD: VULGAR FRACTION ONE HALF -->
+ <td>&#x00BE;x <!-- U+00BE: VULGAR FRACTION THREE QUARTERS -->
+ <td>&#x00BF;x <!-- U+00BF: INVERTED QUESTION MARK -->
+ <td>&#x00C0;x <!-- U+00C0: LATIN CAPITAL LETTER A WITH GRAVE -->
+ <td>&#x00C1;x <!-- U+00C1: LATIN CAPITAL LETTER A WITH ACUTE -->
+ <td>&#x00C2;x <!-- U+00C2: LATIN CAPITAL LETTER A WITH CIRCUMFLEX -->
+ <td>&#x00C3;x <!-- U+00C3: LATIN CAPITAL LETTER A WITH TILDE -->
+ <td>&#x00C4;x <!-- U+00C4: LATIN CAPITAL LETTER A WITH DIAERESIS -->
+ <td>&#x00C5;x <!-- U+00C5: LATIN CAPITAL LETTER A WITH RING ABOVE -->
+ <td>&#x00C6;x <!-- U+00C6: LATIN CAPITAL LETTER AE -->
+ <td>&#x00C7;x <!-- U+00C7: LATIN CAPITAL LETTER C WITH CEDILLA -->
+ <td>&#x00C8;x <!-- U+00C8: LATIN CAPITAL LETTER E WITH GRAVE -->
+ <td>&#x00C9;x <!-- U+00C9: LATIN CAPITAL LETTER E WITH ACUTE -->
+ <tr>
+ <td>&#x00CA;x <!-- U+00CA: LATIN CAPITAL LETTER E WITH CIRCUMFLEX -->
+ <td>&#x00CB;x <!-- U+00CB: LATIN CAPITAL LETTER E WITH DIAERESIS -->
+ <td>&#x00CC;x <!-- U+00CC: LATIN CAPITAL LETTER I WITH GRAVE -->
+ <td>&#x00CD;x <!-- U+00CD: LATIN CAPITAL LETTER I WITH ACUTE -->
+ <td>&#x00CE;x <!-- U+00CE: LATIN CAPITAL LETTER I WITH CIRCUMFLEX -->
+ <td>&#x00CF;x <!-- U+00CF: LATIN CAPITAL LETTER I WITH DIAERESIS -->
+ <td>&#x00D0;x <!-- U+00D0: LATIN CAPITAL LETTER ETH -->
+ <td>&#x00D1;x <!-- U+00D1: LATIN CAPITAL LETTER N WITH TILDE -->
+ <td>&#x00D2;x <!-- U+00D2: LATIN CAPITAL LETTER O WITH GRAVE -->
+ <td>&#x00D3;x <!-- U+00D3: LATIN CAPITAL LETTER O WITH ACUTE -->
+ <td>&#x00D4;x <!-- U+00D4: LATIN CAPITAL LETTER O WITH CIRCUMFLEX -->
+ <td>&#x00D5;x <!-- U+00D5: LATIN CAPITAL LETTER O WITH TILDE -->
+ <td>&#x00D6;x <!-- U+00D6: LATIN CAPITAL LETTER O WITH DIAERESIS -->
+ <td>&#x00D7;x <!-- U+00D7: MULTIPLICATION SIGN -->
+ <td>&#x00D8;x <!-- U+00D8: LATIN CAPITAL LETTER O WITH STROKE -->
+ <td>&#x00D9;x <!-- U+00D9: LATIN CAPITAL LETTER U WITH GRAVE -->
+ <td>&#x00DA;x <!-- U+00DA: LATIN CAPITAL LETTER U WITH ACUTE -->
+ <tr>
+ <td>&#x00DB;x <!-- U+00DB: LATIN CAPITAL LETTER U WITH CIRCUMFLEX -->
+ <td>&#x00DC;x <!-- U+00DC: LATIN CAPITAL LETTER U WITH DIAERESIS -->
+ <td>&#x00DD;x <!-- U+00DD: LATIN CAPITAL LETTER Y WITH ACUTE -->
+ <td>&#x00DE;x <!-- U+00DE: LATIN CAPITAL LETTER THORN -->
+ <td>&#x00DF;x <!-- U+00DF: LATIN SMALL LETTER SHARP S -->
+ <td>&#x00E0;x <!-- U+00E0: LATIN SMALL LETTER A WITH GRAVE -->
+ <td>&#x00E1;x <!-- U+00E1: LATIN SMALL LETTER A WITH ACUTE -->
+ <td>&#x00E2;x <!-- U+00E2: LATIN SMALL LETTER A WITH CIRCUMFLEX -->
+ <td>&#x00E3;x <!-- U+00E3: LATIN SMALL LETTER A WITH TILDE -->
+ <td>&#x00E4;x <!-- U+00E4: LATIN SMALL LETTER A WITH DIAERESIS -->
+ <td>&#x00E5;x <!-- U+00E5: LATIN SMALL LETTER A WITH RING ABOVE -->
+ <td>&#x00E6;x <!-- U+00E6: LATIN SMALL LETTER AE -->
+ <td>&#x00E7;x <!-- U+00E7: LATIN SMALL LETTER C WITH CEDILLA -->
+ <td>&#x00E8;x <!-- U+00E8: LATIN SMALL LETTER E WITH GRAVE -->
+ <td>&#x00E9;x <!-- U+00E9: LATIN SMALL LETTER E WITH ACUTE -->
+ <td>&#x00EA;x <!-- U+00EA: LATIN SMALL LETTER E WITH CIRCUMFLEX -->
+ <td>&#x00EB;x <!-- U+00EB: LATIN SMALL LETTER E WITH DIAERESIS -->
+ <tr>
+ <td>&#x00EC;x <!-- U+00EC: LATIN SMALL LETTER I WITH GRAVE -->
+ <td>&#x00ED;x <!-- U+00ED: LATIN SMALL LETTER I WITH ACUTE -->
+ <td>&#x00EE;x <!-- U+00EE: LATIN SMALL LETTER I WITH CIRCUMFLEX -->
+ <td>&#x00EF;x <!-- U+00EF: LATIN SMALL LETTER I WITH DIAERESIS -->
+ <td>&#x00F0;x <!-- U+00F0: LATIN SMALL LETTER ETH -->
+ <td>&#x00F1;x <!-- U+00F1: LATIN SMALL LETTER N WITH TILDE -->
+ <td>&#x00F2;x <!-- U+00F2: LATIN SMALL LETTER O WITH GRAVE -->
+ <td>&#x00F3;x <!-- U+00F3: LATIN SMALL LETTER O WITH ACUTE -->
+ <td>&#x00F4;x <!-- U+00F4: LATIN SMALL LETTER O WITH CIRCUMFLEX -->
+ <td>&#x00F5;x <!-- U+00F5: LATIN SMALL LETTER O WITH TILDE -->
+ <td>&#x00F6;x <!-- U+00F6: LATIN SMALL LETTER O WITH DIAERESIS -->
+ <td>&#x00F7;x <!-- U+00F7: DIVISION SIGN -->
+ <td>&#x00F8;x <!-- U+00F8: LATIN SMALL LETTER O WITH STROKE -->
+ <td>&#x00F9;x <!-- U+00F9: LATIN SMALL LETTER U WITH GRAVE -->
+ <td>&#x00FA;x <!-- U+00FA: LATIN SMALL LETTER U WITH ACUTE -->
+ <td>&#x00FB;x <!-- U+00FB: LATIN SMALL LETTER U WITH CIRCUMFLEX -->
+ <td>&#x00FC;x <!-- U+00FC: LATIN SMALL LETTER U WITH DIAERESIS -->
+ <tr>
+ <td>&#x00FD;x <!-- U+00FD: LATIN SMALL LETTER Y WITH ACUTE -->
+ <td>&#x00FE;x <!-- U+00FE: LATIN SMALL LETTER THORN -->
+ <td>&#x00FF;x <!-- U+00FF: LATIN SMALL LETTER Y WITH DIAERESIS -->
+ <td>&#x0131;x <!-- U+0131: LATIN SMALL LETTER DOTLESS I -->
+ <td>&#x0152;x <!-- U+0152: LATIN CAPITAL LIGATURE OE -->
+ <td>&#x0153;x <!-- U+0153: LATIN SMALL LIGATURE OE -->
+ <td>&#x0178;x <!-- U+0178: LATIN CAPITAL LETTER Y WITH DIAERESIS -->
+ <td>&#x0192;x <!-- U+0192: LATIN SMALL LETTER F WITH HOOK -->
+ <td>&#x02C6;x <!-- U+02C6: MODIFIER LETTER CIRCUMFLEX ACCENT -->
+ <td>&#x02C7;x <!-- U+02C7: CARON -->
+ <td>&#x02C9;x <!-- U+02C9: MODIFIER LETTER MACRON -->
+ <td>&#x02D8;x <!-- U+02D8: BREVE -->
+ <td>&#x02D9;x <!-- U+02D9: DOT ABOVE -->
+ <td>&#x02DA;x <!-- U+02DA: RING ABOVE -->
+ <td>&#x02DB;x <!-- U+02DB: OGONEK -->
+ <td>&#x02DC;x <!-- U+02DC: SMALL TILDE -->
+ <td>&#x02DD;x <!-- U+02DD: DOUBLE ACUTE ACCENT -->
+ <tr>
+ <td>&#x0394;x <!-- U+0394: GREEK CAPITAL LETTER DELTA -->
+ <td>&#x03A5;x <!-- U+03A5: GREEK CAPITAL LETTER UPSILON -->
+ <td>&#x03A7;x <!-- U+03A7: GREEK CAPITAL LETTER CHI -->
+ <td>&#x03A9;x <!-- U+03A9: GREEK CAPITAL LETTER OMEGA -->
+ <td>&#x03BC;x <!-- U+03BC: GREEK SMALL LETTER MU -->
+ <td>&#x03C0;x <!-- U+03C0: GREEK SMALL LETTER PI -->
+ <td>&#x2002;x <!-- U+2002: EN SPACE -->
+ <td>&#x2003;x <!-- U+2003: EM SPACE -->
+ <td>&#x2004;x <!-- U+2004: THREE-PER-EM SPACE -->
+ <td>&#x2005;x <!-- U+2005: FOUR-PER-EM SPACE -->
+ <td>&#x2006;x <!-- U+2006: SIX-PER-EM SPACE -->
+ <td>&#x2009;x <!-- U+2009: THIN SPACE -->
+ <td>&#x200A;x <!-- U+200A: HAIR SPACE -->
+ <td>&#x200B;x <!-- U+200B: ZERO WIDTH SPACE -->
+ <td>&#x200C;x <!-- U+200C: ZERO WIDTH NON-JOINER -->
+ <td>&#x200D;x <!-- U+200D: ZERO WIDTH JOINER -->
+ <td>&#x2010;x <!-- U+2010: HYPHEN -->
+ <tr>
+ <td>&#x2013;x <!-- U+2013: EN DASH -->
+ <td>&#x2014;x <!-- U+2014: EM DASH -->
+ <td>&#x2018;x <!-- U+2018: LEFT SINGLE QUOTATION MARK -->
+ <td>&#x2019;x <!-- U+2019: RIGHT SINGLE QUOTATION MARK -->
+ <td>&#x201A;x <!-- U+201A: SINGLE LOW-9 QUOTATION MARK -->
+ <td>&#x201C;x <!-- U+201C: LEFT DOUBLE QUOTATION MARK -->
+ <td>&#x201D;x <!-- U+201D: RIGHT DOUBLE QUOTATION MARK -->
+ <td>&#x201E;x <!-- U+201E: DOUBLE LOW-9 QUOTATION MARK -->
+ <td>&#x2020;x <!-- U+2020: DAGGER -->
+ <td>&#x2021;x <!-- U+2021: DOUBLE DAGGER -->
+ <td>&#x2022;x <!-- U+2022: BULLET -->
+ <td>&#x2026;x <!-- U+2026: HORIZONTAL ELLIPSIS -->
+ <td>&#x2030;x <!-- U+2030: PER MILLE SIGN -->
+ <td>&#x2039;x <!-- U+2039: SINGLE LEFT-POINTING ANGLE QUOTATION MARK -->
+ <td>&#x203A;x <!-- U+203A: SINGLE RIGHT-POINTING ANGLE QUOTATION MARK -->
+ <td>&#x2044;x <!-- U+2044: FRACTION SLASH -->
+ <td>&#x2122;x <!-- U+2122: TRADE MARK SIGN -->
+ <tr>
+ <td>&#x2126;x <!-- U+2126: OHM SIGN -->
+ <td>&#x2202;x <!-- U+2202: PARTIAL DIFFERENTIAL -->
+ <td>&#x2206;x <!-- U+2206: INCREMENT -->
+ <td>&#x220F;x <!-- U+220F: N-ARY PRODUCT -->
+ <td>&#x2211;x <!-- U+2211: N-ARY SUMMATION -->
+ <td>&#x2212;x <!-- U+2212: MINUS SIGN -->
+ <td>&#x2219;x <!-- U+2219: BULLET OPERATOR -->
+ <td>&#x221A;x <!-- U+221A: SQUARE ROOT -->
+ <td>&#x221E;x <!-- U+221E: INFINITY -->
+ <td>&#x222B;x <!-- U+222B: INTEGRAL -->
+ <td>&#x2248;x <!-- U+2248: ALMOST EQUAL TO -->
+ <td>&#x2260;x <!-- U+2260: NOT EQUAL TO -->
+ <td>&#x2264;x <!-- U+2264: LESS-THAN OR EQUAL TO -->
+ <td>&#x2265;x <!-- U+2265: GREATER-THAN OR EQUAL TO -->
+ <td>&#x22F2;x <!-- U+22F2: ELEMENT OF WITH LONG HORIZONTAL STROKE -->
+ <td>&#x25CA;x <!-- U+25CA: LOZENGE -->
+ <td>&#x3000;x <!-- U+3000: IDEOGRAPHIC SPACE -->
+ <tr>
+ <td>&#x3007;x <!-- U+3007: IDEOGRAPHIC NUMBER ZERO -->
+ <td>&#x4E00;x <!-- U+4E00: CJK UNIFIED IDEOGRAPH-4E00 -->
+ <td>&#x4E03;x <!-- U+4E03: CJK UNIFIED IDEOGRAPH-4E03 -->
+ <td>&#x4E09;x <!-- U+4E09: CJK UNIFIED IDEOGRAPH-4E09 -->
+ <td>&#x4E5D;x <!-- U+4E5D: CJK UNIFIED IDEOGRAPH-4E5D -->
+ <td>&#x4E8C;x <!-- U+4E8C: CJK UNIFIED IDEOGRAPH-4E8C -->
+ <td>&#x4E94;x <!-- U+4E94: CJK UNIFIED IDEOGRAPH-4E94 -->
+ <td>&#x516B;x <!-- U+516B: CJK UNIFIED IDEOGRAPH-516B -->
+ <td>&#x516D;x <!-- U+516D: CJK UNIFIED IDEOGRAPH-516D -->
+ <td>&#x5341;x <!-- U+5341: CJK UNIFIED IDEOGRAPH-5341 -->
+ <td>&#x56D7;x <!-- U+56D7: CJK UNIFIED IDEOGRAPH-56D7 -->
+ <td>&#x56DB;x <!-- U+56DB: CJK UNIFIED IDEOGRAPH-56DB -->
+ <td>&#x571F;x <!-- U+571F: CJK UNIFIED IDEOGRAPH-571F -->
+ <td>&#x6728;x <!-- U+6728: CJK UNIFIED IDEOGRAPH-6728 -->
+ <td>&#x6A2A;x <!-- U+6A2A: CJK UNIFIED IDEOGRAPH-6A2A -->
+ <td>&#x6C34;x <!-- U+6C34: CJK UNIFIED IDEOGRAPH-6C34 -->
+ <td>&#x706B;x <!-- U+706B: CJK UNIFIED IDEOGRAPH-706B -->
+ <tr>
+ <td>&#x7EB5;x <!-- U+7EB5: CJK UNIFIED IDEOGRAPH-7EB5 -->
+ <td>&#x91D1;x <!-- U+91D1: CJK UNIFIED IDEOGRAPH-91D1 -->
+ <td>&#xF000;x <!-- U+F000 -->
+ <td>&#xF001;x <!-- U+F001 -->
+ <td>&#xF002;x <!-- U+F002 -->
+ <td>&#xFEFF;x <!-- U+FEFF: ZERO WIDTH NO-BREAK SPACE -->
+</table>
diff --git a/testing/web-platform/tests/infrastructure/assumptions/ahem.html b/testing/web-platform/tests/infrastructure/assumptions/ahem.html
new file mode 100644
index 0000000000..068c1d4dee
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/assumptions/ahem.html
@@ -0,0 +1,316 @@
+<!doctype html>
+<title>Ahem checker</title>
+<link rel="match" href="ahem-ref.html">
+<style>
+* {
+ padding: 0;
+ margin: 0;
+ border: none;
+}
+td {
+ width: 34px;
+}
+table {
+ font: 15px/1 Ahem;
+ border-collapse: separate;
+ border-spacing: 1px;
+ table-layout: fixed;
+}
+</style>
+<table>
+ <tr>
+ <td>&#x0020;x <!-- U+0020: SPACE -->
+ <td>&#x0021;x <!-- U+0021: EXCLAMATION MARK -->
+ <td>&#x0022;x <!-- U+0022: QUOTATION MARK -->
+ <td>&#x0023;x <!-- U+0023: NUMBER SIGN -->
+ <td>&#x0024;x <!-- U+0024: DOLLAR SIGN -->
+ <td>&#x0025;x <!-- U+0025: PERCENT SIGN -->
+ <td>&#x0026;x <!-- U+0026: AMPERSAND -->
+ <td>&#x0028;x <!-- U+0028: LEFT PARENTHESIS -->
+ <td>&#x0029;x <!-- U+0029: RIGHT PARENTHESIS -->
+ <td>&#x002A;x <!-- U+002A: ASTERISK -->
+ <td>&#x002B;x <!-- U+002B: PLUS SIGN -->
+ <td>&#x002C;x <!-- U+002C: COMMA -->
+ <td>&#x002D;x <!-- U+002D: HYPHEN-MINUS -->
+ <td>&#x002E;x <!-- U+002E: FULL STOP -->
+ <td>&#x002F;x <!-- U+002F: SOLIDUS -->
+ <td>&#x0030;x <!-- U+0030: DIGIT ZERO -->
+ <td>&#x0031;x <!-- U+0031: DIGIT ONE -->
+ <tr>
+ <td>&#x0032;x <!-- U+0032: DIGIT TWO -->
+ <td>&#x0033;x <!-- U+0033: DIGIT THREE -->
+ <td>&#x0034;x <!-- U+0034: DIGIT FOUR -->
+ <td>&#x0035;x <!-- U+0035: DIGIT FIVE -->
+ <td>&#x0036;x <!-- U+0036: DIGIT SIX -->
+ <td>&#x0037;x <!-- U+0037: DIGIT SEVEN -->
+ <td>&#x0038;x <!-- U+0038: DIGIT EIGHT -->
+ <td>&#x0039;x <!-- U+0039: DIGIT NINE -->
+ <td>&#x003A;x <!-- U+003A: COLON -->
+ <td>&#x003B;x <!-- U+003B: SEMICOLON -->
+ <td>&#x003C;x <!-- U+003C: LESS-THAN SIGN -->
+ <td>&#x003D;x <!-- U+003D: EQUALS SIGN -->
+ <td>&#x003E;x <!-- U+003E: GREATER-THAN SIGN -->
+ <td>&#x003F;x <!-- U+003F: QUESTION MARK -->
+ <td>&#x0040;x <!-- U+0040: COMMERCIAL AT -->
+ <td>&#x0041;x <!-- U+0041: LATIN CAPITAL LETTER A -->
+ <td>&#x0042;x <!-- U+0042: LATIN CAPITAL LETTER B -->
+ <tr>
+ <td>&#x0043;x <!-- U+0043: LATIN CAPITAL LETTER C -->
+ <td>&#x0044;x <!-- U+0044: LATIN CAPITAL LETTER D -->
+ <td>&#x0045;x <!-- U+0045: LATIN CAPITAL LETTER E -->
+ <td>&#x0046;x <!-- U+0046: LATIN CAPITAL LETTER F -->
+ <td>&#x0047;x <!-- U+0047: LATIN CAPITAL LETTER G -->
+ <td>&#x0048;x <!-- U+0048: LATIN CAPITAL LETTER H -->
+ <td>&#x0049;x <!-- U+0049: LATIN CAPITAL LETTER I -->
+ <td>&#x004A;x <!-- U+004A: LATIN CAPITAL LETTER J -->
+ <td>&#x004B;x <!-- U+004B: LATIN CAPITAL LETTER K -->
+ <td>&#x004C;x <!-- U+004C: LATIN CAPITAL LETTER L -->
+ <td>&#x004D;x <!-- U+004D: LATIN CAPITAL LETTER M -->
+ <td>&#x004E;x <!-- U+004E: LATIN CAPITAL LETTER N -->
+ <td>&#x004F;x <!-- U+004F: LATIN CAPITAL LETTER O -->
+ <td>&#x0050;x <!-- U+0050: LATIN CAPITAL LETTER P -->
+ <td>&#x0051;x <!-- U+0051: LATIN CAPITAL LETTER Q -->
+ <td>&#x0052;x <!-- U+0052: LATIN CAPITAL LETTER R -->
+ <td>&#x0053;x <!-- U+0053: LATIN CAPITAL LETTER S -->
+ <tr>
+ <td>&#x0054;x <!-- U+0054: LATIN CAPITAL LETTER T -->
+ <td>&#x0055;x <!-- U+0055: LATIN CAPITAL LETTER U -->
+ <td>&#x0056;x <!-- U+0056: LATIN CAPITAL LETTER V -->
+ <td>&#x0057;x <!-- U+0057: LATIN CAPITAL LETTER W -->
+ <td>&#x0058;x <!-- U+0058: LATIN CAPITAL LETTER X -->
+ <td>&#x0059;x <!-- U+0059: LATIN CAPITAL LETTER Y -->
+ <td>&#x005A;x <!-- U+005A: LATIN CAPITAL LETTER Z -->
+ <td>&#x005B;x <!-- U+005B: LEFT SQUARE BRACKET -->
+ <td>&#x005C;x <!-- U+005C: REVERSE SOLIDUS -->
+ <td>&#x005D;x <!-- U+005D: RIGHT SQUARE BRACKET -->
+ <td>&#x005E;x <!-- U+005E: CIRCUMFLEX ACCENT -->
+ <td>&#x005F;x <!-- U+005F: LOW LINE -->
+ <td>&#x0060;x <!-- U+0060: GRAVE ACCENT -->
+ <td>&#x0061;x <!-- U+0061: LATIN SMALL LETTER A -->
+ <td>&#x0062;x <!-- U+0062: LATIN SMALL LETTER B -->
+ <td>&#x0063;x <!-- U+0063: LATIN SMALL LETTER C -->
+ <td>&#x0064;x <!-- U+0064: LATIN SMALL LETTER D -->
+ <tr>
+ <td>&#x0065;x <!-- U+0065: LATIN SMALL LETTER E -->
+ <td>&#x0066;x <!-- U+0066: LATIN SMALL LETTER F -->
+ <td>&#x0067;x <!-- U+0067: LATIN SMALL LETTER G -->
+ <td>&#x0068;x <!-- U+0068: LATIN SMALL LETTER H -->
+ <td>&#x0069;x <!-- U+0069: LATIN SMALL LETTER I -->
+ <td>&#x006A;x <!-- U+006A: LATIN SMALL LETTER J -->
+ <td>&#x006B;x <!-- U+006B: LATIN SMALL LETTER K -->
+ <td>&#x006C;x <!-- U+006C: LATIN SMALL LETTER L -->
+ <td>&#x006D;x <!-- U+006D: LATIN SMALL LETTER M -->
+ <td>&#x006E;x <!-- U+006E: LATIN SMALL LETTER N -->
+ <td>&#x006F;x <!-- U+006F: LATIN SMALL LETTER O -->
+ <td>&#x0070;x <!-- U+0070: LATIN SMALL LETTER P -->
+ <td>&#x0071;x <!-- U+0071: LATIN SMALL LETTER Q -->
+ <td>&#x0072;x <!-- U+0072: LATIN SMALL LETTER R -->
+ <td>&#x0073;x <!-- U+0073: LATIN SMALL LETTER S -->
+ <td>&#x0074;x <!-- U+0074: LATIN SMALL LETTER T -->
+ <td>&#x0075;x <!-- U+0075: LATIN SMALL LETTER U -->
+ <tr>
+ <td>&#x0076;x <!-- U+0076: LATIN SMALL LETTER V -->
+ <td>&#x0077;x <!-- U+0077: LATIN SMALL LETTER W -->
+ <td>&#x0078;x <!-- U+0078: LATIN SMALL LETTER X -->
+ <td>&#x0079;x <!-- U+0079: LATIN SMALL LETTER Y -->
+ <td>&#x007A;x <!-- U+007A: LATIN SMALL LETTER Z -->
+ <td>&#x007B;x <!-- U+007B: LEFT CURLY BRACKET -->
+ <td>&#x007C;x <!-- U+007C: VERTICAL LINE -->
+ <td>&#x007D;x <!-- U+007D: RIGHT CURLY BRACKET -->
+ <td>&#x007E;x <!-- U+007E: TILDE -->
+ <td>&#x00A0;x <!-- U+00A0: NO-BREAK SPACE -->
+ <td>&#x00A1;x <!-- U+00A1: INVERTED EXCLAMATION MARK -->
+ <td>&#x00A2;x <!-- U+00A2: CENT SIGN -->
+ <td>&#x00A3;x <!-- U+00A3: POUND SIGN -->
+ <td>&#x00A4;x <!-- U+00A4: CURRENCY SIGN -->
+ <td>&#x00A5;x <!-- U+00A5: YEN SIGN -->
+ <td>&#x00A6;x <!-- U+00A6: BROKEN BAR -->
+ <td>&#x00A7;x <!-- U+00A7: SECTION SIGN -->
+ <tr>
+ <td>&#x00A8;x <!-- U+00A8: DIAERESIS -->
+ <td>&#x00A9;x <!-- U+00A9: COPYRIGHT SIGN -->
+ <td>&#x00AA;x <!-- U+00AA: FEMININE ORDINAL INDICATOR -->
+ <td>&#x00AB;x <!-- U+00AB: LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -->
+ <td>&#x00AC;x <!-- U+00AC: NOT SIGN -->
+ <td>&#x00AD;x <!-- U+00AD: SOFT HYPHEN -->
+ <td>&#x00AE;x <!-- U+00AE: REGISTERED SIGN -->
+ <td>&#x00AF;x <!-- U+00AF: MACRON -->
+ <td>&#x00B0;x <!-- U+00B0: DEGREE SIGN -->
+ <td>&#x00B1;x <!-- U+00B1: PLUS-MINUS SIGN -->
+ <td>&#x00B2;x <!-- U+00B2: SUPERSCRIPT TWO -->
+ <td>&#x00B3;x <!-- U+00B3: SUPERSCRIPT THREE -->
+ <td>&#x00B4;x <!-- U+00B4: ACUTE ACCENT -->
+ <td>&#x00B5;x <!-- U+00B5: MICRO SIGN -->
+ <td>&#x00B6;x <!-- U+00B6: PILCROW SIGN -->
+ <td>&#x00B7;x <!-- U+00B7: MIDDLE DOT -->
+ <td>&#x00B8;x <!-- U+00B8: CEDILLA -->
+ <tr>
+ <td>&#x00B9;x <!-- U+00B9: SUPERSCRIPT ONE -->
+ <td>&#x00BA;x <!-- U+00BA: MASCULINE ORDINAL INDICATOR -->
+ <td>&#x00BB;x <!-- U+00BB: RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -->
+ <td>&#x00BC;x <!-- U+00BC: VULGAR FRACTION ONE QUARTER -->
+ <td>&#x00BD;x <!-- U+00BD: VULGAR FRACTION ONE HALF -->
+ <td>&#x00BE;x <!-- U+00BE: VULGAR FRACTION THREE QUARTERS -->
+ <td>&#x00BF;x <!-- U+00BF: INVERTED QUESTION MARK -->
+ <td>&#x00C0;x <!-- U+00C0: LATIN CAPITAL LETTER A WITH GRAVE -->
+ <td>&#x00C1;x <!-- U+00C1: LATIN CAPITAL LETTER A WITH ACUTE -->
+ <td>&#x00C2;x <!-- U+00C2: LATIN CAPITAL LETTER A WITH CIRCUMFLEX -->
+ <td>&#x00C3;x <!-- U+00C3: LATIN CAPITAL LETTER A WITH TILDE -->
+ <td>&#x00C4;x <!-- U+00C4: LATIN CAPITAL LETTER A WITH DIAERESIS -->
+ <td>&#x00C5;x <!-- U+00C5: LATIN CAPITAL LETTER A WITH RING ABOVE -->
+ <td>&#x00C6;x <!-- U+00C6: LATIN CAPITAL LETTER AE -->
+ <td>&#x00C7;x <!-- U+00C7: LATIN CAPITAL LETTER C WITH CEDILLA -->
+ <td>&#x00C8;x <!-- U+00C8: LATIN CAPITAL LETTER E WITH GRAVE -->
+ <td>&#x00C9;x <!-- U+00C9: LATIN CAPITAL LETTER E WITH ACUTE -->
+ <tr>
+ <td>&#x00CA;x <!-- U+00CA: LATIN CAPITAL LETTER E WITH CIRCUMFLEX -->
+ <td>&#x00CB;x <!-- U+00CB: LATIN CAPITAL LETTER E WITH DIAERESIS -->
+ <td>&#x00CC;x <!-- U+00CC: LATIN CAPITAL LETTER I WITH GRAVE -->
+ <td>&#x00CD;x <!-- U+00CD: LATIN CAPITAL LETTER I WITH ACUTE -->
+ <td>&#x00CE;x <!-- U+00CE: LATIN CAPITAL LETTER I WITH CIRCUMFLEX -->
+ <td>&#x00CF;x <!-- U+00CF: LATIN CAPITAL LETTER I WITH DIAERESIS -->
+ <td>&#x00D0;x <!-- U+00D0: LATIN CAPITAL LETTER ETH -->
+ <td>&#x00D1;x <!-- U+00D1: LATIN CAPITAL LETTER N WITH TILDE -->
+ <td>&#x00D2;x <!-- U+00D2: LATIN CAPITAL LETTER O WITH GRAVE -->
+ <td>&#x00D3;x <!-- U+00D3: LATIN CAPITAL LETTER O WITH ACUTE -->
+ <td>&#x00D4;x <!-- U+00D4: LATIN CAPITAL LETTER O WITH CIRCUMFLEX -->
+ <td>&#x00D5;x <!-- U+00D5: LATIN CAPITAL LETTER O WITH TILDE -->
+ <td>&#x00D6;x <!-- U+00D6: LATIN CAPITAL LETTER O WITH DIAERESIS -->
+ <td>&#x00D7;x <!-- U+00D7: MULTIPLICATION SIGN -->
+ <td>&#x00D8;x <!-- U+00D8: LATIN CAPITAL LETTER O WITH STROKE -->
+ <td>&#x00D9;x <!-- U+00D9: LATIN CAPITAL LETTER U WITH GRAVE -->
+ <td>&#x00DA;x <!-- U+00DA: LATIN CAPITAL LETTER U WITH ACUTE -->
+ <tr>
+ <td>&#x00DB;x <!-- U+00DB: LATIN CAPITAL LETTER U WITH CIRCUMFLEX -->
+ <td>&#x00DC;x <!-- U+00DC: LATIN CAPITAL LETTER U WITH DIAERESIS -->
+ <td>&#x00DD;x <!-- U+00DD: LATIN CAPITAL LETTER Y WITH ACUTE -->
+ <td>&#x00DE;x <!-- U+00DE: LATIN CAPITAL LETTER THORN -->
+ <td>&#x00DF;x <!-- U+00DF: LATIN SMALL LETTER SHARP S -->
+ <td>&#x00E0;x <!-- U+00E0: LATIN SMALL LETTER A WITH GRAVE -->
+ <td>&#x00E1;x <!-- U+00E1: LATIN SMALL LETTER A WITH ACUTE -->
+ <td>&#x00E2;x <!-- U+00E2: LATIN SMALL LETTER A WITH CIRCUMFLEX -->
+ <td>&#x00E3;x <!-- U+00E3: LATIN SMALL LETTER A WITH TILDE -->
+ <td>&#x00E4;x <!-- U+00E4: LATIN SMALL LETTER A WITH DIAERESIS -->
+ <td>&#x00E5;x <!-- U+00E5: LATIN SMALL LETTER A WITH RING ABOVE -->
+ <td>&#x00E6;x <!-- U+00E6: LATIN SMALL LETTER AE -->
+ <td>&#x00E7;x <!-- U+00E7: LATIN SMALL LETTER C WITH CEDILLA -->
+ <td>&#x00E8;x <!-- U+00E8: LATIN SMALL LETTER E WITH GRAVE -->
+ <td>&#x00E9;x <!-- U+00E9: LATIN SMALL LETTER E WITH ACUTE -->
+ <td>&#x00EA;x <!-- U+00EA: LATIN SMALL LETTER E WITH CIRCUMFLEX -->
+ <td>&#x00EB;x <!-- U+00EB: LATIN SMALL LETTER E WITH DIAERESIS -->
+ <tr>
+ <td>&#x00EC;x <!-- U+00EC: LATIN SMALL LETTER I WITH GRAVE -->
+ <td>&#x00ED;x <!-- U+00ED: LATIN SMALL LETTER I WITH ACUTE -->
+ <td>&#x00EE;x <!-- U+00EE: LATIN SMALL LETTER I WITH CIRCUMFLEX -->
+ <td>&#x00EF;x <!-- U+00EF: LATIN SMALL LETTER I WITH DIAERESIS -->
+ <td>&#x00F0;x <!-- U+00F0: LATIN SMALL LETTER ETH -->
+ <td>&#x00F1;x <!-- U+00F1: LATIN SMALL LETTER N WITH TILDE -->
+ <td>&#x00F2;x <!-- U+00F2: LATIN SMALL LETTER O WITH GRAVE -->
+ <td>&#x00F3;x <!-- U+00F3: LATIN SMALL LETTER O WITH ACUTE -->
+ <td>&#x00F4;x <!-- U+00F4: LATIN SMALL LETTER O WITH CIRCUMFLEX -->
+ <td>&#x00F5;x <!-- U+00F5: LATIN SMALL LETTER O WITH TILDE -->
+ <td>&#x00F6;x <!-- U+00F6: LATIN SMALL LETTER O WITH DIAERESIS -->
+ <td>&#x00F7;x <!-- U+00F7: DIVISION SIGN -->
+ <td>&#x00F8;x <!-- U+00F8: LATIN SMALL LETTER O WITH STROKE -->
+ <td>&#x00F9;x <!-- U+00F9: LATIN SMALL LETTER U WITH GRAVE -->
+ <td>&#x00FA;x <!-- U+00FA: LATIN SMALL LETTER U WITH ACUTE -->
+ <td>&#x00FB;x <!-- U+00FB: LATIN SMALL LETTER U WITH CIRCUMFLEX -->
+ <td>&#x00FC;x <!-- U+00FC: LATIN SMALL LETTER U WITH DIAERESIS -->
+ <tr>
+ <td>&#x00FD;x <!-- U+00FD: LATIN SMALL LETTER Y WITH ACUTE -->
+ <td>&#x00FE;x <!-- U+00FE: LATIN SMALL LETTER THORN -->
+ <td>&#x00FF;x <!-- U+00FF: LATIN SMALL LETTER Y WITH DIAERESIS -->
+ <td>&#x0131;x <!-- U+0131: LATIN SMALL LETTER DOTLESS I -->
+ <td>&#x0152;x <!-- U+0152: LATIN CAPITAL LIGATURE OE -->
+ <td>&#x0153;x <!-- U+0153: LATIN SMALL LIGATURE OE -->
+ <td>&#x0178;x <!-- U+0178: LATIN CAPITAL LETTER Y WITH DIAERESIS -->
+ <td>&#x0192;x <!-- U+0192: LATIN SMALL LETTER F WITH HOOK -->
+ <td>&#x02C6;x <!-- U+02C6: MODIFIER LETTER CIRCUMFLEX ACCENT -->
+ <td>&#x02C7;x <!-- U+02C7: CARON -->
+ <td>&#x02C9;x <!-- U+02C9: MODIFIER LETTER MACRON -->
+ <td>&#x02D8;x <!-- U+02D8: BREVE -->
+ <td>&#x02D9;x <!-- U+02D9: DOT ABOVE -->
+ <td>&#x02DA;x <!-- U+02DA: RING ABOVE -->
+ <td>&#x02DB;x <!-- U+02DB: OGONEK -->
+ <td>&#x02DC;x <!-- U+02DC: SMALL TILDE -->
+ <td>&#x02DD;x <!-- U+02DD: DOUBLE ACUTE ACCENT -->
+ <tr>
+ <td>&#x0394;x <!-- U+0394: GREEK CAPITAL LETTER DELTA -->
+ <td>&#x03A5;x <!-- U+03A5: GREEK CAPITAL LETTER UPSILON -->
+ <td>&#x03A7;x <!-- U+03A7: GREEK CAPITAL LETTER CHI -->
+ <td>&#x03A9;x <!-- U+03A9: GREEK CAPITAL LETTER OMEGA -->
+ <td>&#x03BC;x <!-- U+03BC: GREEK SMALL LETTER MU -->
+ <td>&#x03C0;x <!-- U+03C0: GREEK SMALL LETTER PI -->
+ <td>&#x2002;x <!-- U+2002: EN SPACE -->
+ <td>&#x2003;x <!-- U+2003: EM SPACE -->
+ <td>&#x2004;x <!-- U+2004: THREE-PER-EM SPACE -->
+ <td>&#x2005;x <!-- U+2005: FOUR-PER-EM SPACE -->
+ <td>&#x2006;x <!-- U+2006: SIX-PER-EM SPACE -->
+ <td>&#x2009;x <!-- U+2009: THIN SPACE -->
+ <td>&#x200A;x <!-- U+200A: HAIR SPACE -->
+ <td>&#x200B;x <!-- U+200B: ZERO WIDTH SPACE -->
+ <td>&#x200C;x <!-- U+200C: ZERO WIDTH NON-JOINER -->
+ <td>&#x200D;x <!-- U+200D: ZERO WIDTH JOINER -->
+ <td>&#x2010;x <!-- U+2010: HYPHEN -->
+ <tr>
+ <td>&#x2013;x <!-- U+2013: EN DASH -->
+ <td>&#x2014;x <!-- U+2014: EM DASH -->
+ <td>&#x2018;x <!-- U+2018: LEFT SINGLE QUOTATION MARK -->
+ <td>&#x2019;x <!-- U+2019: RIGHT SINGLE QUOTATION MARK -->
+ <td>&#x201A;x <!-- U+201A: SINGLE LOW-9 QUOTATION MARK -->
+ <td>&#x201C;x <!-- U+201C: LEFT DOUBLE QUOTATION MARK -->
+ <td>&#x201D;x <!-- U+201D: RIGHT DOUBLE QUOTATION MARK -->
+ <td>&#x201E;x <!-- U+201E: DOUBLE LOW-9 QUOTATION MARK -->
+ <td>&#x2020;x <!-- U+2020: DAGGER -->
+ <td>&#x2021;x <!-- U+2021: DOUBLE DAGGER -->
+ <td>&#x2022;x <!-- U+2022: BULLET -->
+ <td>&#x2026;x <!-- U+2026: HORIZONTAL ELLIPSIS -->
+ <td>&#x2030;x <!-- U+2030: PER MILLE SIGN -->
+ <td>&#x2039;x <!-- U+2039: SINGLE LEFT-POINTING ANGLE QUOTATION MARK -->
+ <td>&#x203A;x <!-- U+203A: SINGLE RIGHT-POINTING ANGLE QUOTATION MARK -->
+ <td>&#x2044;x <!-- U+2044: FRACTION SLASH -->
+ <td>&#x2122;x <!-- U+2122: TRADE MARK SIGN -->
+ <tr>
+ <td>&#x2126;x <!-- U+2126: OHM SIGN -->
+ <td>&#x2202;x <!-- U+2202: PARTIAL DIFFERENTIAL -->
+ <td>&#x2206;x <!-- U+2206: INCREMENT -->
+ <td>&#x220F;x <!-- U+220F: N-ARY PRODUCT -->
+ <td>&#x2211;x <!-- U+2211: N-ARY SUMMATION -->
+ <td>&#x2212;x <!-- U+2212: MINUS SIGN -->
+ <td>&#x2219;x <!-- U+2219: BULLET OPERATOR -->
+ <td>&#x221A;x <!-- U+221A: SQUARE ROOT -->
+ <td>&#x221E;x <!-- U+221E: INFINITY -->
+ <td>&#x222B;x <!-- U+222B: INTEGRAL -->
+ <td>&#x2248;x <!-- U+2248: ALMOST EQUAL TO -->
+ <td>&#x2260;x <!-- U+2260: NOT EQUAL TO -->
+ <td>&#x2264;x <!-- U+2264: LESS-THAN OR EQUAL TO -->
+ <td>&#x2265;x <!-- U+2265: GREATER-THAN OR EQUAL TO -->
+ <td>&#x22F2;x <!-- U+22F2: ELEMENT OF WITH LONG HORIZONTAL STROKE -->
+ <td>&#x25CA;x <!-- U+25CA: LOZENGE -->
+ <td>&#x3000;x <!-- U+3000: IDEOGRAPHIC SPACE -->
+ <tr>
+ <td>&#x3007;x <!-- U+3007: IDEOGRAPHIC NUMBER ZERO -->
+ <td>&#x4E00;x <!-- U+4E00: CJK UNIFIED IDEOGRAPH-4E00 -->
+ <td>&#x4E03;x <!-- U+4E03: CJK UNIFIED IDEOGRAPH-4E03 -->
+ <td>&#x4E09;x <!-- U+4E09: CJK UNIFIED IDEOGRAPH-4E09 -->
+ <td>&#x4E5D;x <!-- U+4E5D: CJK UNIFIED IDEOGRAPH-4E5D -->
+ <td>&#x4E8C;x <!-- U+4E8C: CJK UNIFIED IDEOGRAPH-4E8C -->
+ <td>&#x4E94;x <!-- U+4E94: CJK UNIFIED IDEOGRAPH-4E94 -->
+ <td>&#x516B;x <!-- U+516B: CJK UNIFIED IDEOGRAPH-516B -->
+ <td>&#x516D;x <!-- U+516D: CJK UNIFIED IDEOGRAPH-516D -->
+ <td>&#x5341;x <!-- U+5341: CJK UNIFIED IDEOGRAPH-5341 -->
+ <td>&#x56D7;x <!-- U+56D7: CJK UNIFIED IDEOGRAPH-56D7 -->
+ <td>&#x56DB;x <!-- U+56DB: CJK UNIFIED IDEOGRAPH-56DB -->
+ <td>&#x571F;x <!-- U+571F: CJK UNIFIED IDEOGRAPH-571F -->
+ <td>&#x6728;x <!-- U+6728: CJK UNIFIED IDEOGRAPH-6728 -->
+ <td>&#x6A2A;x <!-- U+6A2A: CJK UNIFIED IDEOGRAPH-6A2A -->
+ <td>&#x6C34;x <!-- U+6C34: CJK UNIFIED IDEOGRAPH-6C34 -->
+ <td>&#x706B;x <!-- U+706B: CJK UNIFIED IDEOGRAPH-706B -->
+ <tr>
+ <td>&#x7EB5;x <!-- U+7EB5: CJK UNIFIED IDEOGRAPH-7EB5 -->
+ <td>&#x91D1;x <!-- U+91D1: CJK UNIFIED IDEOGRAPH-91D1 -->
+ <td>&#xF000;x <!-- U+F000 -->
+ <td>&#xF001;x <!-- U+F001 -->
+ <td>&#xF002;x <!-- U+F002 -->
+ <td>&#xFEFF;x <!-- U+FEFF: ZERO WIDTH NO-BREAK SPACE -->
+</table>
diff --git a/testing/web-platform/tests/infrastructure/assumptions/allowed-to-play.html b/testing/web-platform/tests/infrastructure/assumptions/allowed-to-play.html
new file mode 100644
index 0000000000..bfa5729371
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/assumptions/allowed-to-play.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<title>&lt;audio and &lt;video> autoplay</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/media.html#dom-media-play">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/media.js"></script>
+<video></video>
+<script>
+async_test(t => {
+ const a = new Audio(getAudioURI("/media/sound_5"));
+ a.play();
+ assert_false(a.paused);
+ a.onplaying = t.step_func_done();
+}, "<audio> autoplay");
+
+async_test(t => {
+ const v = document.querySelector("video");
+ v.src = getVideoURI("/media/movie_5");
+ v.play();
+ assert_false(v.paused);
+ v.onplaying = t.step_func_done();
+}, "<video> autoplay");
+</script>
diff --git a/testing/web-platform/tests/infrastructure/assumptions/blank.html b/testing/web-platform/tests/infrastructure/assumptions/blank.html
new file mode 100644
index 0000000000..6d8da5e89c
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/assumptions/blank.html
@@ -0,0 +1,2 @@
+<title>Blank Document</title>
+<link rel=match href="about:blank">
diff --git a/testing/web-platform/tests/infrastructure/assumptions/canvas-background-ref.html b/testing/web-platform/tests/infrastructure/assumptions/canvas-background-ref.html
new file mode 100644
index 0000000000..b117f6b300
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/assumptions/canvas-background-ref.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<title>canvas background reference</title>
+<style>
+html {
+ background: white;
+}
+</style>
+<p>The background should be white
diff --git a/testing/web-platform/tests/infrastructure/assumptions/canvas-background.html b/testing/web-platform/tests/infrastructure/assumptions/canvas-background.html
new file mode 100644
index 0000000000..962edf5e8b
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/assumptions/canvas-background.html
@@ -0,0 +1,4 @@
+<!doctype html>
+<title>Check canvas background is white</title>
+<link rel="match" href="canvas-background-ref.html">
+<p>The background should be white
diff --git a/testing/web-platform/tests/infrastructure/assumptions/cookie.html b/testing/web-platform/tests/infrastructure/assumptions/cookie.html
new file mode 100644
index 0000000000..5d5b0dc0e1
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/assumptions/cookie.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<title>cookies work in default browse settings</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="help" href="https://html.spec.whatwg.org/#dom-document-cookie">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+ test(t => {
+ t.add_cleanup(() => {
+ let date = new Date();
+ date.setTime(date.getTime() - 10000);
+ document.cookie = "name=''; expires=" + date.toGMTString();
+ });
+ document.cookie = "name=test_cookie";
+ assert_not_equals(document.cookie.match(/name=test_cookie/), null);
+ });
+</script>
diff --git a/testing/web-platform/tests/infrastructure/assumptions/document-fonts-ready.html b/testing/web-platform/tests/infrastructure/assumptions/document-fonts-ready.html
new file mode 100644
index 0000000000..9fb0137025
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/assumptions/document-fonts-ready.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<title>document.fonts.ready resolves after layout depending on loaded fonts</title>
+<link rel="help" href="https://drafts.csswg.org/css-font-loading/#fontfaceset-pending-on-the-environment">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ #foo {
+ font: 100px/1 Ahem;
+ }
+</style>
+<div id="log"></div>
+<span id="foo">X</span>
+<script>
+ // The purpose of this test is to ensure that testharness.js tests can use
+ // `document.fonts.ready` to wait for a web font to load, without having to
+ // wait for the window load event before or requestAnimationFrame after.
+ //
+ // The spec says that a FontFaceSet is "pending on the environment" if "the
+ // document has pending layout operations which might cause the user agent to
+ // request a font, or which depend on recently-loaded fonts", and both are
+ // assumed to hold true in this test.
+ async_test(t => {
+ assert_equals(document.fonts.size, 1, 'one font is pending');
+ document.fonts.ready.then(t.step_func_done(() => {
+ const span = document.getElementById('foo');
+ const rect = span.getBoundingClientRect();
+ // If Ahem has loaded, the X will be 100px wide.
+ assert_equals(rect.width, 100, 'span is 100px wide');
+ }));
+ });
+</script>
diff --git a/testing/web-platform/tests/infrastructure/assumptions/html-elements.html b/testing/web-platform/tests/infrastructure/assumptions/html-elements.html
new file mode 100644
index 0000000000..3fe3d201ff
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/assumptions/html-elements.html
@@ -0,0 +1,133 @@
+<!doctype html>
+<title>HTML styles</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+#parent {
+ display: none;
+}
+
+div.b {
+ all: initial;
+ direction: initial;
+ unicode-bidi: isolate;
+ display: block;
+}
+
+div.c {
+ background: red;
+ background: initial;
+}
+
+span.b {
+ all: initial;
+ direction: initial;
+ unicode-bidi: initial;
+ display: inline;
+}
+</style>
+<div id="parent">
+ <div class="a"></div>
+ <div class="b"></div>
+ <div class="c"></div>
+ <span class="a"></span>
+ <span class="b"></span>
+ <p></p>
+ <ul>
+ <li>
+ </ul>
+ <ol>
+ <li>
+ </ol>
+ <table>
+ <tbody>
+ <tr>
+ <td>
+ </table>
+</div>
+<script>
+test(function() {
+ assert_true('all' in document.documentElement.style);
+}, "(pre-req for comparison tests) all CSS short-hand supported");
+
+test(function() {
+ assert_in_array(window.getComputedStyle(document.querySelector("div.c")).backgroundColor,
+ ["rgba(0, 0, 0, 0)", "transparent"]);
+}, "(pre-req for comparison tests) initial CSS value supported");
+
+test(function() {
+ var a = document.querySelector("div.a");
+ var b = document.querySelector("div.b");
+
+ var a_styles = window.getComputedStyle(a);
+ var b_styles = window.getComputedStyle(b);
+
+ assert_equals(a_styles.length, b_styles.length, "Same properties on both div.a and div.b");
+
+ for (var i = 0; i < a_styles.length; i++) {
+ var property = a_styles[i];
+ assert_equals(property, b_styles[i], "Same property on div.a and div.b");
+ if (property !== "unicode-bidi") {
+ assert_equals(a_styles[property], b_styles[property], "Different value for " + property);
+ }
+ }
+}, "Compare CSS div definitions (only valid if pre-reqs pass)");
+
+test(function() {
+ var a = document.querySelector("span.a");
+ var b = document.querySelector("span.b");
+
+ var a_styles = window.getComputedStyle(a);
+ var b_styles = window.getComputedStyle(b);
+
+ assert_equals(a_styles.length, b_styles.length, "Same properties on both span.a and span.b");
+
+ for (var i = 0; i < a_styles.length; i++) {
+ var property = a_styles[i];
+ assert_equals(property, b_styles[i], "Same property on span.a and span.b");
+ assert_equals(a_styles[property], b_styles[property], "Different value for " + property);
+ }
+}, "Compare CSS span definitions (only valid if pre-reqs pass)");
+
+test(function() {
+ var p = document.getElementsByTagName("p")[0];
+ var styles = window.getComputedStyle(p);
+ assert_equals(styles["display"], "block");
+}, "p is display: block");
+
+test(function() {
+ var ul_li = document.querySelector("ul > li");
+ var styles = window.getComputedStyle(ul_li);
+ assert_equals(styles["display"], "list-item");
+}, "ul > li is display: list-item");
+
+test(function() {
+ var ol_li = document.querySelector("ol > li");
+ var styles = window.getComputedStyle(ol_li);
+ assert_equals(styles["display"], "list-item");
+}, "ol > li is display: list-item");
+
+test(function() {
+ var table = document.getElementsByTagName("table")[0];
+ var styles = window.getComputedStyle(table);
+ assert_equals(styles["display"], "table");
+}, "table is display: table");
+
+test(function() {
+ var tbody = document.getElementsByTagName("tbody")[0];
+ var styles = window.getComputedStyle(tbody);
+ assert_equals(styles["display"], "table-row-group");
+}, "tbody is display: table-row-group");
+
+test(function() {
+ var tr = document.getElementsByTagName("tr")[0];
+ var styles = window.getComputedStyle(tr);
+ assert_equals(styles["display"], "table-row");
+}, "tr is display: table-row");
+
+test(function() {
+ var td = document.getElementsByTagName("td")[0];
+ var styles = window.getComputedStyle(td);
+ assert_equals(styles["display"], "table-cell");
+}, "td is display: table-cell");
+</script>
diff --git a/testing/web-platform/tests/infrastructure/assumptions/initial-color-ref.html b/testing/web-platform/tests/infrastructure/assumptions/initial-color-ref.html
new file mode 100644
index 0000000000..46dd110bd3
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/assumptions/initial-color-ref.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<title>Initial color is black reference</title>
+<style>
+html {
+ background: white;
+}
+
+p {
+ color: black;
+}
+</style>
+<p>The text should be black
diff --git a/testing/web-platform/tests/infrastructure/assumptions/initial-color.html b/testing/web-platform/tests/infrastructure/assumptions/initial-color.html
new file mode 100644
index 0000000000..f1033c7d7e
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/assumptions/initial-color.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<title>Initial color is black</title>
+<link rel="match" href="initial-color-ref.html">
+<style>
+html {
+ background: white;
+}
+</style>
+<p>The text should be black
diff --git a/testing/web-platform/tests/infrastructure/assumptions/medium-font-size-ref.html b/testing/web-platform/tests/infrastructure/assumptions/medium-font-size-ref.html
new file mode 100644
index 0000000000..c1600ec419
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/assumptions/medium-font-size-ref.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<title>medium font-size reference</title>
+<style>
+p {
+ font-size: 16px;
+}
+</style>
+<p>This text should be 16px
diff --git a/testing/web-platform/tests/infrastructure/assumptions/medium-font-size.html b/testing/web-platform/tests/infrastructure/assumptions/medium-font-size.html
new file mode 100644
index 0000000000..f4c303d0ba
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/assumptions/medium-font-size.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<title>Check medium font-size is 16px</title>
+<link rel="match" href="medium-font-size-ref.html">
+<style>
+p {
+ font-size: medium;
+}
+</style>
+<p>This text should be 16px
diff --git a/testing/web-platform/tests/infrastructure/assumptions/min-font-size-ref.html b/testing/web-platform/tests/infrastructure/assumptions/min-font-size-ref.html
new file mode 100644
index 0000000000..013970bedf
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/assumptions/min-font-size-ref.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<title>Tiny text reference</title>
+<style>
+p {
+ font-size: 2px;
+}
+</style>
+<p>Tiny text
diff --git a/testing/web-platform/tests/infrastructure/assumptions/min-font-size.html b/testing/web-platform/tests/infrastructure/assumptions/min-font-size.html
new file mode 100644
index 0000000000..a4b9a1cd36
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/assumptions/min-font-size.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<title>Check 1px and 2px font-sizes are different</title>
+<link rel="mismatch" href="min-font-size-ref.html">
+<style>
+p {
+ font-size: 1px;
+}
+</style>
+<p>Tiny text
diff --git a/testing/web-platform/tests/infrastructure/assumptions/non-local-ports.sub.window.js b/testing/web-platform/tests/infrastructure/assumptions/non-local-ports.sub.window.js
new file mode 100644
index 0000000000..06ecb3ab21
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/assumptions/non-local-ports.sub.window.js
@@ -0,0 +1,111 @@
+// Verifies that non-local HTTP(S) ports are open and serve correctly.
+//
+// See the corresponding WPT RFC:
+// https://github.com/web-platform-tests/rfcs/blob/master/rfcs/address_space_overrides.md
+//
+// These ports are used to test the Local Network Access specification:
+// https://wicg.github.io/local-network-access/
+//
+// More tests can be found in `fetch/local-network-access/`.
+
+const alternatePorts = {
+ httpPrivate: "{{ports[http-private][0]}}",
+ httpsPrivate: "{{ports[https-private][0]}}",
+ httpPublic: "{{ports[http-public][0]}}",
+ httpsPublic: "{{ports[https-public][0]}}",
+};
+
+// Resolves a URL relative to the current location, returning an absolute URL.
+//
+// `url` specifies the relative URL, e.g. "foo.html" or "http://foo.example".
+// `options.protocol` and `options.port`, if defined, override the respective
+// properties of the returned URL object.
+function resolveUrl(url, options) {
+ const result = new URL(url, window.location);
+ if (options === undefined) {
+ return result;
+ }
+
+ const { port, protocol } = options;
+ if (port !== undefined) {
+ result.port = port;
+ }
+ if (protocol !== undefined) {
+ result.protocol = protocol;
+ }
+
+ return result;
+}
+
+const alternateOrigins = {
+ httpPrivate: {
+ protocol: "http:",
+ port: alternatePorts.httpPrivate,
+ },
+ httpsPrivate: {
+ protocol: "https:",
+ port: alternatePorts.httpsPrivate,
+ },
+ httpPublic: {
+ protocol: "http:",
+ port: alternatePorts.httpPublic,
+ },
+ httpsPublic: {
+ protocol: "https:",
+ port: alternatePorts.httpsPublic,
+ },
+};
+
+promise_test(async () => {
+ const url =
+ resolveUrl("/common/blank-with-cors.html", alternateOrigins.httpsPrivate);
+ const response = await fetch(url);
+ assert_true(response.ok);
+}, "Fetch from https-private port works.");
+
+promise_test(async () => {
+ const url =
+ resolveUrl("/common/blank-with-cors.html", alternateOrigins.httpPrivate);
+ const response = await fetch(url);
+ assert_true(response.ok);
+}, "Fetch from http-private port works.");
+
+promise_test(async () => {
+ const url =
+ resolveUrl("/common/blank-with-cors.html", alternateOrigins.httpsPublic);
+ const response = await fetch(url);
+ assert_true(response.ok);
+}, "Fetch from https-public port works.");
+
+promise_test(async () => {
+ const url =
+ resolveUrl("/common/blank-with-cors.html", alternateOrigins.httpPublic);
+ const response = await fetch(url);
+ assert_true(response.ok);
+}, "Fetch from http-public port works.");
+
+promise_test(async (t) => {
+ const futureMessage = new Promise((resolve) => {
+ window.addEventListener("message", resolve);
+ });
+
+ const iframe = await new Promise((resolve, reject) => {
+ const iframe = document.createElement("iframe");
+ iframe.src = resolveUrl("resources/fetch-and-post-result.html",
+ alternateOrigins.httpPublic);
+
+ iframe.onload = () => { resolve(iframe); };
+ iframe.onerror = reject;
+
+ document.body.appendChild(iframe);
+ t.add_cleanup(() => {
+ document.body.removeChild(iframe);
+ });
+ });
+
+ iframe.contentWindow.postMessage(
+ resolveUrl("/common/blank-with-cors.html").toString(), "*");
+
+ const evt = await futureMessage;
+ assert_equals(evt.data, "failure: error = TypeError");
+}, "Fetch from http-public to local http fails.");
diff --git a/testing/web-platform/tests/infrastructure/assumptions/non-secure-context.any.js b/testing/web-platform/tests/infrastructure/assumptions/non-secure-context.any.js
new file mode 100644
index 0000000000..c05689fe76
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/assumptions/non-secure-context.any.js
@@ -0,0 +1,9 @@
+test(() => {
+ assert_false(self.isSecureContext);
+}, "Lack of .https file name flag implies non-secure context");
+
+test(() => {
+ assert_equals(location.protocol, "http:");
+}, "Lack of .https file name flag implies HTTP scheme");
+
+done();
diff --git a/testing/web-platform/tests/infrastructure/assumptions/resources/fetch-and-post-result.html b/testing/web-platform/tests/infrastructure/assumptions/resources/fetch-and-post-result.html
new file mode 100644
index 0000000000..4df0c4c71a
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/assumptions/resources/fetch-and-post-result.html
@@ -0,0 +1,12 @@
+<script>
+ window.addEventListener("message", function (event) {
+ fetch(event.data)
+ .then(response => {
+ parent.postMessage(`success: status = ${response.status}`, "*");
+ })
+ .catch(error => {
+ parent.postMessage(`failure: error = ${error.name}`, "*")
+ });
+ });
+</script>
+
diff --git a/testing/web-platform/tests/infrastructure/assumptions/tools/ahem-generate-table.py b/testing/web-platform/tests/infrastructure/assumptions/tools/ahem-generate-table.py
new file mode 100644
index 0000000000..314279f671
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/assumptions/tools/ahem-generate-table.py
@@ -0,0 +1,127 @@
+import itertools
+import unicodedata
+
+from fontTools.ttLib import TTFont
+
+try:
+ chr(0x100)
+except ValueError:
+ chr = unichr
+
+def grouper(n, iterable):
+ """
+ >>> list(grouper(3, 'ABCDEFG'))
+ [['A', 'B', 'C'], ['D', 'E', 'F'], ['G']]
+ """
+ iterable = iter(iterable)
+ return iter(lambda: list(itertools.islice(iterable, n)), [])
+
+ttf = TTFont("../../../fonts/Ahem.ttf")
+
+chars = {char for table in ttf['cmap'].tables for char in table.cmap.keys()}
+
+# exclude chars that can't be represented as HTML numeric character refs
+chars = chars - (set(range(0x80, 0x9F+1)) | {0x00})
+
+chars_sorted = sorted(chars)
+
+per_row = 17
+
+
+doctype = "<!doctype html>"
+title = "<title>Ahem checker</title>"
+style_open = """
+<style>
+* {
+ padding: 0;
+ margin: 0;
+ border: none;
+}
+td {
+ width: 34px;
+}""".strip()
+style_close = "</style>"
+style_font_face = """
+@font-face {
+ font-family: Ahem;
+ src: url("../../fonts/Ahem.ttf");
+}""".strip()
+style_table_font_specified = """
+table {
+ font: 15px/1 Ahem;
+ border-collapse: separate;
+ border-spacing: 1px;
+ table-layout: fixed;
+}""".strip()
+style_table_font_unspecified = """
+table {
+ font-size: 15px;
+ line-height: 1;
+ border-collapse: separate;
+ border-spacing: 1px;
+ table-layout: fixed;
+}""".strip()
+
+
+def build_header(is_test, rel, href):
+ rv = [doctype, title]
+
+ if rel != None and href != None:
+ rv.append('<link rel="%s" href="%s">' % (rel, href))
+
+ rv.append(style_open)
+
+ if not is_test:
+ if rel == None and href == None:
+ # ahem-notref.html
+ rv.append(style_table_font_unspecified)
+ else:
+ # ahem-ref.html
+ rv.append(style_font_face)
+ rv.append(style_table_font_specified)
+ else:
+ # ahem.html
+ rv.append(style_table_font_specified)
+
+ rv.append(style_close)
+
+ return "\n".join(rv)
+
+
+def build_table():
+ rv = ["\n"]
+
+ rv.append("<table>\n")
+ for row in grouper(per_row, chars_sorted):
+ rv.append(" " * 4 + "<tr>\n")
+ for codepoint in row:
+ assert codepoint <= 0xFFFF
+ try:
+ name = unicodedata.name(chr(codepoint))
+ except ValueError:
+ rv.append(" " * 8 + "<td>&#x%04X;x <!-- U+%04X -->\n" % (codepoint, codepoint))
+ else:
+ rv.append(" " * 8 + "<td>&#x%04X;x <!-- U+%04X: %s -->\n" % (codepoint, codepoint, name))
+ rv.append("</table>\n")
+
+ return "".join(rv)
+
+
+cases = [
+ # file, is_test, rel
+ ("../ahem.html", True, "match"),
+ ("../ahem-ref.html", False, "mismatch"),
+ ("../ahem-notref.html", False, None),
+]
+
+table = build_table()
+
+for index, case in enumerate(cases):
+ next_index = index + 1
+ file, is_test, rel = case
+ href = cases[next_index][0][3:] if next_index < len(cases) else None
+ header = build_header(is_test, rel, href)
+
+ with open(file, "w") as file:
+ file.write("%s%s" % (header, table))
+
diff --git a/testing/web-platform/tests/infrastructure/browsers/firefox/prefs.html b/testing/web-platform/tests/infrastructure/browsers/firefox/prefs.html
new file mode 100644
index 0000000000..9656aa051e
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/browsers/firefox/prefs.html
@@ -0,0 +1,9 @@
+<title>Ensure that setting gecko prefs works</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(function() {
+ assert_equals(getComputedStyle(document.documentElement).color, "rgb(0, 255, 0)")
+});
+</script>
+<p>This should be green</p>
diff --git a/testing/web-platform/tests/infrastructure/channels/child_message.html b/testing/web-platform/tests/infrastructure/channels/child_message.html
new file mode 100644
index 0000000000..6baf47b193
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/channels/child_message.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<script src="/resources/channel.sub.js"></script>
+<script>
+function handleMessage(msg) {
+ // We expect the message to be a SendChannel
+ respChannel = msg;
+ respChannel.send("PASS");
+}
+
+let channel = global_channel();
+channel.addMessageHandler(handleMessage);
+channel.connect();
+</script>
diff --git a/testing/web-platform/tests/infrastructure/channels/child_script.html b/testing/web-platform/tests/infrastructure/channels/child_script.html
new file mode 100644
index 0000000000..1c10379bde
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/channels/child_script.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<script src="/resources/channel.sub.js"></script>
+<div id="test">FAIL</div>
+<script>
+(async function() {
+ await new Promise(resolve => onload = resolve);
+ document.getElementById("test").textContent = "PASS";
+ await start_global_channel();
+})()
+</script>
diff --git a/testing/web-platform/tests/infrastructure/channels/serialize-data.js b/testing/web-platform/tests/infrastructure/channels/serialize-data.js
new file mode 100644
index 0000000000..5c423ee160
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/channels/serialize-data.js
@@ -0,0 +1,37 @@
+let cyclicArray = [1];
+cyclicArray.push(cyclicArray);
+
+let cyclicObject = {key1: "data"};
+cyclicObject.key2 = cyclicObject;
+
+let cyclicSet = new Set([1]);
+cyclicSet.add(cyclicSet);
+
+let cyclicMap = new Map([["key1", 1]]);
+cyclicMap.set("key2", cyclicMap);
+
+const objects = {
+ "null": {input: null},
+ "undefined": {input: undefined},
+ "int": {input: 1},
+ "Infinity": {input: Infinity},
+ "-Infinity": {input: -Infinity},
+ "NaN": {input: NaN},
+ "string": {input: "foo"},
+ "true": {input: true},
+ "false": {input: false},
+ "bigint": {input: 1n},
+ "RegExp": {input: /abc/g},
+ "Date": {input: new Date('December 17, 1995 03:24:00')},
+ "Error": {"input": new Error("message")},
+ "TypeError": {"input": new TypeError("TypeError message")},
+ "array": {input: [1,"foo"], output: [1, "foo"]},
+ "nested array": {input: [1,[2]]},
+ "set": {input: new Set([1, "foo", null])},
+ "object": {input: {key1: 1, key2: false}},
+ "nested object": {input: {key1: 1, key2: false}},
+ "map": {input: new Map([[1, 1], ["key2", false]])},
+ "cyclic array": {input: cyclicArray},
+ "cyclic object": {input: cyclicObject},
+ "cyclic map": {input: cyclicMap},
+};
diff --git a/testing/web-platform/tests/infrastructure/channels/serialize_child.html b/testing/web-platform/tests/infrastructure/channels/serialize_child.html
new file mode 100644
index 0000000000..6ad3accfee
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/channels/serialize_child.html
@@ -0,0 +1,173 @@
+<!doctype html>
+<script src="/resources/channel.sub.js"></script>
+<script src="serialize-data.js"></script>
+<script>
+
+let lastData;
+
+// Hack: these will be converted into testharness AssertionError instances in the test
+// This means they will be treated identically to asserts raised by `assert_` in the harness
+// In the long term we want to be able to use parts of testharness.js directly in remote
+// contexts and automatically send the results over a channel.
+function AssertionError(message) {
+ this.message = message;
+}
+AssertionError.prototype = Object.create(Error.prototype);
+
+function compareResult(name, actual) {
+ let obj = objects[name];
+ // If there's an output property use that, otherwise assume the output is equal to the input
+ let expected = obj.hasOwnProperty("output") ? obj.output : obj.input;
+ seen = new Set();
+ try {
+ compareValue(actual, expected, seen);
+ } catch(e) {
+ throw new AssertionError(e.message);
+ }
+ return true;
+}
+
+function compareValue(actualValue, expectedValue, seen) {
+ let seenActual;
+ if (typeof actualValue != typeof expectedValue) {
+ throw new Error(`Types differ, expected ${typeof expectedValue}, got ${typeof actualValue}`);
+ }
+ if (["undefined", "string", "boolean", "number", "bigint"].includes(typeof expectedValue) ||
+ actualValue === null) {
+ if (!Object.is(actualValue, expectedValue)) {
+ throw new Error(`Expected ${typeof expected} ${expected}, got ${actual}`);
+ }
+ return;
+ }
+
+ if (expectedValue.constructor && actualValue.constructor && expectedValue.constructor.name !== actualValue.constructor.name) {
+ throw new Error(`Constructors differ, expected ${expectedValue.constructor.name}, got ${actualValue.constructor.name}`);
+ }
+ if (expectedValue.constructor && expectedValue.constructor.name === "SendChannel") {
+ if (expectedValue.uuid !== actualValue.uuid) {
+ throw new Error(`SendChannels differ, expected uuid ${expectedValue.uuid}, got ${actualValue.uuid}`);
+ }
+ }
+ else if (expectedValue.constructor && expectedValue.constructor.name === "RegExp") {
+ if (expectedValue.source !== actualValue.source ||
+ expectedValue.flags !== actualValue.flags) {
+ throw new Error(`RegExps differ, expected ${expectedValue}, got ${actualValue}`);
+ }
+ } else if (expectedValue.constructor && expectedValue.constructor.name == "Date") {
+ if (expectedValue.valueOf() !== actualValue.valueOf()) {
+ throw new Error(`Dates differ, expected ${expectedValue.valueOf()} (${expectedValue.toDateString()}), `
+ `got ${actualValue.valueOf()} (${actualValue.toDateString()})`);
+ }
+ } else if (expectedValue instanceof Error) {
+ if (expectedValue.message !== actualValue.message ||
+ expectedValue.lineNumber !== actualValue.lineNumber ||
+ expectedValue.columnNumber !== actualValue.columnNumber ||
+ expectedValue.fileName !== actualValue.fileName) {
+ throw new Error(`Errors differ, expected ${expectedValue}, got ${actualValue}`);
+ }
+ } else if (Array.isArray(expectedValue)) {
+ seenActual = seen.has(actualValue);
+ seenExpected = seen.has(expectedValue)
+ if (seenActual && seenExpected) {
+ return;
+ } else if (seenExpected && !seenActual) {
+ throw new Error(`Expected cyclic array`);
+ } else if (!seenExpected && seenActual) {
+ throw new Error(`Got unexpected cyclic array`);
+ }
+ seen.add(actualValue);
+ seen.add(expectedValue);
+
+ if (actualValue.length !== expectedValue.length) {
+ throw new Error(`Array lengths differ, expected ${expectedValue.length}, got ${actualValue.length}`);
+ }
+ for (let i=0; i<actualValue.length; i++) {
+ compareValue(actualValue[i], expectedValue[i], seen);
+ }
+ } else if (expectedValue.constructor && expectedValue.constructor.name === "Set") {
+ seenActual = seen.has(actualValue);
+ seenExpected = seen.has(expectedValue)
+ if (seenActual && seenExpected) {
+ return;
+ } else if (seenExpected && !seenActual) {
+ throw new Error(`Expected cyclic set`);
+ } else if (!seenExpected && seenActual) {
+ throw new Error(`Got unexpected cyclic set`);
+ }
+ seen.add(actualValue);
+ seen.add(expectedValue);
+
+
+ if (actualValue.size !== expectedValue.size) {
+ throw new Error(`Set sizes differ, expected ${expectedValue.size}, got ${actualValue.size}`);
+ }
+ // For an arbitary set it's complex to check if two sets are equivalent, since
+ // we'd need to compare every object in one set with every object in the
+ // other set, so we end up with quadratic complexity. Instead, just support sets
+ // containing primitives and rely on the other tests for correct handling of
+ // objects.
+ for (let entry of expectedValue) {
+ if (["undefined", "string", "boolean", "number", "bigint"].includes(typeof entry) || entry === null) {
+ if(!actualValue.has(entry)) {
+ throw new Error(`Set missing entry, expected ${entry}`);
+ }
+ } else {
+ throw new Error(`Can't compare non-primitive value ${entry} inside sets`);
+ }
+ }
+ } else if (expectedValue.constructor && expectedValue.constructor.name === "Map") {
+ seenActual = seen.has(actualValue);
+ seenExpected = seen.has(expectedValue)
+ if (seenActual && seenExpected) {
+ return;
+ } else if (seenExpected && !seenActual) {
+ throw new Error(`Expected cyclic map`);
+ } else if (!seenExpected && seenActual) {
+ throw new Error(`Got unexpected cyclic map`);
+ }
+ seen.add(actualValue);
+ seen.add(expectedValue);
+
+ if (actualValue.size !== expectedValue.size) {
+ throw new Error(`Map sizes differ, expected ${expectedValue.size}, got ${actualValue.size}`);
+ }
+ // So for a set we can't really check if the values are the same
+ // except where they're primitives
+ for (let [key, value] of expectedValue.entries()) {
+ if(!actualValue.has(key)) {
+ throw new Error(`Map missing key, expected key ${key} with value ${value}`);
+ }
+ compareValue(actualValue.get(key), value, seen);
+ }
+ } else {
+ seenActual = seen.has(actualValue);
+ seenExpected = seen.has(expectedValue)
+ if (seenActual && seenExpected) {
+ return;
+ } else if (seenExpected && !seenActual) {
+ throw new Error(`Expected cyclic object`);
+ } else if (!seenExpected && seenActual) {
+ throw new Error(`Got unexpected cyclic object`);
+ }
+ seen.add(actualValue);
+ seen.add(expectedValue);
+
+
+ // Compare as a general Object
+ let expectedEntries = Object.entries(expectedValue);
+ if (Object.keys(actualValue).length !== expectedEntries.length) {
+ throw new Error(`Object keys differ, expected [${Object.keys(expectedValue).join(",")}], got [${Object.keys(actualValue).join(",")}]`);
+ }
+ // So for a set we can't really check if the values are the same
+ // except where they're primitives
+ for (let [name, entry] of expectedEntries) {
+ if(!actualValue.hasOwnProperty(name)) {
+ throw new Error(`Object missing key ${name}`);
+ }
+ compareValue(actualValue[name], entry, seen);
+ }
+ }
+}
+
+ctx = start_global_channel();
+</script>
diff --git a/testing/web-platform/tests/infrastructure/channels/test_call.html b/testing/web-platform/tests/infrastructure/channels/test_call.html
new file mode 100644
index 0000000000..49beaea4ff
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/channels/test_call.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>call method</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/channel.sub.js"></script>
+
+<script>
+setup({single_test: true})
+onload = async () => {
+ let remote = await new RemoteGlobal();
+
+ let url = `child_script.html?uuid=${remote.uuid}`;
+ win = window.open(url, "_blank", "noopener");
+
+ let result = await remote.call(async (elemId) => {
+ return document.getElementById(elemId).textContent;
+ }, ["test"]);
+ assert_equals(result.trim(), "PASS");
+ done();
+}
+</script>
diff --git a/testing/web-platform/tests/infrastructure/channels/test_postMessage.html b/testing/web-platform/tests/infrastructure/channels/test_postMessage.html
new file mode 100644
index 0000000000..473c8630a6
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/channels/test_postMessage.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>postMessage method</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/channel.sub.js"></script>
+
+<script>
+setup({single_test: true});
+(async () => {
+ let remote = await new RemoteGlobal();
+
+ let url = `child_message.html?uuid=${remote.uuid}`;
+ win = window.open(url, "_blank", "noopener");
+
+ let [recvChannel, sendChannel] = channel();
+ await remote.postMessage(sendChannel);
+ await recvChannel.connect();
+ let message = await recvChannel.nextMessage();
+ assert_equals(message, "PASS");
+ done();
+})();
+</script>
diff --git a/testing/web-platform/tests/infrastructure/channels/test_serialize.html b/testing/web-platform/tests/infrastructure/channels/test_serialize.html
new file mode 100644
index 0000000000..88a9ce5221
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/channels/test_serialize.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>object serialization</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/channel.sub.js"></script>
+<script src="serialize-data.js"></script>
+
+<script>
+setup(() => {
+ remote = new RemoteGlobal();
+
+ let url = `serialize_child.html?uuid=${remote.uuid}`;
+ win = window.open(url);
+});
+
+for (let [name, obj] of Object.entries(objects)) {
+ promise_test(async t => {
+ let result = await remote.call(
+ (name, inputValue) => compareResult(name, inputValue),
+ name,
+ obj.input);
+ assert_true(result);
+ }, `Serialize ${name}`);
+}
+
+promise_test(async t => {
+ let remoteValue = RemoteObject.from(document.head);
+ let result = await remote.call(inputValue => {
+ if (!inputValue instanceof RemoteObject) {
+ throw new AssertionError(`Expected RemoteObject`);
+ }
+ return inputValue;
+ }, remoteValue);
+ assert_equals(result, document.head);
+}, "Serialize RemoteObject");
+
+</script>
diff --git a/testing/web-platform/tests/infrastructure/crashtests/example.html b/testing/web-platform/tests/infrastructure/crashtests/example.html
new file mode 100644
index 0000000000..e0fa7b3c88
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/crashtests/example.html
@@ -0,0 +1 @@
+<p>Test that should not crash
diff --git a/testing/web-platform/tests/infrastructure/expected-fail/failing-test.html b/testing/web-platform/tests/infrastructure/expected-fail/failing-test.html
new file mode 100644
index 0000000000..249099c06f
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/expected-fail/failing-test.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Failing test</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(function() {
+ assert_unreached("Expected failure");
+});
+</script>
diff --git a/testing/web-platform/tests/infrastructure/expected-fail/timeout.html b/testing/web-platform/tests/infrastructure/expected-fail/timeout.html
new file mode 100644
index 0000000000..29ff348a9a
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/expected-fail/timeout.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test that should time out</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test()
+</script>
diff --git a/testing/web-platform/tests/infrastructure/expected-fail/uncaught-exception-following-subtest.html b/testing/web-platform/tests/infrastructure/expected-fail/uncaught-exception-following-subtest.html
new file mode 100644
index 0000000000..ed95c60328
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/expected-fail/uncaught-exception-following-subtest.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Uncaught exception following subtest</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(function() {});
+throw new Error("error outside any setup or test");
+</script>
diff --git a/testing/web-platform/tests/infrastructure/expected-fail/uncaught-exception-single-test.html b/testing/web-platform/tests/infrastructure/expected-fail/uncaught-exception-single-test.html
new file mode 100644
index 0000000000..4f88704cad
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/expected-fail/uncaught-exception-single-test.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Uncaught exception in single-page test</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+setup({ single_test: true });
+throw new Error("error outside any setup or test");
+</script>
diff --git a/testing/web-platform/tests/infrastructure/expected-fail/uncaught-exception.html b/testing/web-platform/tests/infrastructure/expected-fail/uncaught-exception.html
new file mode 100644
index 0000000000..4442d51375
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/expected-fail/uncaught-exception.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Uncaught exception</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+throw new Error("error outside any setup or test");
+</script>
diff --git a/testing/web-platform/tests/infrastructure/expected-fail/unhandled-rejection-following-subtest.html b/testing/web-platform/tests/infrastructure/expected-fail/unhandled-rejection-following-subtest.html
new file mode 100644
index 0000000000..d8cab6d910
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/expected-fail/unhandled-rejection-following-subtest.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Unhandled rejection following subtest</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+setup({ explicit_done: true });
+window.addEventListener('unhandledrejection', () => { done(); }, {once: true});
+test(function() {});
+Promise.reject(new Error("error outside any setup or test"));
+</script>
diff --git a/testing/web-platform/tests/infrastructure/expected-fail/unhandled-rejection-single-test.html b/testing/web-platform/tests/infrastructure/expected-fail/unhandled-rejection-single-test.html
new file mode 100644
index 0000000000..925787191c
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/expected-fail/unhandled-rejection-single-test.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Unhandled rejection in single-page test</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+setup({ single_test: true });
+Promise.reject(new Error("error outside any setup or test"));
+</script>
diff --git a/testing/web-platform/tests/infrastructure/expected-fail/unhandled-rejection.html b/testing/web-platform/tests/infrastructure/expected-fail/unhandled-rejection.html
new file mode 100644
index 0000000000..f25f6e088f
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/expected-fail/unhandled-rejection.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Unhandled rejection</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+Promise.reject(new Error("error outside any setup or test"));
+</script>
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/assumptions/ahem.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/assumptions/ahem.html.ini
new file mode 100644
index 0000000000..8587775d8f
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/assumptions/ahem.html.ini
@@ -0,0 +1,3 @@
+[ahem.html]
+ expected:
+ if product == "safari": FAIL # system fonts not loaded since macOS Mojave
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/assumptions/allowed-to-play.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/assumptions/allowed-to-play.html.ini
new file mode 100644
index 0000000000..6891cbe24e
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/assumptions/allowed-to-play.html.ini
@@ -0,0 +1,9 @@
+[allowed-to-play.html]
+ disabled:
+ if product == "firefox": https://bugzilla.mozilla.org/show_bug.cgi?id=1607802
+ expected:
+ if product == "safari": ERROR # https://bugs.webkit.org/show_bug.cgi?id=190775
+
+ [<audio> autoplay]
+ expected:
+ if product == "safari": FAIL # https://bugs.webkit.org/show_bug.cgi?id=190775
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/assumptions/document-fonts-ready.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/assumptions/document-fonts-ready.html.ini
new file mode 100644
index 0000000000..d074292053
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/assumptions/document-fonts-ready.html.ini
@@ -0,0 +1,4 @@
+[document-fonts-ready.html]
+ [document.fonts.ready resolves after layout depending on loaded fonts]
+ expected:
+ if product == "epiphany" or product == "webkit": FAIL # https://bugs.webkit.org/show_bug.cgi?id=174030
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/assumptions/non-local-ports.sub.window.js.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/assumptions/non-local-ports.sub.window.js.ini
new file mode 100644
index 0000000000..87d8cd43c4
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/assumptions/non-local-ports.sub.window.js.ini
@@ -0,0 +1,4 @@
+[non-local-ports.sub.window.html]
+ [Fetch from http-public to local http fails.]
+ expected:
+ if product != "chrome": FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/browsers/firefox/__dir__.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/browsers/firefox/__dir__.ini
new file mode 100644
index 0000000000..3e0ed18107
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/browsers/firefox/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+ if product != "firefox": true \ No newline at end of file
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/browsers/firefox/prefs.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/browsers/firefox/prefs.html.ini
new file mode 100644
index 0000000000..7b78d216de
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/browsers/firefox/prefs.html.ini
@@ -0,0 +1,2 @@
+[prefs.html]
+ prefs: ["browser.display.foreground_color:#00FF00"]
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/failing-test.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/failing-test.html.ini
new file mode 100644
index 0000000000..b954a0e9b7
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/failing-test.html.ini
@@ -0,0 +1,4 @@
+[failing-test.html]
+ [Failing test]
+ expected: FAIL
+
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/timeout.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/timeout.html.ini
new file mode 100644
index 0000000000..53b281f835
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/timeout.html.ini
@@ -0,0 +1,4 @@
+[timeout.html]
+ expected: TIMEOUT
+ [Test that should time out]
+ expected: NOTRUN
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/uncaught-exception-following-subtest.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/uncaught-exception-following-subtest.html.ini
new file mode 100644
index 0000000000..f7f3d4f7b5
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/uncaught-exception-following-subtest.html.ini
@@ -0,0 +1,6 @@
+[uncaught-exception-following-subtest.html]
+ expected: ERROR
+
+ [Uncaught exception following subtest]
+ expected: PASS
+
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/uncaught-exception-single-test.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/uncaught-exception-single-test.html.ini
new file mode 100644
index 0000000000..6d2bd7f236
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/uncaught-exception-single-test.html.ini
@@ -0,0 +1,4 @@
+[uncaught-exception-single-test.html]
+ [Uncaught exception in single-page test]
+ expected: FAIL
+
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/uncaught-exception.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/uncaught-exception.html.ini
new file mode 100644
index 0000000000..40a58e4153
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/uncaught-exception.html.ini
@@ -0,0 +1,2 @@
+[uncaught-exception.html]
+ expected: ERROR
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/unhandled-rejection-following-subtest.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/unhandled-rejection-following-subtest.html.ini
new file mode 100644
index 0000000000..ff1861aff9
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/unhandled-rejection-following-subtest.html.ini
@@ -0,0 +1,6 @@
+[unhandled-rejection-following-subtest.html]
+ expected: ERROR
+
+ [Unhandled rejection following subtest]
+ expected: PASS
+
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/unhandled-rejection-single-test.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/unhandled-rejection-single-test.html.ini
new file mode 100644
index 0000000000..f785f4cc6e
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/unhandled-rejection-single-test.html.ini
@@ -0,0 +1,4 @@
+[unhandled-rejection-single-test.html]
+ [Unhandled rejection in single-page test]
+ expected: FAIL
+
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/unhandled-rejection.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/unhandled-rejection.html.ini
new file mode 100644
index 0000000000..da4fe27e58
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/unhandled-rejection.html.ini
@@ -0,0 +1,2 @@
+[unhandled-rejection.html]
+ expected: ERROR
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/window-onload-test.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/window-onload-test.html.ini
new file mode 100644
index 0000000000..e380f5e581
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/expected-fail/window-onload-test.html.ini
@@ -0,0 +1,16 @@
+[window-onload-test.html]
+
+ [test 2]
+ expected: FAIL
+
+ [test 3]
+ expected: FAIL
+
+ [promise 1]
+ expected: FAIL
+
+ [promise 2]
+ expected: FAIL
+
+ [promise 3]
+ expected: FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/legacy/fuzzy-ref-2.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/legacy/fuzzy-ref-2.html.ini
new file mode 100644
index 0000000000..cdfd9736c5
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/legacy/fuzzy-ref-2.html.ini
@@ -0,0 +1,4 @@
+[fuzzy-ref-2.html]
+ fuzzy:
+ if os == "mac" and product == "chrome": maxDifference=254-255;100-100
+ maxDifference=255;100-100
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/legacy/reftest_and_fail_0-ref.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/legacy/reftest_and_fail_0-ref.html.ini
new file mode 100644
index 0000000000..1e13cec6ac
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/legacy/reftest_and_fail_0-ref.html.ini
@@ -0,0 +1,2 @@
+[reftest_and_fail_0-ref.html]
+ expected: FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/legacy/reftest_cycle_fail_0-ref.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/legacy/reftest_cycle_fail_0-ref.html.ini
new file mode 100644
index 0000000000..9a0066917e
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/legacy/reftest_cycle_fail_0-ref.html.ini
@@ -0,0 +1,2 @@
+[reftest_cycle_fail_0-ref.html]
+ expected: FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/legacy/reftest_fuzzy_chain_ini.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/legacy/reftest_fuzzy_chain_ini.html.ini
new file mode 100644
index 0000000000..d3776e243e
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/legacy/reftest_fuzzy_chain_ini.html.ini
@@ -0,0 +1,4 @@
+[reftest_fuzzy_chain_ini.html]
+ fuzzy:
+ if os == "mac" and product == "chrome": maxDifference=254-255;100-100
+ maxDifference=255;100-100
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_1.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_1.html.ini
new file mode 100644
index 0000000000..44f185357b
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_1.html.ini
@@ -0,0 +1,3 @@
+[reftest_fuzzy_1.html]
+ fuzzy:
+ if os == "mac" and product == "chrome": fuzzy-ref-1.html:254-255;100
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_full.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_full.html.ini
new file mode 100644
index 0000000000..d682550d53
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_full.html.ini
@@ -0,0 +1,6 @@
+[reftest_fuzzy_ini_full.html]
+ fuzzy:
+ if os == "mac" and product == "chrome": [maxDifference=1;100-100,
+ reftest_fuzzy_ini_full.html==fuzzy-ref-1.html:254-255;100]
+ if 1 == 1: [maxDifference=1;100-100, # 'if 1 == 1:' is a workaround for a parser bug
+ reftest_fuzzy_ini_full.html==fuzzy-ref-1.html:255;100]
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_ref_only.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_ref_only.html.ini
new file mode 100644
index 0000000000..4437fceff8
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_ref_only.html.ini
@@ -0,0 +1,8 @@
+[reftest_fuzzy_ini_ref_only.html]
+ fuzzy:
+ if os == "mac" and product == "chrome": [maxDifference=1;100-100,
+ fuzzy-ref-1.html:maxDifference=254-255;100-100,
+ reftest_fuzzy==fuzzy-ref-2.html:maxDifference=1;100-100]
+ if 1 == 1: [maxDifference=1;100-100, # 1 == 1 is a workaround for a parser bug.
+ fuzzy-ref-1.html:maxDifference=255;100-100,
+ reftest_fuzzy==fuzzy-ref-2.html:maxDifference=1;100-100]
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_short.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_short.html.ini
new file mode 100644
index 0000000000..27e3290e6f
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_short.html.ini
@@ -0,0 +1,4 @@
+[reftest_fuzzy_ini_short.html]
+ fuzzy:
+ if os == "mac" and product == "chrome": maxDifference=254-255;100-100
+ maxDifference=255;100-100
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_and_mismatch-0.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_and_mismatch-0.html.ini
new file mode 100644
index 0000000000..f90b3d6847
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_and_mismatch-0.html.ini
@@ -0,0 +1,2 @@
+[reftest_match_and_mismatch-0.html]
+ expected: FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_and_mismatch-1.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_and_mismatch-1.html.ini
new file mode 100644
index 0000000000..eeb9fc582d
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_and_mismatch-1.html.ini
@@ -0,0 +1,2 @@
+[reftest_match_and_mismatch-1.html]
+ expected: FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_and_mismatch-4.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_and_mismatch-4.html.ini
new file mode 100644
index 0000000000..77c7ba227d
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_and_mismatch-4.html.ini
@@ -0,0 +1,2 @@
+[reftest_match_and_mismatch-4.html]
+ expected: FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_and_mismatch-5.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_and_mismatch-5.html.ini
new file mode 100644
index 0000000000..e87acf9b67
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_and_mismatch-5.html.ini
@@ -0,0 +1,2 @@
+[reftest_match_and_mismatch-5.html]
+ expected: FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_and_mismatch-6.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_and_mismatch-6.html.ini
new file mode 100644
index 0000000000..e3089dd103
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_and_mismatch-6.html.ini
@@ -0,0 +1,2 @@
+[reftest_match_and_mismatch-6.html]
+ expected: FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_and_mismatch-7.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_and_mismatch-7.html.ini
new file mode 100644
index 0000000000..09162d8801
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_and_mismatch-7.html.ini
@@ -0,0 +1,2 @@
+[reftest_match_and_mismatch-7.html]
+ expected: FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_fail-print.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_fail-print.html.ini
new file mode 100644
index 0000000000..c45488203d
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_fail-print.html.ini
@@ -0,0 +1,2 @@
+[reftest_match_fail-print.html]
+ expected: FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_fail.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_fail.html.ini
new file mode 100644
index 0000000000..f3dc3362fa
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_match_fail.html.ini
@@ -0,0 +1,3 @@
+[reftest_match_fail.html]
+ type: reftest
+ expected: FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_mismatch_fail-print.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_mismatch_fail-print.html.ini
new file mode 100644
index 0000000000..4520f4cbb1
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_mismatch_fail-print.html.ini
@@ -0,0 +1,2 @@
+[reftest_mismatch_fail-print.html]
+ expected: FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_mismatch_fail.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_mismatch_fail.html.ini
new file mode 100644
index 0000000000..1055337e2d
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_mismatch_fail.html.ini
@@ -0,0 +1,3 @@
+[reftest_mismatch_fail.html]
+ type: reftest
+ expected: FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_multiple_mismatch-0.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_multiple_mismatch-0.html.ini
new file mode 100644
index 0000000000..6bc0bef41d
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_multiple_mismatch-0.html.ini
@@ -0,0 +1,2 @@
+[reftest_multiple_mismatch-0.html]
+ expected: FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_multiple_mismatch-1.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_multiple_mismatch-1.html.ini
new file mode 100644
index 0000000000..964858b1ac
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_multiple_mismatch-1.html.ini
@@ -0,0 +1,2 @@
+[reftest_multiple_mismatch-1.html]
+ expected: FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_ref_timeout.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_ref_timeout.html.ini
new file mode 100644
index 0000000000..8936241ad2
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_ref_timeout.html.ini
@@ -0,0 +1,3 @@
+[reftest_ref_timeout.html]
+ type: reftest
+ expected: TIMEOUT
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_timeout.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_timeout.html.ini
new file mode 100644
index 0000000000..0d1b9bade9
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/reftest/reftest_timeout.html.ini
@@ -0,0 +1,3 @@
+[reftest_timeout.html]
+ type: reftest
+ expected: TIMEOUT
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/server/context.any.js.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/server/context.any.js.ini
new file mode 100644
index 0000000000..03bf96ec46
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/server/context.any.js.ini
@@ -0,0 +1,8 @@
+[context.any.serviceworker.html]
+ [context]
+ expected:
+ if product == "epiphany" or product == "webkit": FAIL # https://bugs.webkit.org/show_bug.cgi?id=200815
+
+[context.any.serviceworker-module.html]
+ expected:
+ if product == "firefox": ERROR
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/server/http2-context.sub.h2.any.js.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/server/http2-context.sub.h2.any.js.ini
new file mode 100644
index 0000000000..8b13789179
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/server/http2-context.sub.h2.any.js.ini
@@ -0,0 +1 @@
+
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/server/http2-websocket.sub.h2.any.js.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/server/http2-websocket.sub.h2.any.js.ini
new file mode 100644
index 0000000000..74470b82c2
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/server/http2-websocket.sub.h2.any.js.ini
@@ -0,0 +1,16 @@
+[http2-websocket.sub.h2.any.html]
+ expected:
+ if product == "safari": TIMEOUT
+ [WSS over h2]
+ expected:
+ if product == "epiphany" or product == "webkit": FAIL
+ if product == "safari": TIMEOUT
+
+
+[http2-websocket.sub.h2.any.worker.html]
+ expected:
+ if product == "safari": TIMEOUT
+ [WSS over h2]
+ expected:
+ if product == "epiphany" or product == "webkit": FAIL
+ if product == "safari": TIMEOUT
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/server/secure-context.https.any.js.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/server/secure-context.https.any.js.ini
new file mode 100644
index 0000000000..e795514ac3
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/server/secure-context.https.any.js.ini
@@ -0,0 +1,6 @@
+[secure-context.https.any.sharedworker.html]
+
+[secure-context.https.any.serviceworker.html]
+ [secure-context]
+ expected:
+ if product == "epiphany" or product == "webkit": FAIL # https://bugs.webkit.org/show_bug.cgi?id=200815
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/server/test-pac.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/server/test-pac.html.ini
new file mode 100644
index 0000000000..26ea697fe8
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/server/test-pac.html.ini
@@ -0,0 +1,4 @@
+[test-pac.html]
+ [test that PAC metadata is respected]
+ expected:
+ if product == "safari": FAIL # Safari WebDriver does not support PAC \ No newline at end of file
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/server/webtransport-h3.https.sub.any.js.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/server/webtransport-h3.https.sub.any.js.ini
new file mode 100644
index 0000000000..60d2e38eca
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/server/webtransport-h3.https.sub.any.js.ini
@@ -0,0 +1,29 @@
+[webtransport-h3.https.sub.any.html]
+ [WebTransport server should be running and should handle a bidirectional stream]
+ expected:
+ if product == "chrome" or product == "firefox": PASS
+ FAIL
+
+[webtransport-h3.https.sub.any.window.html]
+ [WebTransport server should be running and should handle a bidirectional stream]
+ expected:
+ if product == "chrome" or product == "firefox": PASS
+ FAIL
+
+[webtransport-h3.https.sub.any.worker.html]
+ [WebTransport server should be running and should handle a bidirectional stream]
+ expected:
+ if product == "chrome" or product == "firefox": PASS
+ FAIL
+
+[webtransport-h3.https.sub.any.sharedworker.html]
+ [WebTransport server should be running and should handle a bidirectional stream]
+ expected:
+ if product == "chrome" or product == "firefox": PASS
+ FAIL
+
+[webtransport-h3.https.sub.any.serviceworker.html]
+ [WebTransport server should be running and should handle a bidirectional stream]
+ expected:
+ if product == "chrome" or product == "firefox": PASS
+ FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/server/wpt-server-http.sub.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/server/wpt-server-http.sub.html.ini
new file mode 100644
index 0000000000..e2f26c7e4b
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/server/wpt-server-http.sub.html.ini
@@ -0,0 +1,20 @@
+[wpt-server-http.sub.html]
+ [HTTPS protocol, punycode subdomain #1]
+ expected:
+ if product == "epiphany" or product == "webkit": FAIL
+
+ [HTTPS protocol, www subdomain #1]
+ expected:
+ if product == "epiphany" or product == "webkit": FAIL
+
+ [HTTPS protocol, www subdomain #2]
+ expected:
+ if product == "epiphany" or product == "webkit": FAIL
+
+ [HTTPS protocol, www subdomain #3]
+ expected:
+ if product == "epiphany" or product == "webkit": FAIL
+
+ [HTTPS protocol, punycode subdomain #2]
+ expected:
+ if product == "epiphany" or product == "webkit": FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/server/wpt-server-websocket.sub.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/server/wpt-server-websocket.sub.html.ini
new file mode 100644
index 0000000000..2cc364b610
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/server/wpt-server-websocket.sub.html.ini
@@ -0,0 +1,41 @@
+[wpt-server-websocket.sub.html]
+ [WSS protocol, www subdomain #3]
+ expected:
+ if product == "epiphany" or product == "webkit": FAIL
+
+ [WSS protocol, punycode subdomain #1]
+ expected:
+ if product == "epiphany" or product == "webkit": FAIL
+
+ [WSS protocol, punycode subdomain #2]
+ expected:
+ if product == "epiphany" or product == "webkit": FAIL
+
+ [WSS protocol, www subdomain #1]
+ expected:
+ if product == "epiphany" or product == "webkit": FAIL
+
+ [WSS protocol, www subdomain #2]
+ expected:
+ if product == "epiphany" or product == "webkit": FAIL
+
+ [WSS protocol, www subdomain #3]
+ expected:
+ if product == "epiphany" or product == "webkit": FAIL
+
+ [WSS protocol, punycode subdomain #1]
+ expected:
+ if product == "epiphany" or product == "webkit": FAIL
+
+ [WSS protocol, punycode subdomain #2]
+ expected:
+ if product == "epiphany" or product == "webkit": FAIL
+
+ [WSS protocol, www subdomain #1]
+ expected:
+ if product == "epiphany" or product == "webkit": FAIL
+
+ [WSS protocol, www subdomain #2]
+ expected:
+ if product == "epiphany" or product == "webkit": FAIL
+
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/crossOrigin.sub.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/crossOrigin.sub.html.ini
new file mode 100644
index 0000000000..c4519f1ee8
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/crossOrigin.sub.html.ini
@@ -0,0 +1,4 @@
+[crossOrigin.sub.html]
+ [Actions in cross-origin iframe]
+ expected:
+ if product == "chrome": [PASS, FAIL]
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/eventOrder.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/eventOrder.html.ini
new file mode 100644
index 0000000000..94fb0e3f97
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/eventOrder.html.ini
@@ -0,0 +1,3 @@
+[eventOrder.html]
+ expected:
+ if (product == "epiphany") or (product == "webkit"): ERROR
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/mouseClickCount.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/mouseClickCount.html.ini
new file mode 100644
index 0000000000..15eda88934
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/mouseClickCount.html.ini
@@ -0,0 +1,4 @@
+[mouseClickCount.html]
+ [TestDriver actions: test the mouse click counts at different cases]
+ expected:
+ if product == "firefox" or product == "safari": FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/multiTouchPoints.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/multiTouchPoints.html.ini
new file mode 100644
index 0000000000..c8fd2d282f
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/multiTouchPoints.html.ini
@@ -0,0 +1,7 @@
+[multiTouchPoints.html]
+ expected:
+ if product == "epiphany" or product == "webkit": ERROR
+
+ [TestDriver actions: two touch points with one moving one pause]
+ expected:
+ if product == "safari": FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/multiTouchPointsReleaseFirstPoint.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/multiTouchPointsReleaseFirstPoint.html.ini
new file mode 100644
index 0000000000..ac49afe3d5
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/multiTouchPointsReleaseFirstPoint.html.ini
@@ -0,0 +1,4 @@
+[multiTouchPointsReleaseFirstPoint.html]
+ [TestDriver actions: two touch points with one moving one pause]
+ expected:
+ if product == "safari": FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/multiTouchPointsReleaseSecondPoint.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/multiTouchPointsReleaseSecondPoint.html.ini
new file mode 100644
index 0000000000..4c9aeb0a18
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/multiTouchPointsReleaseSecondPoint.html.ini
@@ -0,0 +1,5 @@
+[multiTouchPointsReleaseSecondPoint.html]
+ [TestDriver actions: two touch points with one moving one pause]
+ expected:
+ if product == "safari": FAIL
+ if product == "chrome": [PASS, FAIL]
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/multiTouchPointsSimultaneousMove.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/multiTouchPointsSimultaneousMove.html.ini
new file mode 100644
index 0000000000..e4d63b7eed
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/multiTouchPointsSimultaneousMove.html.ini
@@ -0,0 +1,5 @@
+[multiTouchPointsSimultaneousMove.html]
+ [TestDriver actions: two touch points with both moving]
+ expected:
+ if product == "chrome": [PASS, FAIL]
+ if product == "safari": FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/multiTouchPointsTwoTouchStarts.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/multiTouchPointsTwoTouchStarts.html.ini
new file mode 100644
index 0000000000..b0778ab8c5
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/multiTouchPointsTwoTouchStarts.html.ini
@@ -0,0 +1,4 @@
+[multiTouchPointsTwoTouchStarts.html]
+ [TestDriver actions: two touch points with one moving one pause]
+ expected:
+ if product == "safari": FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/multiTouchPointsWithPause.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/multiTouchPointsWithPause.html.ini
new file mode 100644
index 0000000000..56fa5edc68
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/multiTouchPointsWithPause.html.ini
@@ -0,0 +1,4 @@
+[multiTouchPointsWithPause.html]
+ [TestDriver actions: two touch points with one moving one pause]
+ expected:
+ if product == "safari": FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/pause.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/pause.html.ini
new file mode 100644
index 0000000000..657d2a2492
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/pause.html.ini
@@ -0,0 +1,3 @@
+[pause.html]
+ expected:
+ if product == "epiphany" or product == "webkit": ERROR
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/penPointerEventProperties.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/penPointerEventProperties.html.ini
new file mode 100644
index 0000000000..d808b1793c
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/penPointerEventProperties.html.ini
@@ -0,0 +1,6 @@
+[penPointerEventProperties.html]
+ expected:
+ if product == "firefox": ERROR
+ [TestDriver actions: pointerevent properties of pen type]
+ expected:
+ if product == "safari" or product == "firefox": FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/penPointerEvents.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/penPointerEvents.html.ini
new file mode 100644
index 0000000000..39e05a8f09
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/penPointerEvents.html.ini
@@ -0,0 +1,6 @@
+[penPointerEvents.html]
+ expected:
+ if product == "firefox": ERROR
+ [TestDriver actions: pointerevent properties of pen type]
+ expected:
+ if product == "safari": FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/touchPointerEventProperties.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/touchPointerEventProperties.html.ini
new file mode 100644
index 0000000000..6de2ea2601
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/touchPointerEventProperties.html.ini
@@ -0,0 +1,4 @@
+[touchPointerEventProperties.html]
+ [TestDriver actions: pointerevent properties of touch type]
+ expected:
+ if product == "safari": FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/wheelScroll.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/wheelScroll.html.ini
new file mode 100644
index 0000000000..5632dcf112
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/actions/wheelScroll.html.ini
@@ -0,0 +1,3 @@
+[wheelScroll.html]
+ expected:
+ if product == "epiphany": ERROR
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/click_iframe_crossorigin.sub.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/click_iframe_crossorigin.sub.html.ini
new file mode 100644
index 0000000000..aa94652ad7
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/click_iframe_crossorigin.sub.html.ini
@@ -0,0 +1,4 @@
+[click_iframe_crossorigin.sub.html]
+ [TestDriver click on a document in an iframe]
+ expected:
+ if product == "chrome": [PASS, FAIL] # https://github.com/web-platform-tests/wpt/issues/26295
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/file_upload.sub.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/file_upload.sub.html.ini
new file mode 100644
index 0000000000..a74028aaac
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/file_upload.sub.html.ini
@@ -0,0 +1,6 @@
+[file_upload.sub.html]
+ expected:
+ if product == "safari": TIMEOUT
+ [File upload using testdriver]
+ expected:
+ if (product == "epiphany") or (product == "webkit"): FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/generate_test_report.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/generate_test_report.html.ini
new file mode 100644
index 0000000000..726eea68b9
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/generate_test_report.html.ini
@@ -0,0 +1,4 @@
+[generate_test_report.html]
+ [TestDriver generate_test_report method]
+ expected:
+ if product == "firefox" or product == "epiphany" or product == "webkit": FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/set_permission.https.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/set_permission.https.html.ini
new file mode 100644
index 0000000000..026e682351
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/set_permission.https.html.ini
@@ -0,0 +1,8 @@
+[set_permission.https.html]
+ [Grant Permission]
+ expected:
+ if product != "chrome": FAIL
+
+ [Deny Permission]
+ expected:
+ if product != "chrome": FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/virtual_authenticator.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/virtual_authenticator.html.ini
new file mode 100644
index 0000000000..92cbbf3762
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testdriver/virtual_authenticator.html.ini
@@ -0,0 +1,31 @@
+[virtual_authenticator.html]
+ expected:
+ if product == "safari": ERROR
+
+ [Can create an authenticator]
+ expected:
+ if product != "chrome": FAIL
+
+ [Can add a credential]
+ expected:
+ if product != "chrome": FAIL
+
+ [Can get the credentials]
+ expected:
+ if product != "chrome": FAIL
+
+ [Can remove a credential]
+ expected:
+ if product != "chrome": FAIL
+
+ [Can remove all credentials]
+ expected:
+ if product != "chrome": FAIL
+
+ [Can set user verified]
+ expected:
+ if product != "chrome": FAIL
+
+ [Can remove a virtual authenticator]
+ expected:
+ if product != "chrome": FAIL
diff --git a/testing/web-platform/tests/infrastructure/metadata/infrastructure/testharness/lone-surrogates.html.ini b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testharness/lone-surrogates.html.ini
new file mode 100644
index 0000000000..6505d896a9
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/infrastructure/testharness/lone-surrogates.html.ini
@@ -0,0 +1,7 @@
+[lone-surrogates.html]
+ [failing test with lone surrogate in assert]
+ expected: FAIL
+
+ [failing test with lone surrogate U+d800 in name]
+ expected: FAIL
+
diff --git a/testing/web-platform/tests/infrastructure/metadata/update_properties.json b/testing/web-platform/tests/infrastructure/metadata/update_properties.json
new file mode 100644
index 0000000000..00909d956b
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/metadata/update_properties.json
@@ -0,0 +1 @@
+{"properties": ["product"]}
diff --git a/testing/web-platform/tests/infrastructure/reftest-wait-ref.html b/testing/web-platform/tests/infrastructure/reftest-wait-ref.html
new file mode 100644
index 0000000000..6772c2c460
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest-wait-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title>Reference for Test infrastructure should support 'reftest-wait'</title>
+<style>
+.marker {
+ margin-bottom: 10px;
+ background: green;
+ height: 50px;
+ width: 50px;
+}
+</style>
+
+<div class="marker"></div>
+<div>The box above should be green.</div>
diff --git a/testing/web-platform/tests/infrastructure/reftest-wait.html b/testing/web-platform/tests/infrastructure/reftest-wait.html
new file mode 100644
index 0000000000..c2e9986ad8
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest-wait.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>Test infrastructure should support 'reftest-wait'</title>
+<link rel="match" href="reftest-wait-ref.html">
+<style>
+.marker {
+ margin-bottom: 10px;
+ background: red;
+ height: 50px;
+ width: 50px;
+}
+</style>
+<script>
+setTimeout(function() {
+ document.querySelector(".marker").style.background = 'green';
+ document.documentElement.classList.remove("reftest-wait");
+}, 1000);
+</script>
+<div class="marker"></div>
+<div>The box above should be green.</div>
+</html>
diff --git a/testing/web-platform/tests/infrastructure/reftest/fuzzy-ref-1.html b/testing/web-platform/tests/infrastructure/reftest/fuzzy-ref-1.html
new file mode 100644
index 0000000000..e50fc11ef6
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/fuzzy-ref-1.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+}
+</style>
+<div></div>
diff --git a/testing/web-platform/tests/infrastructure/reftest/green-ref.html b/testing/web-platform/tests/infrastructure/reftest/green-ref.html
new file mode 100644
index 0000000000..0e145d60b5
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/green-ref.html
@@ -0,0 +1,4 @@
+<link rel=match href=green.html>
+<style>
+:root {background-color:green}
+</style> \ No newline at end of file
diff --git a/testing/web-platform/tests/infrastructure/reftest/green.html b/testing/web-platform/tests/infrastructure/reftest/green.html
new file mode 100644
index 0000000000..38167bb58d
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/green.html
@@ -0,0 +1,3 @@
+<style>
+:root {background-color:green}
+</style> \ No newline at end of file
diff --git a/testing/web-platform/tests/infrastructure/reftest/legacy/README.md b/testing/web-platform/tests/infrastructure/reftest/legacy/README.md
new file mode 100644
index 0000000000..01bb6f773e
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/legacy/README.md
@@ -0,0 +1,5 @@
+This directory contains the old reftest chaining tests, based on how they worked prior to
+[RFC #15](https://github.com/web-platform-tests/rfcs/blob/master/rfcs/reftest_simplification.md).
+
+The expectations for these match the current logic; these are included here so we have
+tests that fail if any external runner is implementing this logic.
diff --git a/testing/web-platform/tests/infrastructure/reftest/legacy/fuzzy-ref-2.html b/testing/web-platform/tests/infrastructure/reftest/legacy/fuzzy-ref-2.html
new file mode 100644
index 0000000000..cdaf6446ed
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/legacy/fuzzy-ref-2.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<!-- This will only match with the fuzzy set in the ini file -->
+<link rel="match" href="fuzzy-ref-2a.html">
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+}
+</style>
+<div></div>
diff --git a/testing/web-platform/tests/infrastructure/reftest/legacy/fuzzy-ref-2a.html b/testing/web-platform/tests/infrastructure/reftest/legacy/fuzzy-ref-2a.html
new file mode 100644
index 0000000000..99da3203af
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/legacy/fuzzy-ref-2a.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<style>
+div {
+ width: 101px;
+ height: 100px;
+ background-color: green;
+}
+</style>
+<div></div>
diff --git a/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_and_fail.html b/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_and_fail.html
new file mode 100644
index 0000000000..2960195356
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_and_fail.html
@@ -0,0 +1,5 @@
+<title>Reftest chain that should fail</title>
+<link rel=match href=reftest_and_fail_0-ref.html>
+<style>
+:root {background-color:green}
+</style> \ No newline at end of file
diff --git a/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_and_fail_0-ref.html b/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_and_fail_0-ref.html
new file mode 100644
index 0000000000..565f663ed5
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_and_fail_0-ref.html
@@ -0,0 +1,5 @@
+<title>Reftest chain that should fail</title>
+<link rel=match href=../red.html>
+<style>
+:root {background-color:green}
+</style>
diff --git a/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_and_mismatch.html b/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_and_mismatch.html
new file mode 100644
index 0000000000..b6b4847473
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_and_mismatch.html
@@ -0,0 +1,5 @@
+<title>Reftest chain with mismatch and mismatch</title>
+<link rel=mismatch href=reftest_and_mismatch_0.html>
+<style>
+:root {background-color:green}
+</style>
diff --git a/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_and_mismatch_0.html b/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_and_mismatch_0.html
new file mode 100644
index 0000000000..f84ce6a13a
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_and_mismatch_0.html
@@ -0,0 +1,5 @@
+<title>Reftest chain with mismatch and mismatch</title>
+<link rel=mismatch href=reftest_and_mismatch_1.html>
+<style>
+:root {background-color:blue}
+</style>
diff --git a/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_and_mismatch_1.html b/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_and_mismatch_1.html
new file mode 100644
index 0000000000..05e905adaf
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_and_mismatch_1.html
@@ -0,0 +1,4 @@
+<title>Reftest chain with match and mismatch</title>
+<style>
+:root {background-color:green}
+</style>
diff --git a/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_cycle.html b/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_cycle.html
new file mode 100644
index 0000000000..4a84a3b674
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_cycle.html
@@ -0,0 +1,5 @@
+<title>Reftest with cycle, all match</title>
+<link rel=match href=reftest_cycle_0-ref.html>
+<style>
+:root {background-color:green}
+</style> \ No newline at end of file
diff --git a/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_cycle_0-ref.html b/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_cycle_0-ref.html
new file mode 100644
index 0000000000..118bfd8844
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_cycle_0-ref.html
@@ -0,0 +1,5 @@
+<title>OR match that should pass</title>
+<link rel=match href=reftest_cycle_1-ref.html>
+<style>
+:root {background-color:green}
+</style> \ No newline at end of file
diff --git a/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_cycle_1-ref.html b/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_cycle_1-ref.html
new file mode 100644
index 0000000000..59be0b641d
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_cycle_1-ref.html
@@ -0,0 +1,5 @@
+<title>Reftest with cycle, all match</title>
+<link rel=match href=reftest_cycle.html>
+<style>
+:root {background-color:green}
+</style> \ No newline at end of file
diff --git a/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_cycle_fail.html b/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_cycle_fail.html
new file mode 100644
index 0000000000..175e76c4cc
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_cycle_fail.html
@@ -0,0 +1,5 @@
+<title>Reftest with cycle, fails</title>
+<link rel=match href=reftest_cycle_fail_0-ref.html>
+<style>
+:root {background-color:green}
+</style> \ No newline at end of file
diff --git a/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_cycle_fail_0-ref.html b/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_cycle_fail_0-ref.html
new file mode 100644
index 0000000000..c8e548c462
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_cycle_fail_0-ref.html
@@ -0,0 +1,5 @@
+<title>Reftest with cycle, fails</title>
+<link rel=mismatch href=reftest_cycle_fail.html>
+<style>
+:root {background-color:green}
+</style> \ No newline at end of file
diff --git a/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_fuzzy_chain_ini.html b/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_fuzzy_chain_ini.html
new file mode 100644
index 0000000000..4353379ddb
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/legacy/reftest_fuzzy_chain_ini.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<link rel=match href=fuzzy-ref-2.html>
+<!-- The metadata is added to the corresponding ini file -->
+<style>
+div {
+ width: 99px;
+ height: 100px;
+ background-color: green;
+}
+</style>
+<div></div>
diff --git a/testing/web-platform/tests/infrastructure/reftest/red.html b/testing/web-platform/tests/infrastructure/reftest/red.html
new file mode 100644
index 0000000000..2b677e0063
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/red.html
@@ -0,0 +1,3 @@
+<style>
+:root {background-color:red}
+</style> \ No newline at end of file
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest.https.html b/testing/web-platform/tests/infrastructure/reftest/reftest.https.html
new file mode 100644
index 0000000000..5a45f10f35
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest.https.html
@@ -0,0 +1,9 @@
+<link rel=match href=green.html>
+<style>
+:root {background-color:red}
+</style>
+<script>
+if (window.location.protocol === "https:") {
+ document.documentElement.style.backgroundColor = "green";
+}
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest.www.sub.html b/testing/web-platform/tests/infrastructure/reftest/reftest.www.sub.html
new file mode 100644
index 0000000000..ccffd98f43
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest.www.sub.html
@@ -0,0 +1,10 @@
+<title>Tests that reftests obey the 'www' file-flag</title>
+<link rel=match href=green.html>
+<style>
+:root {background-color:red}
+</style>
+<script>
+if (location.hostname === "{{domains[www]}}") {
+ document.documentElement.style.backgroundColor = "green";
+}
+</script>
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_fuzzy_1.html b/testing/web-platform/tests/infrastructure/reftest/reftest_fuzzy_1.html
new file mode 100644
index 0000000000..1930fe0ae8
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_fuzzy_1.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<link rel=match href=fuzzy-ref-1.html>
+<meta name=fuzzy content="fuzzy-ref-1.html:255;100">
+<style>
+div {
+ width: 99px;
+ height: 100px;
+ background-color: green;
+}
+</style>
+<div></div>
+
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_fuzzy_ini_full.html b/testing/web-platform/tests/infrastructure/reftest/reftest_fuzzy_ini_full.html
new file mode 100644
index 0000000000..7429025798
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_fuzzy_ini_full.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<link rel=match href=fuzzy-ref-1.html>
+<!-- This meta is overridden in the corresponding ini file -->
+<meta name=fuzzy content="fuzzy-ref-1.html:128;100">
+<style>
+div {
+ width: 99px;
+ height: 100px;
+ background-color: green;
+}
+</style>
+<div></div>
+
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_fuzzy_ini_ref_only.html b/testing/web-platform/tests/infrastructure/reftest/reftest_fuzzy_ini_ref_only.html
new file mode 100644
index 0000000000..7429025798
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_fuzzy_ini_ref_only.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<link rel=match href=fuzzy-ref-1.html>
+<!-- This meta is overridden in the corresponding ini file -->
+<meta name=fuzzy content="fuzzy-ref-1.html:128;100">
+<style>
+div {
+ width: 99px;
+ height: 100px;
+ background-color: green;
+}
+</style>
+<div></div>
+
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_fuzzy_ini_short.html b/testing/web-platform/tests/infrastructure/reftest/reftest_fuzzy_ini_short.html
new file mode 100644
index 0000000000..7429025798
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_fuzzy_ini_short.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<link rel=match href=fuzzy-ref-1.html>
+<!-- This meta is overridden in the corresponding ini file -->
+<meta name=fuzzy content="fuzzy-ref-1.html:128;100">
+<style>
+div {
+ width: 99px;
+ height: 100px;
+ background-color: green;
+}
+</style>
+<div></div>
+
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_fuzzy_no_differences.html b/testing/web-platform/tests/infrastructure/reftest/reftest_fuzzy_no_differences.html
new file mode 100644
index 0000000000..95863904aa
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_fuzzy_no_differences.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<link rel=match href=fuzzy-ref-1.html>
+<!-- This exactly matches the reference, and includes the possibility of
+ 0 pixels different; in this case the maxDifference is ignored --->
+<meta name=fuzzy content="fuzzy-ref-1.html:128;0-100">
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+}
+</style>
+<div></div>
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_fuzzy_no_differences_1.html b/testing/web-platform/tests/infrastructure/reftest/reftest_fuzzy_no_differences_1.html
new file mode 100644
index 0000000000..9513f9bda8
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_fuzzy_no_differences_1.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<link rel=match href=fuzzy-ref-1.html>
+<!-- This exactly matches the reference, and includes the possibility of
+ 0 difference in the color channel; in this case the pixelsDifferent is ignored --->
+<meta name=fuzzy content="fuzzy-ref-1.html:0-128;100">
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+}
+</style>
+<div></div>
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_match-print-ref.html b/testing/web-platform/tests/infrastructure/reftest/reftest_match-print-ref.html
new file mode 100644
index 0000000000..5bc16469c8
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_match-print-ref.html
@@ -0,0 +1,13 @@
+<title></title>
+<meta name="reftest-pages" content="1-2">
+<style>
+* {margin: 0; padding:0}
+/* This should be 192px (2 inches at 96dpi), but the default margin on body reduces it to 180px */
+div {height:180px;}
+</style>
+<div>
+page 1
+</div>
+<div>
+page 2
+</div>
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_match-print.html b/testing/web-platform/tests/infrastructure/reftest/reftest_match-print.html
new file mode 100644
index 0000000000..1b979db965
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_match-print.html
@@ -0,0 +1,12 @@
+<title>rel=match that should pass</title>
+<link rel=match href=reftest_match-print-ref.html>
+<style>
+* {margin: 0; padding:0}
+div {page-break-after: always;}
+</style>
+<div>
+page 1
+</div>
+<div>
+page 2
+</div>
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_match.html b/testing/web-platform/tests/infrastructure/reftest/reftest_match.html
new file mode 100644
index 0000000000..333cc6c1ec
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_match.html
@@ -0,0 +1,5 @@
+<title>rel=match that should pass</title>
+<link rel=match href=green.html>
+<style>
+:root {background-color:green}
+</style> \ No newline at end of file
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-0.html b/testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-0.html
new file mode 100644
index 0000000000..9f52615a64
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-0.html
@@ -0,0 +1,6 @@
+<title>AND match/mismatch that should fail</title>
+<link rel=match href=red.html>
+<link rel=mismatch href=red.html?2>
+<style>
+:root {background-color:red}
+</style>
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-1.html b/testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-1.html
new file mode 100644
index 0000000000..1bba49ea0d
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-1.html
@@ -0,0 +1,6 @@
+<title>AND match/mismatch that should fail</title>
+<link rel=mismatch href=red.html>
+<link rel=match href=red.html?2>
+<style>
+:root {background-color:red}
+</style>
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-2.html b/testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-2.html
new file mode 100644
index 0000000000..60141aedf8
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-2.html
@@ -0,0 +1,7 @@
+<title>OR match AND mismatch that should pass</title>
+<link rel=match href=red.html>
+<link rel=match href=green.html>
+<link rel=mismatch href=red.html?2>
+<style>
+:root {background-color:green}
+</style>
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-3.html b/testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-3.html
new file mode 100644
index 0000000000..f707c1b13f
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-3.html
@@ -0,0 +1,7 @@
+<title>OR match AND mismatch that should pass</title>
+<link rel=mismatch href=red.html>
+<link rel=match href=green.html>
+<link rel=match href=red.html?2>
+<style>
+:root {background-color:green}
+</style>
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-4.html b/testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-4.html
new file mode 100644
index 0000000000..ac08cb70b6
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-4.html
@@ -0,0 +1,7 @@
+<title>OR match AND mismatch that should fail</title>
+<link rel=match href=green.html>
+<link rel=match href=red.html>
+<link rel=mismatch href=red.html?2>
+<style>
+:root {background-color:red}
+</style>
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-5.html b/testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-5.html
new file mode 100644
index 0000000000..b30d84a2dd
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-5.html
@@ -0,0 +1,7 @@
+<title>OR match AND mismatch that should fail</title>
+<link rel=match href=red.html>
+<link rel=match href=green.html>
+<link rel=mismatch href=red.html?2>
+<style>
+:root {background-color:red}
+</style>
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-6.html b/testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-6.html
new file mode 100644
index 0000000000..1a2dcc204a
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-6.html
@@ -0,0 +1,8 @@
+<title>OR match AND mismatch that should fail</title>
+<link rel=match href=green.html>
+<link rel=match href=red.html>
+<link rel=mismatch href=green.html?2>
+<link rel=mismatch href=red.html?2>
+<style>
+:root {background-color:red}
+</style>
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-7.html b/testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-7.html
new file mode 100644
index 0000000000..073e220611
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_match_and_mismatch-7.html
@@ -0,0 +1,8 @@
+<title>OR match AND mismatch that should fail</title>
+<link rel=match href=green.html>
+<link rel=match href=red.html>
+<link rel=mismatch href=red.html?2>
+<link rel=mismatch href=green.html?2>
+<style>
+:root {background-color:red}
+</style>
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_match_fail-print.html b/testing/web-platform/tests/infrastructure/reftest/reftest_match_fail-print.html
new file mode 100644
index 0000000000..92c5fa6a69
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_match_fail-print.html
@@ -0,0 +1,12 @@
+<title>rel=match that should fail</title>
+<link rel=match href=reftest_match-print-ref.html>
+<style>
+* {margin: 0; padding:0}
+div {page-break-after: always;}
+</style>
+<div>
+page 1
+</div>
+<div>
+Another page
+</div>
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_match_fail.html b/testing/web-platform/tests/infrastructure/reftest/reftest_match_fail.html
new file mode 100644
index 0000000000..a9272ef74d
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_match_fail.html
@@ -0,0 +1,5 @@
+<title>rel=match that should fail</title>
+<link rel=match href=red.html>
+<style>
+:root {background-color:green}
+</style> \ No newline at end of file
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_mismatch-num-pages-print.html b/testing/web-platform/tests/infrastructure/reftest/reftest_mismatch-num-pages-print.html
new file mode 100644
index 0000000000..5efb590653
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_mismatch-num-pages-print.html
@@ -0,0 +1,3 @@
+<!doctype html>
+<link rel=mismatch href=reftest_match-print-ref.html>
+<!-- Should be only one page, while the reference has two. The test should pass -->
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_mismatch-print.html b/testing/web-platform/tests/infrastructure/reftest/reftest_mismatch-print.html
new file mode 100644
index 0000000000..5fd4a7f52a
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_mismatch-print.html
@@ -0,0 +1,13 @@
+<title>rel=mismatch that should PASS</title>
+<link rel=mismatch href=reftest_match-print-ref.html>
+<meta name="reftest-pages" content="reftest_match-print-ref.html:1-2">
+<style>
+* {margin: 0; padding:0}
+div {page-break-after: always;}
+</style>
+<div>
+page 1
+</div>
+<div>
+page 3
+</div>
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_mismatch.html b/testing/web-platform/tests/infrastructure/reftest/reftest_mismatch.html
new file mode 100644
index 0000000000..af5fa0750d
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_mismatch.html
@@ -0,0 +1,5 @@
+<title>rel=mismatch that should pass</title>
+<link rel=mismatch href=red.html>
+<style>
+:root {background-color:green}
+</style> \ No newline at end of file
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_mismatch_fail-print.html b/testing/web-platform/tests/infrastructure/reftest/reftest_mismatch_fail-print.html
new file mode 100644
index 0000000000..afec2ef51f
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_mismatch_fail-print.html
@@ -0,0 +1,13 @@
+<title>rel=mismatch that should FAIL</title>
+<link rel=mismatch href=reftest_match-print-ref.html>
+<meta name="reftest-pages" content="reftest_match-print-ref.html:1-2">
+<style>
+* {margin: 0; padding:0}
+div {page-break-after: always;}
+</style>
+<div>
+page 1
+</div>
+<div>
+page 2
+</div>
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_mismatch_fail.html b/testing/web-platform/tests/infrastructure/reftest/reftest_mismatch_fail.html
new file mode 100644
index 0000000000..8d160c4fc2
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_mismatch_fail.html
@@ -0,0 +1,5 @@
+<title>rel=mismatch that should fail</title>
+<link rel=mismatch href=green.html>
+<style>
+:root {background-color:green}
+</style> \ No newline at end of file
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_mismatch_page_margins-print.html b/testing/web-platform/tests/infrastructure/reftest/reftest_mismatch_page_margins-print.html
new file mode 100644
index 0000000000..62c925927e
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_mismatch_page_margins-print.html
@@ -0,0 +1,13 @@
+<title>print-reftest should respect @page margins</title>
+<link rel=mismatch href=reftest_match-print-ref.html>
+<style>
+* {margin: 0; padding:0}
+@page {margin: 0;}
+div {page-break-after: always;}
+</style>
+<div>
+page 1
+</div>
+<div>
+page 2
+</div>
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_multiple_match-0.html b/testing/web-platform/tests/infrastructure/reftest/reftest_multiple_match-0.html
new file mode 100644
index 0000000000..3a51de2164
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_multiple_match-0.html
@@ -0,0 +1,6 @@
+<title>OR match that should pass</title>
+<link rel=match href=red.html>
+<link rel=match href=green.html>
+<style>
+:root {background-color:green}
+</style> \ No newline at end of file
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_multiple_match-1.html b/testing/web-platform/tests/infrastructure/reftest/reftest_multiple_match-1.html
new file mode 100644
index 0000000000..9a8b769d65
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_multiple_match-1.html
@@ -0,0 +1,6 @@
+<title>OR match that should pass</title>
+<link rel=match href=green.html>
+<link rel=match href=red.html>
+<style>
+:root {background-color:green}
+</style>
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_multiple_mismatch-0.html b/testing/web-platform/tests/infrastructure/reftest/reftest_multiple_mismatch-0.html
new file mode 100644
index 0000000000..b0115a7551
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_multiple_mismatch-0.html
@@ -0,0 +1,6 @@
+<title>AND mismatch that should fail</title>
+<link rel=mismatch href=green.html>
+<link rel=mismatch href=red.html>
+<style>
+:root {background-color:red}
+</style>
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_multiple_mismatch-1.html b/testing/web-platform/tests/infrastructure/reftest/reftest_multiple_mismatch-1.html
new file mode 100644
index 0000000000..65ddd34324
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_multiple_mismatch-1.html
@@ -0,0 +1,6 @@
+<title>AND mismatch that should fail</title>
+<link rel=mismatch href=red.html>
+<link rel=mismatch href=green.html>
+<style>
+:root {background-color:red}
+</style>
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_ref_timeout-ref.html b/testing/web-platform/tests/infrastructure/reftest/reftest_ref_timeout-ref.html
new file mode 100644
index 0000000000..2f52c05979
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_ref_timeout-ref.html
@@ -0,0 +1,5 @@
+<html class="reftest-wait">
+<title>rel=match that should time out in the ref</title>
+<style>
+:root {background-color:green}
+</style>
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_ref_timeout.html b/testing/web-platform/tests/infrastructure/reftest/reftest_ref_timeout.html
new file mode 100644
index 0000000000..aaf68f5cb5
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_ref_timeout.html
@@ -0,0 +1,6 @@
+<html>
+<title>rel=match that should time out in the ref</title>
+<link rel=match href=reftest_ref_timeout-ref.html>
+<style>
+:root {background-color:green}
+</style>
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_timeout.html b/testing/web-platform/tests/infrastructure/reftest/reftest_timeout.html
new file mode 100644
index 0000000000..b10e676bf0
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_timeout.html
@@ -0,0 +1,6 @@
+<html class="reftest-wait">
+<title>rel=match that should timeout</title>
+<link rel=match href=green.html>
+<style>
+:root {background-color:green}
+</style>
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_wait_0.html b/testing/web-platform/tests/infrastructure/reftest/reftest_wait_0.html
new file mode 100644
index 0000000000..fec62a3cae
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_wait_0.html
@@ -0,0 +1,13 @@
+<html class="reftest-wait">
+<title>Test with reftest-wait</title>
+<link rel=match href=green.html>
+<style>
+:root {background-color:red}
+</style>
+<script>
+setTimeout(function() {
+ document.documentElement.style.backgroundColor = "green";
+ document.documentElement.className = "";
+}, 2000);
+</script>
+</html>
diff --git a/testing/web-platform/tests/infrastructure/reftest/reftest_wait_TestRendered.html b/testing/web-platform/tests/infrastructure/reftest/reftest_wait_TestRendered.html
new file mode 100644
index 0000000000..4316d338b5
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/reftest_wait_TestRendered.html
@@ -0,0 +1,14 @@
+<html class="reftest-wait">
+<title>Test with reftest-wait</title>
+<link rel=match href=green.html>
+<style>
+:root {background-color:red}
+</style>
+<script>
+document.addEventListener("TestRendered",
+ function() {
+ document.documentElement.style.backgroundColor = "green";
+ document.documentElement.className = "";
+ });
+</script>
+</html>
diff --git a/testing/web-platform/tests/infrastructure/reftest/size-ref.html b/testing/web-platform/tests/infrastructure/reftest/size-ref.html
new file mode 100644
index 0000000000..bb792a3feb
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/size-ref.html
@@ -0,0 +1,2 @@
+<!doctype html>
+<p>innerWidth x innerHeight: <span>800x600</span></p>
diff --git a/testing/web-platform/tests/infrastructure/reftest/size.html b/testing/web-platform/tests/infrastructure/reftest/size.html
new file mode 100644
index 0000000000..a60befbf03
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/reftest/size.html
@@ -0,0 +1,6 @@
+<!doctype html>
+<link rel=match href=size-ref.html>
+<p>innerWidth x innerHeight: <span id=size></span></p>
+<script>
+document.querySelector("#size").textContent = window.innerWidth + "x" + window.innerHeight;
+</script>
diff --git a/testing/web-platform/tests/infrastructure/resources/ok.txt b/testing/web-platform/tests/infrastructure/resources/ok.txt
new file mode 100644
index 0000000000..a0aba9318a
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/resources/ok.txt
@@ -0,0 +1 @@
+OK \ No newline at end of file
diff --git a/testing/web-platform/tests/infrastructure/resources/ok.txt.headers b/testing/web-platform/tests/infrastructure/resources/ok.txt.headers
new file mode 100644
index 0000000000..23de552c1a
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/resources/ok.txt.headers
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: * \ No newline at end of file
diff --git a/testing/web-platform/tests/infrastructure/server/context.any.js b/testing/web-platform/tests/infrastructure/server/context.any.js
new file mode 100644
index 0000000000..11ab76d874
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/server/context.any.js
@@ -0,0 +1,13 @@
+// META: global=window,dedicatedworker,sharedworker,serviceworker,dedicatedworker-module,sharedworker-module,serviceworker-module
+test(t => {
+ // Test for object that's only exposed in serviceworker
+ if (self.clients) {
+ assert_true(self.isSecureContext);
+ assert_equals(location.protocol, "https:");
+ } else {
+ assert_false(self.isSecureContext);
+ assert_equals(location.protocol, "http:");
+ }
+});
+
+done();
diff --git a/testing/web-platform/tests/infrastructure/server/http2-context.sub.h2.any.js b/testing/web-platform/tests/infrastructure/server/http2-context.sub.h2.any.js
new file mode 100644
index 0000000000..26f7007418
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/server/http2-context.sub.h2.any.js
@@ -0,0 +1,12 @@
+// META: global=window,dedicatedworker,sharedworker,serviceworker
+test(() => {
+ assert_true(self.isSecureContext);
+}, "Use of .h2. file name flag implies secure context");
+
+test(() => {
+ assert_equals(location.protocol, "https:");
+}, "Use of .h2. file name flag implies HTTPS scheme");
+
+test(() => {
+ assert_equals(location.port, "{{ports[h2][0]}}");
+}, "Use of .h2. file name flag implies correct port");
diff --git a/testing/web-platform/tests/infrastructure/server/http2-websocket.sub.h2.any.js b/testing/web-platform/tests/infrastructure/server/http2-websocket.sub.h2.any.js
new file mode 100644
index 0000000000..617f9ca4e0
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/server/http2-websocket.sub.h2.any.js
@@ -0,0 +1,20 @@
+function check(protocol, domain, port, done) {
+ var url = protocol + '://' + domain + ':' + port + '/echo';
+ var ws = new WebSocket(url);
+
+ ws.addEventListener('error', function() {
+ done(false);
+ });
+
+ ws.addEventListener('open', function() {
+ done(true);
+ });
+}
+
+async_test(function(t) {
+ check('wss', '{{browser_host}}', {{ports[h2][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'WSS over h2');
diff --git a/testing/web-platform/tests/infrastructure/server/order-of-metas.any.js b/testing/web-platform/tests/infrastructure/server/order-of-metas.any.js
new file mode 100644
index 0000000000..20f678475c
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/server/order-of-metas.any.js
@@ -0,0 +1,10 @@
+// META: global=window,dedicatedworker,sharedworker
+// META: script=resources/expect-seen-testharness.js
+// META: timeout=long
+// META: title=foo
+// META: script=resources/expect-global.js
+// META: script=resources/expect-title-meta.js
+
+test(() => {
+ assert_array_equals(scripts, ['expect-seen-testharness.js', 'expect-global.js', 'expect-title-meta.js']);
+}, "order of scripts");
diff --git a/testing/web-platform/tests/infrastructure/server/order-of-metas.window.js b/testing/web-platform/tests/infrastructure/server/order-of-metas.window.js
new file mode 100644
index 0000000000..ec2848056a
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/server/order-of-metas.window.js
@@ -0,0 +1,8 @@
+// META: script=resources/expect-seen-testharness.js
+// META: timeout=long
+// META: title=foo
+// META: script=resources/expect-title-meta.js
+
+test(() => {
+ assert_array_equals(scripts, ['expect-seen-testharness.js', 'expect-title-meta.js']);
+}, "order of scripts");
diff --git a/testing/web-platform/tests/infrastructure/server/resources/expect-global.js b/testing/web-platform/tests/infrastructure/server/resources/expect-global.js
new file mode 100644
index 0000000000..63d4944e61
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/server/resources/expect-global.js
@@ -0,0 +1,5 @@
+test(() => {
+ assert_true('GLOBAL' in self);
+}, 'GLOBAL exists');
+
+scripts.push('expect-global.js');
diff --git a/testing/web-platform/tests/infrastructure/server/resources/expect-seen-testharness.js b/testing/web-platform/tests/infrastructure/server/resources/expect-seen-testharness.js
new file mode 100644
index 0000000000..29af1fca55
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/server/resources/expect-seen-testharness.js
@@ -0,0 +1,5 @@
+test(() => {
+ assert_true('add_completion_callback' in self);
+}, 'add_completion_callback exists');
+
+var scripts = ['expect-seen-testharness.js'];
diff --git a/testing/web-platform/tests/infrastructure/server/resources/expect-title-meta.js b/testing/web-platform/tests/infrastructure/server/resources/expect-title-meta.js
new file mode 100644
index 0000000000..d17588a18f
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/server/resources/expect-title-meta.js
@@ -0,0 +1,11 @@
+if (!self.GLOBAL || self.GLOBAL.isWindow()) {
+ test(() => {
+ assert_equals(document.title, "foo");
+ }, '<title> exists');
+
+ test(() => {
+ assert_equals(document.querySelectorAll("meta[name=timeout][content=long]").length, 1);
+ }, '<meta name=timeout> exists');
+}
+
+scripts.push('expect-title-meta.js');
diff --git a/testing/web-platform/tests/infrastructure/server/resources/proxy.sub.pac b/testing/web-platform/tests/infrastructure/server/resources/proxy.sub.pac
new file mode 100644
index 0000000000..78ce023448
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/server/resources/proxy.sub.pac
@@ -0,0 +1,7 @@
+function FindProxyForURL(url, host) {
+ if (dnsDomainIs(host, '.wpt.test')) {
+ return "PROXY 127.0.0.1:{{ports[http][0]}}"
+ }
+
+ return "DIRECT";
+}
diff --git a/testing/web-platform/tests/infrastructure/server/secure-context.https.any.js b/testing/web-platform/tests/infrastructure/server/secure-context.https.any.js
new file mode 100644
index 0000000000..626fa70069
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/server/secure-context.https.any.js
@@ -0,0 +1,10 @@
+// META: global=window,dedicatedworker,sharedworker,serviceworker
+test(() => {
+ assert_true(self.isSecureContext);
+}, "Use of .https file name flag implies secure context");
+
+test(() => {
+ assert_equals(location.protocol, "https:");
+}, "Use of .https file name flag implies HTTPS scheme");
+
+done();
diff --git a/testing/web-platform/tests/infrastructure/server/subdomain-flag.www.sub.window.js b/testing/web-platform/tests/infrastructure/server/subdomain-flag.www.sub.window.js
new file mode 100644
index 0000000000..9b4140340a
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/server/subdomain-flag.www.sub.window.js
@@ -0,0 +1,5 @@
+test(() => {
+ assert_equals(location.hostname, "{{domains[www]}}");
+}, "Use of .www. file name flag implies www subdomain");
+
+done();
diff --git a/testing/web-platform/tests/infrastructure/server/test-pac.html b/testing/web-platform/tests/infrastructure/server/test-pac.html
new file mode 100644
index 0000000000..598836d376
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/server/test-pac.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<title>test behavior of PROXY configuration (PAC)</title>
+<meta name="pac" content="resources/proxy.sub.pac">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ promise_test(async t => {
+ const response = await fetch('http://not-a-real-domain.wpt.test/infrastructure/resources/ok.txt');
+ const text = await response.text();
+ assert_equals(text, 'OK');
+ }, 'test that PAC metadata is respected');
+</script>
diff --git a/testing/web-platform/tests/infrastructure/server/title.any.js b/testing/web-platform/tests/infrastructure/server/title.any.js
new file mode 100644
index 0000000000..df2f8b048c
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/server/title.any.js
@@ -0,0 +1,13 @@
+// META: global=window,dedicatedworker,sharedworker
+// META: title=foobar
+test(t => {
+ if (GLOBAL.isWindow()) {
+ assert_equals(document.title, 'foobar');
+ assert_false('META_TITLE' in self);
+ } else {
+ assert_equals(META_TITLE, 'foobar');
+ }
+ assert_equals(t.name, 'foobar');
+});
+
+done();
diff --git a/testing/web-platform/tests/infrastructure/server/webtransport-h3.https.sub.any.js b/testing/web-platform/tests/infrastructure/server/webtransport-h3.https.sub.any.js
new file mode 100644
index 0000000000..1a0c10031d
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/server/webtransport-h3.https.sub.any.js
@@ -0,0 +1,26 @@
+// META: global=window,worker
+// META: script=/common/get-host-info.sub.js
+
+const HOST = get_host_info().ORIGINAL_HOST;
+const PORT = '{{ports[webtransport-h3][0]}}';
+const BASE = `https://${HOST}:${PORT}`;
+
+promise_test(async t => {
+ const wt = new WebTransport(`${BASE}/webtransport/handlers/echo.py`);
+ // When a connection fails `closed` attribute will be rejected.
+ wt.closed.catch((error) => {
+ t.unreached_func(`The 'closed' attribute should not be rejected: ${error}`);
+ });
+ await wt.ready;
+
+ const stream = await wt.createBidirectionalStream();
+
+ const writer = stream.writable.getWriter();
+ await writer.write(new Uint8Array([42]));
+ writer.releaseLock();
+
+ const reader = stream.readable.getReader();
+ const { value } = await reader.read();
+
+ assert_equals(value[0], 42);
+}, "WebTransport server should be running and should handle a bidirectional stream");
diff --git a/testing/web-platform/tests/infrastructure/server/wpt-server-http.sub.html b/testing/web-platform/tests/infrastructure/server/wpt-server-http.sub.html
new file mode 100644
index 0000000000..8d71e7e3a2
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/server/wpt-server-http.sub.html
@@ -0,0 +1,262 @@
+<!doctype html>
+<html>
+ <head>
+ <title>WPT Server checker</title>
+ <meta charset="utf-8" />
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+</body>
+<body>
+<script>
+function check(protocol, domain, port, done) {
+ var scheme = protocol == "h2" ? "https" : protocol;
+ var url = scheme + '://' + domain + ':' + port + '/media/1x1-green.png';
+ var img = document.createElement('img');
+ img.setAttribute('src', url);
+ img.style.display = 'none';
+ img.onerror = function() {
+ done(false);
+ };
+ img.onload = function() {
+ done(true);
+ };
+
+ document.body.appendChild(img);
+}
+
+async_test(function(t) {
+ check('http', '{{browser_host}}', {{ports[http][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'HTTP protocol, no subdomain, port #1');
+
+async_test(function(t) {
+ check('http', '{{browser_host}}', {{ports[http][1]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'HTTP protocol, no subdomain, port #2');
+
+async_test(function(t) {
+ check('http', '{{domains[www]}}', {{ports[http][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'HTTP protocol, www subdomain #1, port #1');
+
+async_test(function(t) {
+ check('http', '{{domains[www]}}', {{ports[http][1]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'HTTP protocol, www subdomain #1, port #2');
+
+async_test(function(t) {
+ check('http', '{{domains[www1]}}', {{ports[http][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'HTTP protocol, www subdomain #2, port #1');
+
+async_test(function(t) {
+ check('http', '{{domains[www1]}}', {{ports[http][1]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'HTTP protocol, www subdomain #2, port #2');
+
+async_test(function(t) {
+ check('http', '{{domains[www2]}}', {{ports[http][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'HTTP protocol, www subdomain #3, port #1');
+
+async_test(function(t) {
+ check('http', '{{domains[www2]}}', {{ports[http][1]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'HTTP protocol, www subdomain #3, port #2');
+
+async_test(function(t) {
+ check('http', '{{domains[élève]}}', {{ports[http][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'HTTP protocol, punycode subdomain #1, port #1');
+
+async_test(function(t) {
+ check('http', '{{domains[élève]}}', {{ports[http][1]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'HTTP protocol, punycode subdomain #1, port #2');
+
+async_test(function(t) {
+ check('http', '{{domains[天気の良い日]}}', {{ports[http][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'HTTP protocol, punycode subdomain #2, port #1');
+
+async_test(function(t) {
+ check('http', '{{domains[天気の良い日]}}', {{ports[http][1]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'HTTP protocol, punycode subdomain #2, port #2');
+
+async_test(function(t) {
+ check('http', 'nonexistent.{{domains[]}}', {{ports[http][0]}}, t.step_func(function(result) {
+ assert_false(result);
+
+ t.done();
+ }));
+}, 'HTTP protocol, non-existent domain, port #1');
+
+async_test(function(t) {
+ check('http', 'nonexistent.{{domains[]}}', {{ports[http][1]}}, t.step_func(function(result) {
+ assert_false(result);
+
+ t.done();
+ }));
+}, 'HTTP protocol, non-existent domain, port #2');
+
+async_test(function(t) {
+ check('https', '{{browser_host}}', {{ports[https][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'HTTPS protocol, no subdomain');
+
+async_test(function(t) {
+ check('https', '{{domains[www]}}', {{ports[https][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'HTTPS protocol, www subdomain #1');
+
+async_test(function(t) {
+ check('https', '{{domains[www1]}}', {{ports[https][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'HTTPS protocol, www subdomain #2');
+
+async_test(function(t) {
+ check('https', '{{domains[www2]}}', {{ports[https][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'HTTPS protocol, www subdomain #3');
+
+async_test(function(t) {
+ check('https', '{{domains[élève]}}', {{ports[https][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'HTTPS protocol, punycode subdomain #1');
+
+async_test(function(t) {
+ check('https', '{{domains[天気の良い日]}}', {{ports[https][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'HTTPS protocol, punycode subdomain #2');
+
+async_test(function(t) {
+ check('https', 'nonexistent.{{domains[]}}', {{ports[http][0]}}, t.step_func(function(result) {
+ assert_false(result);
+
+ t.done();
+ }));
+}, 'HTTPS protocol, non-existent domain, port #1');
+
+async_test(function(t) {
+ check('https', 'nonexistent.{{domains[]}}', {{ports[http][1]}}, t.step_func(function(result) {
+ assert_false(result);
+
+ t.done();
+ }));
+}, 'HTTPS protocol, non-existent domain, port #2');
+
+async_test(function(t) {
+ check('h2', '{{browser_host}}', {{ports[h2][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'H2 protocol, no subdomain');
+
+async_test(function(t) {
+ check('h2', '{{domains[www]}}', {{ports[h2][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'H2 protocol, www subdomain #1');
+
+async_test(function(t) {
+ check('h2', '{{domains[www1]}}', {{ports[h2][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'H2 protocol, www subdomain #2');
+
+async_test(function(t) {
+ check('h2', '{{domains[www2]}}', {{ports[h2][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'H2 protocol, www subdomain #3');
+
+async_test(function(t) {
+ check('h2', '{{domains[élève]}}', {{ports[h2][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'H2 protocol, punycode subdomain #1');
+
+async_test(function(t) {
+ check('h2', '{{domains[天気の良い日]}}', {{ports[h2][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'H2 protocol, punycode subdomain #2');
+
+async_test(function(t) {
+ check('h2', 'nonexistent.{{domains[]}}', {{ports[http][0]}}, t.step_func(function(result) {
+ assert_false(result);
+
+ t.done();
+ }));
+}, 'H2 protocol, non-existent domain, port #1');
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/infrastructure/server/wpt-server-websocket.sub.html b/testing/web-platform/tests/infrastructure/server/wpt-server-websocket.sub.html
new file mode 100644
index 0000000000..ea7973a62e
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/server/wpt-server-websocket.sub.html
@@ -0,0 +1,122 @@
+<!doctype html>
+<html>
+ <head>
+ <title>WPT Server checker</title>
+ <meta charset="utf-8" />
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+</body>
+<body>
+<script>
+function check(protocol, domain, port, done) {
+ var url = protocol + '://' + domain + ':' + port + '/echo';
+ var ws = new WebSocket(url);
+
+ ws.addEventListener('error', function() {
+ done(false);
+ });
+
+ ws.addEventListener('open', function() {
+ done(true);
+ });
+}
+
+async_test(function(t) {
+ check('ws', '{{browser_host}}', {{ports[ws][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'WS protocol, no subdomain');
+
+async_test(function(t) {
+ check('ws', '{{domains[www1]}}', {{ports[ws][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'WS protocol, www subdomain #1');
+
+async_test(function(t) {
+ check('ws', '{{domains[www1]}}', {{ports[ws][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'WS protocol, www subdomain #2');
+
+async_test(function(t) {
+ check('ws', '{{domains[www2]}}', {{ports[ws][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'WS protocol, www subdomain #3');
+
+async_test(function(t) {
+ check('ws', '{{domains[élève]}}', {{ports[ws][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'WS protocol, punycode subdomain #1');
+
+async_test(function(t) {
+ check('ws', '{{domains[天気の良い日]}}', {{ports[ws][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'WS protocol, punycode subdomain #2');
+
+async_test(function(t) {
+ check('wss', '{{browser_host}}', {{ports[wss][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'WSS protocol, no subdomain');
+
+async_test(function(t) {
+ check('wss', '{{domains[www1]}}', {{ports[wss][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'WSS protocol, www subdomain #1');
+
+async_test(function(t) {
+ check('wss', '{{domains[www1]}}', {{ports[wss][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'WSS protocol, www subdomain #2');
+
+async_test(function(t) {
+ check('wss', '{{domains[www2]}}', {{ports[wss][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'WSS protocol, www subdomain #3');
+
+async_test(function(t) {
+ check('wss', '{{domains[élève]}}', {{ports[wss][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'WSS protocol, punycode subdomain #1');
+
+async_test(function(t) {
+ check('wss', '{{domains[天気の良い日]}}', {{ports[wss][0]}}, t.step_func(function(result) {
+ assert_true(result);
+
+ t.done();
+ }));
+}, 'WSS protocol, punycode subdomain #2');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/infrastructure/server/wpt-server-wpt-flags.sub.html b/testing/web-platform/tests/infrastructure/server/wpt-server-wpt-flags.sub.html
new file mode 100644
index 0000000000..9af9cda463
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/server/wpt-server-wpt-flags.sub.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<html>
+ <head>
+ <title>WPT Server checker</title>
+ <meta charset="utf-8" />
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <meta name="variant" content="">
+ <meta name="variant" content="?wpt_flags=h2">
+ <meta name="variant" content="?wpt_flags=https">
+ </head>
+</body>
+<body>
+<script>
+
+if (location.search == '?wpt_flags=h2') {
+ test(function() {
+ assert_equals(document.location.port, "{{ports[h2][0]}}");
+ }, "h2 port with wpt_flags=h2")
+} else if (location.search == '?wpt_flags=https') {
+ test(function() {
+ assert_equals(document.location.port, "{{ports[https][0]}}");
+ }, "https port with wpt_flags=https")
+} else {
+ test(function() {
+ assert_equals(document.location.port, "{{ports[http][0]}}");
+ }, "http port without flag")
+}
+
+</script>
+</body>
+</html>
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>
diff --git a/testing/web-platform/tests/infrastructure/testharness/lone-surrogates.html b/testing/web-platform/tests/infrastructure/testharness/lone-surrogates.html
new file mode 100644
index 0000000000..fb842ecc9e
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/testharness/lone-surrogates.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<title>test behaviour with lone surrogates</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ test(() => assert_true(true), "passing test with lone surrogate \uD800 in name");
+ test(() => assert_true(false), "failing test with lone surrogate \uD800 in name");
+ test(() => assert_true(true, "lone \uD800 surrogate"), "passing test with lone surrogate in assert");
+ test(() => assert_true(false, "lone \uD800 surrogate"), "failing test with lone surrogate in assert");
+</script>
diff --git a/testing/web-platform/tests/infrastructure/webdriver/tests/conftest.py b/testing/web-platform/tests/infrastructure/webdriver/tests/conftest.py
new file mode 100644
index 0000000000..cbc4f83421
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/webdriver/tests/conftest.py
@@ -0,0 +1,7 @@
+import os
+import sys
+# Hack to avoid duplicating the conftest file
+wdpath = os.path.abspath(os.path.join(os.path.dirname(__file__),
+ "../../../webdriver/"))
+sys.path.insert(0, wdpath)
+from tests.conftest import *
diff --git a/testing/web-platform/tests/infrastructure/webdriver/tests/test_load_file.py b/testing/web-platform/tests/infrastructure/webdriver/tests/test_load_file.py
new file mode 100644
index 0000000000..084df8f09a
--- /dev/null
+++ b/testing/web-platform/tests/infrastructure/webdriver/tests/test_load_file.py
@@ -0,0 +1,2 @@
+def test_load(session, inline):
+ inline("PASS")