summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/html/semantics
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/html/semantics')
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/media-elements/mime-types/canPlayType.html6
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/media-elements/track/track-element/track-cue-inline.html4
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-cross-origin-delivered.tentative.sub.window.js (renamed from testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-cross-origin.tentative.sub.window.js)10
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-cross-origin-frame.tentative.sub.window.js18
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-delivered-both.tentative.sub.window.js20
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-delivered.tentative.sub.window.js18
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-frame-both.tentative.sub.window.js20
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-frame.tentative.sub.window.js18
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-unsandboxed.tentative.sub.window.js17
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child.tentative.sub.window.js56
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-cross-origin-escalate.tentative.sub.window.js20
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-cross-site.tentative.sub.window.js21
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-escalate-privileges.tentative.sub.window.js63
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-allow-same-origin.tentative.sub.window.js20
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-frame-allow-top.tentative.sub.window.js19
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-sandboxed-cross-origin-parent.tentative.sub.window.js19
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-sandboxed-escalate.tentative.sub.window.js20
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-sandboxed.tentative.sub.window.js19
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-unsandboxed-cross-origin-parent.tentative.sub.window.js18
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-unsandboxed-inherit.tentative.sub.window.js19
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-unsandboxed.tentative.sub.window.js18
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild.tentative.sub.window.js50
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-same-site-no-activation.tentative.sub.window.js23
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-same-site.tentative.sub.window.js24
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-user-activation-no-sticky.tentative.sub.window.js19
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-user-activation-sticky.tentative.sub.window.js (renamed from testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-user-activation.tentative.sub.window.js)10
-rw-r--r--testing/web-platform/tests/html/semantics/embedded-content/the-object-element/usemap-casing.html92
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/resources/stylable-select-styles.css18
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/select-child-button-and-datalist-ref.html12
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/resources/select-reset-non-interoperable-styles.css5
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/resources/stylable-select-styles.css37
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-custom-button-no-datalist.tentative.html22
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-custom-datalist-ref.html14
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-custom-datalist.tentative.html (renamed from testing/web-platform/tests/html/semantics/forms/the-select-element/select-child-button-and-datalist-invalidation.tentative.html)14
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-no-datalist.tentative.html21
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-child-button-and-datalist-invalidation.tentative.html32
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-child-button-and-datalist-ref.html25
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-child-button-and-datalist.tentative.html (renamed from testing/web-platform/tests/html/semantics/forms/the-select-element/select-child-button-and-datalist.tentative.html)19
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-datalist-options-idl.tentative.html (renamed from testing/web-platform/tests/html/semantics/forms/the-select-element/select-datalist-options-idl.tentative.html)3
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-keyboard-behavior.tentative.html208
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-mouse-behavior.tentative.html62
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-parsing.tentative.html (renamed from testing/web-platform/tests/html/semantics/forms/the-select-element/select-parsing.tentative.html)0
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/selectedoption.tentative.html82
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/idlharness.tentative.html2
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/interestelement-interface.tentative.html1
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/interestevent-dispatch-shadow.tentative.html104
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/interestevent-interface.tentative.html167
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/interesttarget-button-event-dispatch.tentative.html155
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/interesttarget-on-popover-behavior.tentative.html113
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invokeelement-interface.tentative.html2
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invokeevent-dispatch-shadow.tentative.html2
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invokeevent-interface.tentative.html2
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-button-event-dispatch.tentative.html103
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-fullscreen-behavior.tentative.html1
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-on-audio-behavior.tentative.html40
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-on-audio-invalid-behavior.tentative.html37
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-on-details-behavior.tentative.html295
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-on-details-invalid-behavior.tentative.html49
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-on-dialog-behavior.tentative.html61
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-on-dialog-invalid-behavior.tentative.html120
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-on-popover-behavior.tentative.html312
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-on-popover-invalid-behavior.tentative.html47
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-on-video-behavior.tentative.html40
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/resources/invoker-utils.js11
-rw-r--r--testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties-reference-expected.html35
-rw-r--r--testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties-reference.tentative.html37
-rw-r--r--testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties.html38
-rw-r--r--testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties.tentative.html64
-rw-r--r--testing/web-platform/tests/html/semantics/permission-element/display-css-property-reference-expected.html16
-rw-r--r--testing/web-platform/tests/html/semantics/permission-element/display-css-property-reference.tentative.html22
-rw-r--r--testing/web-platform/tests/html/semantics/permission-element/display-css-property.tentative.html34
-rw-r--r--testing/web-platform/tests/html/semantics/permission-element/invalid-css-properties.tentative.html (renamed from testing/web-platform/tests/html/semantics/permission-element/invalid-css-properties.html)1
-rw-r--r--testing/web-platform/tests/html/semantics/permission-element/negative-offset-and-margin.tentative.html (renamed from testing/web-platform/tests/html/semantics/permission-element/negative-offset-and-margin.html)1
-rw-r--r--testing/web-platform/tests/html/semantics/permission-element/no-end-tag-no-contents.tentative.html (renamed from testing/web-platform/tests/html/semantics/permission-element/no-end-tag-no-contents.html)1
-rw-r--r--testing/web-platform/tests/html/semantics/popovers/button-type-reset-popovertarget.tentative.html43
-rw-r--r--testing/web-platform/tests/html/semantics/popovers/popover-anchor-display.tentative.html4
-rw-r--r--testing/web-platform/tests/html/semantics/popovers/popover-anchor-scroll-display.tentative.html2
-rw-r--r--testing/web-platform/tests/html/semantics/popovers/popover-light-dismiss.html52
-rw-r--r--testing/web-platform/tests/html/semantics/popovers/popover-top-layer-nesting.html (renamed from testing/web-platform/tests/html/semantics/popovers/popover-top-layer-nesting.tentative.html)0
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/css-module/integrity.html2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/integrity.html2
81 files changed, 2385 insertions, 868 deletions
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/media-elements/mime-types/canPlayType.html b/testing/web-platform/tests/html/semantics/embedded-content/media-elements/mime-types/canPlayType.html
index 56edf25aa8..855f02d3b1 100644
--- a/testing/web-platform/tests/html/semantics/embedded-content/media-elements/mime-types/canPlayType.html
+++ b/testing/web-platform/tests/html/semantics/embedded-content/media-elements/mime-types/canPlayType.html
@@ -55,10 +55,13 @@ function type_codecs_test(type, audioCodecs, videoCodecs) {
var typeSupported = false;
var codecSupported = false;
+ var mimeSupported = canPlayType(type);
+
// Test 'type' without codecs.
// Spec: Generally, a user agent should never return "probably" for a type
// that allows the codecs parameter if that parameter is not present.
test(function() {
+ assert_implements_optional(mimeSupported, type)
t(type, 'maybe');
t(type + ';', 'maybe');
t(type + ';codecs', 'maybe');
@@ -69,6 +72,7 @@ function type_codecs_test(type, audioCodecs, videoCodecs) {
function test_codec(codec) {
var typeWithCodec = mime(type, [codec]);
test(function() {
+ assert_implements_optional(canPlayType(typeWithCodec), type)
t(typeWithCodec, 'probably');
codecSupported = true;
}, typeWithCodec + ' (optional)');
@@ -81,6 +85,7 @@ function type_codecs_test(type, audioCodecs, videoCodecs) {
// Test different pairings and orderings of audio+video codecs.
if (audioCodecs.length > 0 && videoCodecs.length > 0) {
test(function() {
+ assert_implements_optional(mimeSupported, type)
audioCodecs.forEach(function(ac) {
videoCodecs.forEach(function(vc) {
var canPlayBoth = canPlayType(mime(type, [ac, vc]));
@@ -93,6 +98,7 @@ function type_codecs_test(type, audioCodecs, videoCodecs) {
}, type + ' codecs subset');
test(function() {
+ assert_implements_optional(mimeSupported, type)
audioCodecs.forEach(function(ac) {
videoCodecs.forEach(function(vc) {
assert_equals(canPlayType(mime(type, [ac, vc])),
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/media-elements/track/track-element/track-cue-inline.html b/testing/web-platform/tests/html/semantics/embedded-content/media-elements/track/track-element/track-cue-inline.html
index 3b4c3542a9..1a8aabcaff 100644
--- a/testing/web-platform/tests/html/semantics/embedded-content/media-elements/track/track-element/track-cue-inline.html
+++ b/testing/web-platform/tests/html/semantics/embedded-content/media-elements/track/track-element/track-cue-inline.html
@@ -4,7 +4,7 @@
<script src="/resources/testharnessreport.js"></script>
<video>
<source src="/media/test.mp4" type="video/mp4">
- <source src="/media/test.ogv" type="video/ogg">
+ <source src="/media/test.webm" type="video/webm">
</video>
<script>
test(function() {
@@ -13,4 +13,4 @@ test(function() {
track.addCue(new VTTCue(0.0, 10.0, 'wow wow'));
track.mode = 'showing';
});
-</script> \ No newline at end of file
+</script>
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-cross-origin.tentative.sub.window.js b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-cross-origin-delivered.tentative.sub.window.js
index 95d53e1fe3..8074314557 100644
--- a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-cross-origin.tentative.sub.window.js
+++ b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-cross-origin-delivered.tentative.sub.window.js
@@ -9,16 +9,6 @@
'use strict';
-// /* ---------------------- CROSS ORIGIN (A -> B) TESTS ---------------------- */
-
-promise_test(async t => {
- const main = await setupTest();
- const iframe_1 = await createNestedIframe(main,
- "HTTP_REMOTE_ORIGIN", "allow-top-navigation", "");
-
- await attemptTopNavigation(iframe_1, true);
-}, "A cross-origin frame with frame sandbox flags can navigate top");
-
promise_test(async t => {
const main = await setupTest();
const iframe_1 = await createNestedIframe(main,
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-cross-origin-frame.tentative.sub.window.js b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-cross-origin-frame.tentative.sub.window.js
new file mode 100644
index 0000000000..a2191b352a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-cross-origin-frame.tentative.sub.window.js
@@ -0,0 +1,18 @@
+// META: title=Top-level navigation tests with cross origin & user activated child frames
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/utils.js
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
+// META: script=./resources/sandbox-top-navigation-helper.sub.js
+
+'use strict';
+
+promise_test(async t => {
+ const main = await setupTest();
+ const iframe_1 = await createNestedIframe(
+ main, 'HTTP_REMOTE_ORIGIN', 'allow-top-navigation', '');
+
+ await attemptTopNavigation(iframe_1, true);
+}, 'A cross-origin frame with frame sandbox flags can navigate top');
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-delivered-both.tentative.sub.window.js b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-delivered-both.tentative.sub.window.js
new file mode 100644
index 0000000000..540cc338c9
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-delivered-both.tentative.sub.window.js
@@ -0,0 +1,20 @@
+// META: title=Top-level navigation tests with child frames
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/utils.js
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
+// META: script=./resources/sandbox-top-navigation-helper.sub.js
+
+'use strict';
+
+promise_test(async t => {
+ const main = await setupTest();
+ const iframe_1 = await createNestedIframe(
+ main, 'HTTP_ORIGIN', '',
+ 'allow-top-navigation allow-top-navigation-by-user-activation allow-same-origin');
+
+ await attemptTopNavigation(iframe_1, true);
+}, 'A frame with both top navigation delivered sandbox flags uses the less \
+ restrictive one');
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-delivered.tentative.sub.window.js b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-delivered.tentative.sub.window.js
new file mode 100644
index 0000000000..c020513012
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-delivered.tentative.sub.window.js
@@ -0,0 +1,18 @@
+// META: title=Top-level navigation tests with child frames
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/utils.js
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
+// META: script=./resources/sandbox-top-navigation-helper.sub.js
+
+'use strict';
+
+promise_test(async t => {
+ const main = await setupTest();
+ const iframe_1 = await createNestedIframe(
+ main, 'HTTP_ORIGIN', '', 'allow-top-navigation allow-same-origin');
+
+ await attemptTopNavigation(iframe_1, true);
+}, 'A same-origin frame with delivered sandbox flags can navigate top');
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-frame-both.tentative.sub.window.js b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-frame-both.tentative.sub.window.js
new file mode 100644
index 0000000000..ff7d2eb584
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-frame-both.tentative.sub.window.js
@@ -0,0 +1,20 @@
+// META: title=Top-level navigation tests with child frames
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/utils.js
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
+// META: script=./resources/sandbox-top-navigation-helper.sub.js
+
+'use strict';
+
+promise_test(async t => {
+ const main = await setupTest();
+ const iframe_1 = await createNestedIframe(
+ main, 'HTTP_ORIGIN',
+ 'allow-top-navigation allow-top-navigation-by-user-activation', '');
+
+ await attemptTopNavigation(iframe_1, true);
+}, 'A frame with both top navigation frame sandbox flags uses the less \
+ restrictive one');
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-frame.tentative.sub.window.js b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-frame.tentative.sub.window.js
new file mode 100644
index 0000000000..35abc554b6
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-frame.tentative.sub.window.js
@@ -0,0 +1,18 @@
+// META: title=Top-level navigation tests with child frames
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/utils.js
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
+// META: script=./resources/sandbox-top-navigation-helper.sub.js
+
+'use strict';
+
+promise_test(async t => {
+ const main = await setupTest();
+ const iframe_1 = await createNestedIframe(
+ main, 'HTTP_ORIGIN', 'allow-top-navigation allow-same-origin', '');
+
+ await attemptTopNavigation(iframe_1, true);
+}, 'A same-origin frame with frame sandbox flags can navigate top');
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-unsandboxed.tentative.sub.window.js b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-unsandboxed.tentative.sub.window.js
new file mode 100644
index 0000000000..c2d78b6dd5
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-unsandboxed.tentative.sub.window.js
@@ -0,0 +1,17 @@
+// META: title=Top-level navigation tests with child frames
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/utils.js
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
+// META: script=./resources/sandbox-top-navigation-helper.sub.js
+
+'use strict';
+
+promise_test(async t => {
+ const main = await setupTest();
+ const iframe_1 = await createNestedIframe(main, 'HTTP_ORIGIN', '', '');
+
+ await attemptTopNavigation(iframe_1, true);
+}, 'A same-origin unsandboxed frame can navigate top');
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child.tentative.sub.window.js b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child.tentative.sub.window.js
deleted file mode 100644
index 1d5ea93830..0000000000
--- a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child.tentative.sub.window.js
+++ /dev/null
@@ -1,56 +0,0 @@
-// META: title=Top-level navigation tests with child frames
-// META: script=/common/dispatcher/dispatcher.js
-// META: script=/common/get-host-info.sub.js
-// META: script=/common/utils.js
-// META: script=/resources/testdriver.js
-// META: script=/resources/testdriver-vendor.js
-// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
-// META: script=./resources/sandbox-top-navigation-helper.sub.js
-
-'use strict';
-
-/* ----------------------- SAME ORIGIN (A -> A) TESTS ----------------------- */
-
-promise_test(async t => {
- const main = await setupTest();
- const iframe_1 = await createNestedIframe(main,
- "HTTP_ORIGIN", "", "allow-top-navigation allow-same-origin");
-
- await attemptTopNavigation(iframe_1, true);
-}, "A same-origin frame with delivered sandbox flags can navigate top");
-
-promise_test(async t => {
- const main = await setupTest();
- const iframe_1 = await createNestedIframe(main,
- "HTTP_ORIGIN", "allow-top-navigation allow-same-origin", "");
-
- await attemptTopNavigation(iframe_1, true);
-}, "A same-origin frame with frame sandbox flags can navigate top");
-
-promise_test(async t => {
- const main = await setupTest();
- const iframe_1 = await createNestedIframe(main,
- "HTTP_ORIGIN", "", "");
-
- await attemptTopNavigation(iframe_1, true);
-}, "A same-origin unsandboxed frame can navigate top");
-
-promise_test(async t => {
- const main = await setupTest();
- const iframe_1 = await createNestedIframe(main,
- "HTTP_ORIGIN", "",
- "allow-top-navigation allow-top-navigation-by-user-activation allow-same-origin");
-
- await attemptTopNavigation(iframe_1, true);
-}, "A frame with both top navigation delivered sandbox flags uses the less \
- restrictive one");
-
-promise_test(async t => {
- const main = await setupTest();
- const iframe_1 = await createNestedIframe(main,
- "HTTP_ORIGIN",
- "allow-top-navigation allow-top-navigation-by-user-activation", "");
-
- await attemptTopNavigation(iframe_1, true);
-}, "A frame with both top navigation frame sandbox flags uses the less \
- restrictive one");
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-cross-origin-escalate.tentative.sub.window.js b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-cross-origin-escalate.tentative.sub.window.js
new file mode 100644
index 0000000000..c394699d85
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-cross-origin-escalate.tentative.sub.window.js
@@ -0,0 +1,20 @@
+// META: title=Top-level navigation tests with frames that try to give themselves top-nav permission
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/utils.js
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
+// META: script=./resources/sandbox-top-navigation-helper.sub.js
+
+'use strict';
+
+promise_test(async t => {
+ const main = await setupTest();
+ const iframe_1 = await createNestedIframe(main, 'HTTP_REMOTE_ORIGIN', '', '');
+ const iframe_2 = await createNestedIframe(
+ iframe_1, 'HTTP_REMOTE_ORIGIN', 'allow-top-navigation', '');
+
+ await attemptTopNavigation(iframe_2, false);
+}, 'A cross origin unsandboxed frame can\'t escalate privileges in a child \
+ frame');
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-cross-site.tentative.sub.window.js b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-cross-site.tentative.sub.window.js
index 26db4eeaca..cacc5bd983 100644
--- a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-cross-site.tentative.sub.window.js
+++ b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-cross-site.tentative.sub.window.js
@@ -20,24 +20,3 @@ promise_test(async t => {
await attemptTopNavigation(new_iframe, false);
}, "A cross-site unsandboxed iframe navigation consumes user activation and " +
"disallows top-level navigation.");
-
-promise_test(async t => {
- const main = await setupTest();
-
- const iframe = await createNestedIframe(main, "HTTP_ORIGIN", "", "");
- await activate(iframe);
-
- const new_iframe = await navigateFrameTo(iframe, "HTTP_REMOTE_ORIGIN");
- await attemptTopNavigation(new_iframe, true);
-}, "A same-site unsandboxed iframe navigation does not consume user " +
- "activation and allows top-level navigation.");
-
-promise_test(async t => {
- const main = await setupTest();
-
- const iframe = await createNestedIframe(main, "HTTP_ORIGIN", "", "");
-
- const new_iframe = await navigateFrameTo(iframe, "HTTP_REMOTE_ORIGIN");
- await attemptTopNavigation(new_iframe, false);
-}, "A same-site unsandboxed iframe navigation without sticky user activation " +
- "does not allow top-level navigation.");
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-escalate-privileges.tentative.sub.window.js b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-escalate-privileges.tentative.sub.window.js
deleted file mode 100644
index 2ea0ba606e..0000000000
--- a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-escalate-privileges.tentative.sub.window.js
+++ /dev/null
@@ -1,63 +0,0 @@
-// META: title=Top-level navigation tests with frames that try to give themselves top-nav permission
-// META: script=/common/dispatcher/dispatcher.js
-// META: script=/common/get-host-info.sub.js
-// META: script=/common/utils.js
-// META: script=/resources/testdriver.js
-// META: script=/resources/testdriver-vendor.js
-// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
-// META: script=./resources/sandbox-top-navigation-helper.sub.js
-
-'use strict';
-
-promise_test(async t => {
- const main = await setupTest();
- const iframe_1 = await createNestedIframe(main,
- "HTTP_REMOTE_ORIGIN", "", "");
- const iframe_2 = await createNestedIframe(iframe_1,
- "HTTP_REMOTE_ORIGIN", "allow-top-navigation", "");
-
- await attemptTopNavigation(iframe_2, false);
-}, "A cross origin unsandboxed frame can't escalate privileges in a child \
- frame");
-
-promise_test(async t => {
- const main = await setupTest();
- const iframe_1 = await createNestedIframe(main,
- "HTTP_REMOTE_ORIGIN", "allow-top-navigation", "");
- const iframe_2 = await createNestedIframe(iframe_1,
- "OTHER_ORIGIN", "", "");
-
- await attemptTopNavigation(iframe_2, true);
-}, "An unsandboxed grandchild inherits its parents ability to navigate top.");
-
-promise_test(async t => {
- const main = await setupTest();
- const iframe_1 = await createNestedIframe(main,
- "HTTP_ORIGIN", "", "");
- const iframe_2 = await createNestedIframe(iframe_1,
- "HTTP_ORIGIN", "allow-top-navigation", "");
-
- await attemptTopNavigation(iframe_2, true);
-}, "A same-origin grandchild with frame allow-top can navigate top");
-
-promise_test(async t => {
- const main = await setupTest();
- const iframe_1 = await createNestedIframe(main,
- "HTTP_ORIGIN", "", "");
- const iframe_2 = await createNestedIframe(iframe_1,
- "HTTP_ORIGIN", "", "allow-top-navigation");
-
- await attemptTopNavigation(iframe_2, false);
-}, "A sandboxed same-origin grandchild without allow-same-origin can't \
- escalate its own top-nav privileges");
-
-promise_test(async t => {
- const main = await setupTest();
- const iframe_1 = await createNestedIframe(main,
- "HTTP_ORIGIN", "", "");
- const iframe_2 = await createNestedIframe(iframe_1,
- "HTTP_ORIGIN", "", "allow-same-origin allow-top-navigation");
-
- await attemptTopNavigation(iframe_2, true);
-}, "A sandboxed same-origin grandchild with allow-same-origin can \
- give itself top-nav privileges");
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-allow-same-origin.tentative.sub.window.js b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-allow-same-origin.tentative.sub.window.js
new file mode 100644
index 0000000000..2be6cd66a7
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-allow-same-origin.tentative.sub.window.js
@@ -0,0 +1,20 @@
+// META: title=Top-level navigation tests with frames that try to give themselves top-nav permission
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/utils.js
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
+// META: script=./resources/sandbox-top-navigation-helper.sub.js
+
+'use strict';
+
+promise_test(async t => {
+ const main = await setupTest();
+ const iframe_1 = await createNestedIframe(main, 'HTTP_ORIGIN', '', '');
+ const iframe_2 = await createNestedIframe(
+ iframe_1, 'HTTP_ORIGIN', '', 'allow-same-origin allow-top-navigation');
+
+ await attemptTopNavigation(iframe_2, true);
+}, 'A sandboxed same-origin grandchild with allow-same-origin can \
+ give itself top-nav privileges');
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-frame-allow-top.tentative.sub.window.js b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-frame-allow-top.tentative.sub.window.js
new file mode 100644
index 0000000000..43ca5eb404
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-frame-allow-top.tentative.sub.window.js
@@ -0,0 +1,19 @@
+// META: title=Top-level navigation tests with frames that try to give themselves top-nav permission
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/utils.js
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
+// META: script=./resources/sandbox-top-navigation-helper.sub.js
+
+'use strict';
+
+promise_test(async t => {
+ const main = await setupTest();
+ const iframe_1 = await createNestedIframe(main, 'HTTP_ORIGIN', '', '');
+ const iframe_2 = await createNestedIframe(
+ iframe_1, 'HTTP_ORIGIN', 'allow-top-navigation', '');
+
+ await attemptTopNavigation(iframe_2, true);
+}, 'A same-origin grandchild with frame allow-top can navigate top');
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-sandboxed-cross-origin-parent.tentative.sub.window.js b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-sandboxed-cross-origin-parent.tentative.sub.window.js
new file mode 100644
index 0000000000..8833ad42bb
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-sandboxed-cross-origin-parent.tentative.sub.window.js
@@ -0,0 +1,19 @@
+// META: title=Top-level navigation tests with grandchild frames
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/utils.js
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
+// META: script=./resources/sandbox-top-navigation-helper.sub.js
+
+'use strict';
+
+promise_test(async t => {
+ const main = await setupTest();
+ const iframe_1 = await createNestedIframe(main, 'HTTP_REMOTE_ORIGIN', '', '');
+ const iframe_2 = await createNestedIframe(
+ iframe_1, 'HTTP_ORIGIN', 'allow-top-navigation allow-same-origin', '');
+
+ await attemptTopNavigation(iframe_2, true);
+}, 'A same-origin sandboxed grandchild in a cross-origin parent can navigate top');
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-sandboxed-escalate.tentative.sub.window.js b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-sandboxed-escalate.tentative.sub.window.js
new file mode 100644
index 0000000000..448925144a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-sandboxed-escalate.tentative.sub.window.js
@@ -0,0 +1,20 @@
+// META: title=Top-level navigation tests with frames that try to give themselves top-nav permission
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/utils.js
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
+// META: script=./resources/sandbox-top-navigation-helper.sub.js
+
+'use strict';
+
+promise_test(async t => {
+ const main = await setupTest();
+ const iframe_1 = await createNestedIframe(main, 'HTTP_ORIGIN', '', '');
+ const iframe_2 = await createNestedIframe(
+ iframe_1, 'HTTP_ORIGIN', '', 'allow-top-navigation');
+
+ await attemptTopNavigation(iframe_2, false);
+}, 'A sandboxed same-origin grandchild without allow-same-origin can\'t \
+ escalate its own top-nav privileges');
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-sandboxed.tentative.sub.window.js b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-sandboxed.tentative.sub.window.js
new file mode 100644
index 0000000000..a4b43a7b1f
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-sandboxed.tentative.sub.window.js
@@ -0,0 +1,19 @@
+// META: title=Top-level navigation tests with grandchild frames
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/utils.js
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
+// META: script=./resources/sandbox-top-navigation-helper.sub.js
+
+'use strict';
+
+promise_test(async t => {
+ const main = await setupTest();
+ const iframe_1 = await createNestedIframe(main, 'HTTP_ORIGIN', '', '');
+ const iframe_2 =
+ await createNestedIframe(iframe_1, 'HTTP_ORIGIN', 'allow-scripts', '');
+
+ await attemptTopNavigation(iframe_2, false);
+}, 'A fully sandboxed same-origin grandchild can\'t navigate top');
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-unsandboxed-cross-origin-parent.tentative.sub.window.js b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-unsandboxed-cross-origin-parent.tentative.sub.window.js
new file mode 100644
index 0000000000..5abbb9c30c
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-unsandboxed-cross-origin-parent.tentative.sub.window.js
@@ -0,0 +1,18 @@
+// META: title=Top-level navigation tests with grandchild frames
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/utils.js
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
+// META: script=./resources/sandbox-top-navigation-helper.sub.js
+
+'use strict';
+
+promise_test(async t => {
+ const main = await setupTest();
+ const iframe_1 = await createNestedIframe(main, 'HTTP_REMOTE_ORIGIN', '', '');
+ const iframe_2 = await createNestedIframe(iframe_1, 'HTTP_ORIGIN', '', '');
+
+ await attemptTopNavigation(iframe_2, true);
+}, 'A same-origin grandchild in a cross-origin parent can navigate top');
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-unsandboxed-inherit.tentative.sub.window.js b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-unsandboxed-inherit.tentative.sub.window.js
new file mode 100644
index 0000000000..a31c56b935
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-unsandboxed-inherit.tentative.sub.window.js
@@ -0,0 +1,19 @@
+// META: title=Top-level navigation tests with frames that try to give themselves top-nav permission
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/utils.js
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
+// META: script=./resources/sandbox-top-navigation-helper.sub.js
+
+'use strict';
+
+promise_test(async t => {
+ const main = await setupTest();
+ const iframe_1 = await createNestedIframe(
+ main, 'HTTP_REMOTE_ORIGIN', 'allow-top-navigation', '');
+ const iframe_2 = await createNestedIframe(iframe_1, 'OTHER_ORIGIN', '', '');
+
+ await attemptTopNavigation(iframe_2, true);
+}, 'An unsandboxed grandchild inherits its parents ability to navigate top.');
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-unsandboxed.tentative.sub.window.js b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-unsandboxed.tentative.sub.window.js
new file mode 100644
index 0000000000..7fe80dfa1b
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild-unsandboxed.tentative.sub.window.js
@@ -0,0 +1,18 @@
+// META: title=Top-level navigation tests with grandchild frames
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/utils.js
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
+// META: script=./resources/sandbox-top-navigation-helper.sub.js
+
+'use strict';
+
+promise_test(async t => {
+ const main = await setupTest();
+ const iframe_1 = await createNestedIframe(main, 'HTTP_ORIGIN', '', '');
+ const iframe_2 = await createNestedIframe(iframe_1, 'HTTP_ORIGIN', '', '');
+
+ await attemptTopNavigation(iframe_2, true);
+}, 'An unsandboxed same-origin grandchild can navigate top');
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild.tentative.sub.window.js b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild.tentative.sub.window.js
deleted file mode 100644
index 326c1dd54a..0000000000
--- a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild.tentative.sub.window.js
+++ /dev/null
@@ -1,50 +0,0 @@
-// META: title=Top-level navigation tests with grandchild frames
-// META: script=/common/dispatcher/dispatcher.js
-// META: script=/common/get-host-info.sub.js
-// META: script=/common/utils.js
-// META: script=/resources/testdriver.js
-// META: script=/resources/testdriver-vendor.js
-// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
-// META: script=./resources/sandbox-top-navigation-helper.sub.js
-
-'use strict';
-
-promise_test(async t => {
- const main = await setupTest();
- const iframe_1 = await createNestedIframe(main,
- "HTTP_ORIGIN", "", "");
- const iframe_2 = await createNestedIframe(iframe_1,
- "HTTP_ORIGIN", "allow-scripts", "");
-
- await attemptTopNavigation(iframe_2, false);
-}, "A fully sandboxed same-origin grandchild can't navigate top");
-
-promise_test(async t => {
- const main = await setupTest();
- const iframe_1 = await createNestedIframe(main,
- "HTTP_ORIGIN", "", "");
- const iframe_2 = await createNestedIframe(iframe_1,
- "HTTP_ORIGIN", "", "");
-
- await attemptTopNavigation(iframe_2, true);
-}, "An unsandboxed same-origin grandchild can navigate top");
-
-promise_test(async t => {
- const main = await setupTest();
- const iframe_1 = await createNestedIframe(main,
- "HTTP_REMOTE_ORIGIN", "", "");
- const iframe_2 = await createNestedIframe(iframe_1,
- "HTTP_ORIGIN", "", "");
-
- await attemptTopNavigation(iframe_2, true);
-}, "A same-origin grandchild in a cross-origin parent can navigate top");
-
-promise_test(async t => {
- const main = await setupTest();
- const iframe_1 = await createNestedIframe(main,
- "HTTP_REMOTE_ORIGIN", "", "");
- const iframe_2 = await createNestedIframe(iframe_1,
- "HTTP_ORIGIN", "allow-top-navigation allow-same-origin", "");
-
- await attemptTopNavigation(iframe_2, true);
-}, "A same-origin sandboxed grandchild in a cross-origin parent can navigate top"); \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-same-site-no-activation.tentative.sub.window.js b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-same-site-no-activation.tentative.sub.window.js
new file mode 100644
index 0000000000..03350e76e2
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-same-site-no-activation.tentative.sub.window.js
@@ -0,0 +1,23 @@
+// META: title=Top-level navigation tests with cross origin & user activated child frames
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/utils.js
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-actions.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
+// META: script=./resources/sandbox-top-navigation-helper.sub.js
+
+'use strict';
+
+promise_test(
+ async t => {
+ const main = await setupTest();
+
+ const iframe = await createNestedIframe(main, 'HTTP_ORIGIN', '', '');
+
+ const new_iframe = await navigateFrameTo(iframe, 'HTTP_REMOTE_ORIGIN');
+ await attemptTopNavigation(new_iframe, false);
+ },
+ 'A same-site unsandboxed iframe navigation without sticky user activation ' +
+ 'does not allow top-level navigation.');
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-same-site.tentative.sub.window.js b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-same-site.tentative.sub.window.js
new file mode 100644
index 0000000000..0ee6b8edcc
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-same-site.tentative.sub.window.js
@@ -0,0 +1,24 @@
+// META: title=Top-level navigation tests with cross origin & user activated child frames
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/utils.js
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-actions.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
+// META: script=./resources/sandbox-top-navigation-helper.sub.js
+
+'use strict';
+
+promise_test(
+ async t => {
+ const main = await setupTest();
+
+ const iframe = await createNestedIframe(main, 'HTTP_ORIGIN', '', '');
+ await activate(iframe);
+
+ const new_iframe = await navigateFrameTo(iframe, 'HTTP_REMOTE_ORIGIN');
+ await attemptTopNavigation(new_iframe, true);
+ },
+ 'A same-site unsandboxed iframe navigation does not consume user ' +
+ 'activation and allows top-level navigation.');
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-user-activation-no-sticky.tentative.sub.window.js b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-user-activation-no-sticky.tentative.sub.window.js
new file mode 100644
index 0000000000..c62155ce30
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-user-activation-no-sticky.tentative.sub.window.js
@@ -0,0 +1,19 @@
+// META: title=Top-level navigation tests with cross origin & user activated child frames
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/utils.js
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-actions.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
+// META: script=./resources/sandbox-top-navigation-helper.sub.js
+
+'use strict';
+
+promise_test(async t => {
+ const main = await setupTest();
+ const iframe_1 = await createNestedIframe(
+ main, 'HTTP_ORIGIN', 'allow-top-navigation-by-user-activation', '');
+
+ await attemptTopNavigation(iframe_1, false);
+}, 'allow-top-navigation-by-user-activation set but no sticky activation');
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-user-activation.tentative.sub.window.js b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-user-activation-sticky.tentative.sub.window.js
index 5079c8ad14..e62fbdfb22 100644
--- a/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-user-activation.tentative.sub.window.js
+++ b/testing/web-platform/tests/html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-user-activation-sticky.tentative.sub.window.js
@@ -10,8 +10,6 @@
'use strict';
-/* ------------------------- USER ACTIVATION TESTS ------------------------- */
-
promise_test(async t => {
const main = await setupTest();
const iframe_1 = await createNestedIframe(main,
@@ -20,11 +18,3 @@ promise_test(async t => {
await attemptTopNavigation(iframe_1, true);
}, "Allow top with user activation + user activation");
-
-promise_test(async t => {
- const main = await setupTest();
- const iframe_1 = await createNestedIframe(main,
- "HTTP_ORIGIN", "allow-top-navigation-by-user-activation", "");
-
- await attemptTopNavigation(iframe_1, false);
-}, "allow-top-navigation-by-user-activation set but no sticky activation");
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/the-object-element/usemap-casing.html b/testing/web-platform/tests/html/semantics/embedded-content/the-object-element/usemap-casing.html
index 114a472fb6..9431c73fe7 100644
--- a/testing/web-platform/tests/html/semantics/embedded-content/the-object-element/usemap-casing.html
+++ b/testing/web-platform/tests/html/semantics/embedded-content/the-object-element/usemap-casing.html
@@ -8,53 +8,53 @@
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
-<div id="log"></div>
+<object data="/images/threecolors.png" usemap="#sanityCheck" width="100" height="100"></object>
+<map name="sanityCheck"><area shape="rect" coords="0,0,100,100"></map>
+
+<object data="/images/threecolors.png" usemap="#sImPlE" width="100" height="100"></object>
+<map name="simple"><area shape="rect" coords="0,0,100,100"></map>
+<map name="SIMPLE"><area shape="rect" coords="0,0,100,100"></map>
+
+<object data="/images/threecolors.png" usemap="#paSSfield-killroyß" width="100" height="100"></object>
+<map name="passfield-killroyß"><area shape="rect" coords="0,0,100,100"></map>
+<map name="PASSFIELD-KILLROYß"><area shape="rect" coords="0,0,100,100"></map>
+<map name="paſſfield-killroyß"><area shape="rect" coords="0,0,100,100"></map>
+<map name="passfield-&#x212a;illroyß"><area shape="rect" coords="0,0,100,100"></map>
+<map name="paßfield-killroyß"><area shape="rect" coords="0,0,100,100"></map>
+<map name="paẞfield-killroyß"><area shape="rect" coords="0,0,100,100"></map>
+<map name="passfield-killroyẞ"><area shape="rect" coords="0,0,100,100"></map>
+<map name="passfield-killroyß"><area shape="rect" coords="0,0,100,100"></map>
+<map name="passfıeld-killroyß"><area shape="rect" coords="0,0,100,100"></map>
+<map name="passfİeld-killroyß"><area shape="rect" coords="0,0,100,100"></map>
+
+<object data="/images/threecolors.png" usemap="#глупый" width="100" height="100"></object>
+<map name="глупы&#x438;&#x306;"><area shape="rect" coords="0,0,100,100"></map>
+<map name="ГЛУПЫЙ"><area shape="rect" coords="0,0,100,100"></map>
+<map name="ГЛУПЫ&#x418;&#x306;"><area shape="rect" coords="0,0,100,100"></map>
+
+<object data="/images/threecolors.png" usemap="#åωk" width="100" height="100"></object>
+<map name="ÅΩK"><area shape="rect" coords="0,0,100,100"></map>
+<map name="&#x212b;ωk"><area shape="rect" coords="0,0,100,100"></map>
+<map name="å&#x2126;k"><area shape="rect" coords="0,0,100,100"></map>
+<map name="åω&#x212a;"><area shape="rect" coords="0,0,100,100"></map>
+
+<object data="/images/threecolors.png" usemap="#blah1" width="100" height="100"></object>
+<map name="blah&#x2460;"><area shape="rect" coords="0,0,100,100"></map>
+<map name="bl&#x24b6;h1"><area shape="rect" coords="0,0,100,100"></map>
+<map name="bl&#x24d0;h1"><area shape="rect" coords="0,0,100,100"></map>
+
+<object data="/images/threecolors.png" usemap="#t&Eacute;dz5アパートFi" width="100" height="100"></object>
+<map name="T&Eacute;DZ5アパートFi"><area shape="rect" coords="0,0,100,100"></map>
+<map name="T&eacute;&#x01F1;&#x2075;アパートFi"><area shape="rect" coords="0,0,100,100"></map>
+<map name="t&Eacute;dz5&#x3300;Fi"><area shape="rect" coords="0,0,100,100"></map>
+<map name="t&Eacute;dz5&#x30A2;&#x30CF;&#x309A;&#x30FC;&#x30C8;Fi"><area shape="rect" coords="0,0,100,100"></map>
+<map name="T&Eacute;DZ⁵アパートFi"><area shape="rect" coords="0,0,100,100"></map>
+<map name="T&Eacute;DZ5アパートfi"><area shape="rect" coords="0,0,100,100"></map>
+
+<object data="/images/threecolors.png" usemap="#ΣΣ" width="100" height="100"></object>
+<map name="σς"><area shape="rect" coords="0,0,100,100"></map>
-<object data="/images/threecolors.png" usemap="#sanityCheck" width="300" height="300"></object>
-<map name="sanityCheck"><area shape="rect" coords="0,0,300,300"></map>
-
-<object data="/images/threecolors.png" usemap="#sImPlE" width="300" height="300"></object>
-<map name="simple"><area shape="rect" coords="0,0,300,300"></map>
-<map name="SIMPLE"><area shape="rect" coords="0,0,300,300"></map>
-
-<object data="/images/threecolors.png" usemap="#paSSfield-killroyß" width="300" height="300"></object>
-<map name="passfield-killroyß"><area shape="rect" coords="0,0,300,300"></map>
-<map name="PASSFIELD-KILLROYß"><area shape="rect" coords="0,0,300,300"></map>
-<map name="paſſfield-killroyß"><area shape="rect" coords="0,0,300,300"></map>
-<map name="passfield-&#x212a;illroyß"><area shape="rect" coords="0,0,300,300"></map>
-<map name="paßfield-killroyß"><area shape="rect" coords="0,0,300,300"></map>
-<map name="paẞfield-killroyß"><area shape="rect" coords="0,0,300,300"></map>
-<map name="passfield-killroyẞ"><area shape="rect" coords="0,0,300,300"></map>
-<map name="passfield-killroyß"><area shape="rect" coords="0,0,300,300"></map>
-<map name="passfıeld-killroyß"><area shape="rect" coords="0,0,300,300"></map>
-<map name="passfİeld-killroyß"><area shape="rect" coords="0,0,300,300"></map>
-
-<object data="/images/threecolors.png" usemap="#глупый" width="300" height="300"></object>
-<map name="глупы&#x438;&#x306;"><area shape="rect" coords="0,0,300,300"></map>
-<map name="ГЛУПЫЙ"><area shape="rect" coords="0,0,300,300"></map>
-<map name="ГЛУПЫ&#x418;&#x306;"><area shape="rect" coords="0,0,300,300"></map>
-
-<object data="/images/threecolors.png" usemap="#åωk" width="300" height="300"></object>
-<map name="ÅΩK"><area shape="rect" coords="0,0,300,300"></map>
-<map name="&#x212b;ωk"><area shape="rect" coords="0,0,300,300"></map>
-<map name="å&#x2126;k"><area shape="rect" coords="0,0,300,300"></map>
-<map name="åω&#x212a;"><area shape="rect" coords="0,0,300,300"></map>
-
-<object data="/images/threecolors.png" usemap="#blah1" width="300" height="300"></object>
-<map name="blah&#x2460;"><area shape="rect" coords="0,0,300,300"></map>
-<map name="bl&#x24b6;h1"><area shape="rect" coords="0,0,300,300"></map>
-<map name="bl&#x24d0;h1"><area shape="rect" coords="0,0,300,300"></map>
-
-<object data="/images/threecolors.png" usemap="#t&Eacute;dz5アパートFi" width="300" height="300"></object>
-<map name="T&Eacute;DZ5アパートFi"><area shape="rect" coords="0,0,300,300"></map>
-<map name="T&eacute;&#x01F1;&#x2075;アパートFi"><area shape="rect" coords="0,0,300,300"></map>
-<map name="t&Eacute;dz5&#x3300;Fi"><area shape="rect" coords="0,0,300,300"></map>
-<map name="t&Eacute;dz5&#x30A2;&#x30CF;&#x309A;&#x30FC;&#x30C8;Fi"><area shape="rect" coords="0,0,300,300"></map>
-<map name="T&Eacute;DZ⁵アパートFi"><area shape="rect" coords="0,0,300,300"></map>
-<map name="T&Eacute;DZ5アパートfi"><area shape="rect" coords="0,0,300,300"></map>
-
-<object data="/images/threecolors.png" usemap="#ΣΣ" width="300" height="300"></object>
-<map name="σς"><area shape="rect" coords="0,0,300,300"></map>
+<div id="log"></div>
<script>
"use strict";
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/resources/stylable-select-styles.css b/testing/web-platform/tests/html/semantics/forms/the-select-element/resources/stylable-select-styles.css
deleted file mode 100644
index a7e9a87cdf..0000000000
--- a/testing/web-platform/tests/html/semantics/forms/the-select-element/resources/stylable-select-styles.css
+++ /dev/null
@@ -1,18 +0,0 @@
-.stylable-select-datalist {
- box-shadow: 0px 12.8px 28.8px rgba(0, 0, 0, 0.13), 0px 0px 9.2px rgba(0, 0, 0, 0.11);
- box-sizing: border-box;
- overflow: auto;
- border: 1px solid rgba(0, 0, 0, 0.15);
- border-radius: 0.25em;
- padding: 0.25em 0;
- background-color: Field;
- margin: 0;
- inset: auto;
- min-inline-size: anchor-size(self-inline);
- min-block-size: 1lh;
- inset-block-start: anchor(self-end);
- inset-inline-start: anchor(self-start);
-
- font-family: Arial;
- font-size: 13.3333px;
-}
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-child-button-and-datalist-ref.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-child-button-and-datalist-ref.html
deleted file mode 100644
index 46bbd0ccd0..0000000000
--- a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-child-button-and-datalist-ref.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE html>
-<link rel=stylesheet href="resources/stylable-select-styles.css">
-
-<button popovertarget=popover id=button>button</button>
-<div id=popover popover=auto anchor=button class=stylable-select-datalist>
- <option>one</option>
- <option>two</option>
-</div>
-
-<script>
-document.getElementById('popover').showPopover();
-</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/resources/select-reset-non-interoperable-styles.css b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/resources/select-reset-non-interoperable-styles.css
new file mode 100644
index 0000000000..d2b9d9df26
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/resources/select-reset-non-interoperable-styles.css
@@ -0,0 +1,5 @@
+/* TODO(crbug.com/1511354): linux.css sets background-color on select, consider
+ * removing it. */
+select {
+ background-color: Field;
+}
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/resources/stylable-select-styles.css b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/resources/stylable-select-styles.css
new file mode 100644
index 0000000000..042de838d1
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/resources/stylable-select-styles.css
@@ -0,0 +1,37 @@
+/* These are UA styles for select and stylable select. */
+
+.stylable-select-container {
+ background-color: Field;
+ border: 1px solid rgba(0, 0, 0, 0);
+ border-radius: 0;
+ box-sizing: border-box;
+ display: inline-block;
+}
+
+.stylable-select-datalist {
+ box-shadow: 0px 12.8px 28.8px rgba(0, 0, 0, 0.13), 0px 0px 9.2px rgba(0, 0, 0, 0.11);
+ box-sizing: border-box;
+ overflow: auto;
+ border: 1px solid rgba(0, 0, 0, 0.15);
+ border-radius: 0.25em;
+ padding: 0.25em 0;
+ background-color: Field;
+ margin: 0;
+ inset: auto;
+ min-inline-size: anchor-size(self-inline);
+ min-block-size: 1lh;
+ inset-block-start: anchor(self-end);
+ inset-inline-start: anchor(self-start);
+
+ font-family: Arial;
+ font-size: 13.3333px;
+}
+
+/* These are the UA styles for <option> in chromium.
+ * They will either have to be specced or also added to the main test file.
+ * TODO(crbug.com/1511354): Spec these UA styles. */
+.stylable-select-option {
+ min-height: 1.2em;
+ padding: 0px 2px 1px;
+ white-space: nowrap;
+}
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-custom-button-no-datalist.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-custom-button-no-datalist.tentative.html
new file mode 100644
index 0000000000..94d7fd53b3
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-custom-button-no-datalist.tentative.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/whatwg/html/issues/9799">
+<link rel=match href="select-appearance-no-button-custom-datalist-ref.html">
+<link rel=stylesheet href="resources/select-reset-non-interoperable-styles.css">
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<select style="appearance:base-select">
+ <button type=popover>one</button>
+ <option>one</option>
+ <option>two</option>
+</select>
+
+<script>
+(async () => {
+ await test_driver.bless();
+ document.querySelector('select').showPicker();
+ document.documentElement.classList.remove('reftest-wait');
+})();
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-custom-datalist-ref.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-custom-datalist-ref.html
new file mode 100644
index 0000000000..8e5eadaf57
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-custom-datalist-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<link rel=stylesheet href="resources/stylable-select-styles.css">
+
+<div id=container class=stylable-select-container>
+ <button popovertarget=popover id=button>one</button>
+ <div id=popover popover=auto anchor=container class=stylable-select-datalist>
+ <div class=stylable-select-option>one</div>
+ <div class=stylable-select-option>two</div>
+ </div>
+</div>
+
+<script>
+document.getElementById('popover').showPopover();
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-child-button-and-datalist-invalidation.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-custom-datalist.tentative.html
index f71c1e52fc..87425cf7a3 100644
--- a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-child-button-and-datalist-invalidation.tentative.html
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-custom-datalist.tentative.html
@@ -2,12 +2,12 @@
<html class=reftest-wait>
<link rel=author href="mailto:jarhar@chromium.org">
<link rel=help href="https://github.com/whatwg/html/issues/9799">
-<link rel=match href="select-child-button-and-datalist-ref.html">
+<link rel=match href="select-appearance-no-button-custom-datalist-ref.html">
+<link rel=stylesheet href="resources/select-reset-non-interoperable-styles.css">
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
-<select>
- <button type=popover>button</button>
+<select style="appearance:base-select">
<datalist>
<option>one</option>
<option>two</option>
@@ -15,9 +15,9 @@
</select>
<script>
-requestAnimationFrame(() => {
- document.querySelector('select').style = 'appearance:bikeshed';
- document.querySelector('button').click();
+(async () => {
+ await test_driver.bless();
+ document.querySelector('select').showPicker();
document.documentElement.classList.remove('reftest-wait');
-});
+})();
</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-no-datalist.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-no-datalist.tentative.html
new file mode 100644
index 0000000000..b2a6b5a6d3
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-appearance-no-button-no-datalist.tentative.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/whatwg/html/issues/9799">
+<link rel=match href="select-appearance-no-button-custom-datalist-ref.html">
+<link rel=stylesheet href="resources/select-reset-non-interoperable-styles.css">
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<select style="appearance:base-select">
+ <option>one</option>
+ <option>two</option>
+</select>
+
+<script>
+(async () => {
+ await test_driver.bless();
+ document.querySelector('select').showPicker();
+ document.documentElement.classList.remove('reftest-wait');
+})();
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-child-button-and-datalist-invalidation.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-child-button-and-datalist-invalidation.tentative.html
new file mode 100644
index 0000000000..b6d85ac90a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-child-button-and-datalist-invalidation.tentative.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/whatwg/html/issues/9799">
+<link rel=match href="select-child-button-and-datalist-ref.html">
+<link rel=stylesheet href="resources/select-reset-non-interoperable-styles.css">
+
+<style>
+.blue {
+ color: blue;
+}
+</style>
+
+<select>
+ <button type=popover>button</button>
+ <datalist>
+ <option>
+ <span class=blue>option</span> one
+ </option>
+ <option>
+ <span class=blue>option</span> two
+ </option>
+ </datalist>
+</select>
+
+<script>
+requestAnimationFrame(() => {
+ document.querySelector('select').style = 'appearance:base-select';
+ document.querySelector('button').click();
+ document.documentElement.classList.remove('reftest-wait');
+});
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-child-button-and-datalist-ref.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-child-button-and-datalist-ref.html
new file mode 100644
index 0000000000..e99ca4d57a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-child-button-and-datalist-ref.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<link rel=stylesheet href="resources/stylable-select-styles.css">
+
+<style>
+.blue {
+ color: blue;
+}
+</style>
+
+<div id=container class=stylable-select-container>
+ <button popovertarget=popover id=button>button</button>
+ <div id=popover popover=auto anchor=container class=stylable-select-datalist>
+ <div tabindex=0 class=stylable-select-option>
+ <span class=blue>option</span> one
+ </div>
+ <div tabindex=0 class=stylable-select-option>
+ <span class=blue>option</span> two
+ </div>
+ </div>
+</div>
+
+<script>
+document.getElementById('popover').showPopover();
+document.querySelector('div.stylable-select-option').focus();
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-child-button-and-datalist.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-child-button-and-datalist.tentative.html
index 54785ace95..610861aad8 100644
--- a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-child-button-and-datalist.tentative.html
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-child-button-and-datalist.tentative.html
@@ -2,14 +2,23 @@
<link rel=author href="mailto:jarhar@chromium.org">
<link rel=help href="https://github.com/whatwg/html/issues/9799">
<link rel=match href="select-child-button-and-datalist-ref.html">
-<script src="/resources/testdriver.js"></script>
-<script src="/resources/testdriver-vendor.js"></script>
+<link rel=stylesheet href="resources/select-reset-non-interoperable-styles.css">
-<select style="appearance:bikeshed">
+<style>
+.blue {
+ color: blue;
+}
+</style>
+
+<select style="appearance:base-select">
<button type=popover>button</button>
<datalist>
- <option>one</option>
- <option>two</option>
+ <option>
+ <span class=blue>option</span> one
+ </option>
+ <option>
+ <span class=blue>option</span> two
+ </option>
</datalist>
</select>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-datalist-options-idl.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-datalist-options-idl.tentative.html
index 993f6e126c..92eabdc5d8 100644
--- a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-datalist-options-idl.tentative.html
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-datalist-options-idl.tentative.html
@@ -12,6 +12,9 @@
</div>
<option class=three>three</option>
</datalist>
+ <datalist>
+ <option>ignored since not in first datalist</option>
+ </datalist>
</select>
<script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-keyboard-behavior.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-keyboard-behavior.tentative.html
new file mode 100644
index 0000000000..2fb11ba68b
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-keyboard-behavior.tentative.html
@@ -0,0 +1,208 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1422275">
+<link rel=help href="https://github.com/openui/open-ui/issues/433#issuecomment-1452461404">
+<link rel=help href="https://github.com/openui/open-ui/issues/386#issuecomment-1452469497">
+<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>
+
+<style>
+select {
+ appearance: base-select;
+}
+</style>
+
+<form></form>
+
+<div id=notform>
+ <select id=defaultbutton-defaultdatalist>
+ <option class=one>one</option>
+ <option class=two>two</option>
+ <option class=three>three</option>
+ </select>
+
+ <select id=defaultbutton-customdatalist>
+ <datalist>
+ <option class=one>one</option>
+ <option class=two>two</option>
+ <option class=three>three</option>
+ </datalist>
+ </select>
+
+ <select id=custombutton-defaultdatalist>
+ <button type=popover>custom button</button>
+ <option class=one>one</option>
+ <option class=two>two</option>
+ <option class=three>three</option>
+ </select>
+
+ <select id=custombutton-customdatalist>
+ <button type=popover>custom button</button>
+ <datalist>
+ <option class=one>one</option>
+ <option class=two>two</option>
+ <option class=three>three</option>
+ </datalist>
+ </select>
+</div>
+
+<script>
+const Enter = '\uE007';
+const Escape = '\uE00C';
+const ArrowLeft = '\uE012';
+const ArrowUp = '\uE013';
+const ArrowRight = '\uE014';
+const ArrowDown = '\uE015';
+const Space = ' ';
+const form = document.querySelector('form');
+const notform = document.getElementById('notform');
+
+for (const id of ['defaultbutton-defaultdatalist',
+ 'defaultbutton-customdatalist',
+ 'custombutton-defaultdatalist',
+ 'custombutton-customdatalist']) {
+ const select = document.getElementById(id);
+
+ async function closeListbox() {
+ await test_driver.click(select);
+ }
+
+ function addCloseCleanup(t) {
+ t.add_cleanup(async () => {
+ if (select.matches(':open')) {
+ await closeListbox();
+ }
+ if (select.matches(':open')) {
+ throw new Error('select failed to close!');
+ }
+ select.value = 'one';
+ });
+ }
+
+ promise_test(async t => {
+ addCloseCleanup(t);
+ // TODO(http://crbug.com/1350299): When focus for custom buttons is fixed,
+ // then we shouldn't need to explicitly focus the custom button like this
+ // anymore.
+ const customButton = select.querySelector('button');
+ if (customButton) {
+ customButton.focus();
+ } else {
+ select.focus();
+ }
+ assert_false(select.matches(':open'),
+ 'The select should initially be closed.');
+ await test_driver.send_keys(document.activeElement, Space);
+ assert_true(select.matches(':open'),
+ 'The select should be open after pressing space.');
+ }, `${id}: When the listbox is closed, spacebar should open the listbox.`);
+
+ promise_test(async t => {
+ addCloseCleanup(t);
+ select.value = 'two';
+ select.focus();
+ assert_false(select.matches(':open'),
+ 'The select should initially be closed.');
+
+ await test_driver.send_keys(document.activeElement, ArrowLeft);
+ assert_true(select.matches(':open'),
+ 'Arrow left should open the listbox.');
+ assert_equals(select.value, 'two',
+ 'Arrow left should not change the selected value.');
+ await closeListbox();
+
+ await test_driver.send_keys(document.activeElement, ArrowUp);
+ assert_true(select.matches(':open'),
+ 'Arrow up should open the listbox.');
+ assert_equals(select.value, 'two',
+ 'Arrow up should not change the selected value.');
+ await closeListbox();
+
+ await test_driver.send_keys(document.activeElement, ArrowRight);
+ assert_true(select.matches(':open'),
+ 'Arrow right should open the listbox.');
+ assert_equals(select.value, 'two',
+ 'Arrow right should not change the selected value.');
+ await closeListbox();
+
+ await test_driver.send_keys(document.activeElement, ArrowDown);
+ assert_true(select.matches(':open'),
+ 'Arrow down should open the listbox.');
+ assert_equals(select.value, 'two',
+ 'Arrow down should not change the selected value.');
+ }, `${id}: When the listbox is closed, all arrow keys should open the listbox.`);
+
+ promise_test(async t => {
+ addCloseCleanup(t);
+
+ // TODO(http://crbug.com/1350299): When focus for custom buttons is fixed,
+ // then we shouldn't need to explicitly use the custom button like this
+ // anymore.
+ const customButton = select.querySelector('button');
+ if (customButton) {
+ await test_driver.send_keys(customButton, Enter);
+ } else {
+ await test_driver.send_keys(select, Enter);
+ }
+ assert_false(select.matches(':open'),
+ 'Enter should not open the listbox when outside a form.');
+
+ form.appendChild(select);
+ let formWasSubmitted = false;
+ form.addEventListener('submit', event => {
+ event.preventDefault();
+ formWasSubmitted = true;
+ }, {once: true});
+ if (customButton) {
+ await test_driver.send_keys(customButton, Enter);
+ } else {
+ await test_driver.send_keys(select, Enter);
+ }
+ assert_true(formWasSubmitted,
+ 'Enter should submit the form when the listbox is closed.');
+ assert_false(select.matches(':open'),
+ 'Enter should not open the listbox when it is in a form.');
+ }, `${id}: When the listbox is closed, the enter key should submit the form or do nothing.`);
+
+ promise_test(async t => {
+ addCloseCleanup(t);
+ const optionOne = select.querySelector('.one');
+ const optionTwo = select.querySelector('.two');
+ const optionThree = select.querySelector('.three');
+
+ select.value = 'two';
+ await test_driver.click(select);
+ assert_true(select.matches(':open'),
+ 'The select should open when clicked.');
+ assert_equals(document.activeElement, optionTwo,
+ 'The selected option should receive initial focus.');
+
+ await test_driver.send_keys(document.activeElement, ArrowDown);
+ assert_equals(document.activeElement, optionThree,
+ 'The next option should receive focus when the down arrow key is pressed.');
+ assert_equals(select.value, 'two',
+ 'The selects value should not change when focusing another option.');
+
+ await test_driver.send_keys(document.activeElement, ArrowUp);
+ assert_equals(document.activeElement, optionTwo,
+ 'The previous option should receive focus when the up arrow key is pressed.');
+ assert_equals(select.value, 'two',
+ 'The selects value should not change when focusing another option.');
+
+ await test_driver.send_keys(document.activeElement, ArrowUp);
+ assert_equals(document.activeElement, optionOne,
+ 'The first option should be selected.');
+ assert_equals(select.value, 'two',
+ 'The selects value should not change when focusing another option.');
+
+ await test_driver.send_keys(document.activeElement, Enter);
+ assert_false(select.matches(':open'),
+ 'The listbox should be closed after pressing enter.');
+ assert_equals(select.value, 'one',
+ 'The selects value should change after pressing enter on a different option.');
+ }, `${id}: When the listbox is open, the enter key should commit the selected option.`);
+}
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-mouse-behavior.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-mouse-behavior.tentative.html
new file mode 100644
index 0000000000..aff976d1ad
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-mouse-behavior.tentative.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1422275">
+<link rel=help href="https://github.com/openui/open-ui/issues/433#issuecomment-1452461404">
+<link rel=help href="https://github.com/openui/open-ui/issues/386#issuecomment-1452469497">
+<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>
+
+<style>
+select {
+ appearance: base-select;
+}
+</style>
+
+<!-- TODO(http://crbug.com/1511354): Add test cases with no <button> and no <datalist>. -->
+<select>
+ <button type=popover>button</button>
+ <datalist>
+ <option class=one>one</option>
+ <option class=two>two</option>
+ </datalist>
+</select>
+
+<script>
+const select = document.querySelector('select');
+const button = document.querySelector('button');
+const optionOne = document.querySelector('option.one');
+const optionTwo = document.querySelector('option.two');
+
+promise_test(async () => {
+ assert_false(select.matches(':open'),
+ 'Select should be closed at the start of the test.');
+
+ await test_driver.click(button);
+ assert_true(select.matches(':open'),
+ 'Select should be open after clicking the button.');
+
+ await test_driver.click(button);
+ assert_false(select.matches(':open'),
+ 'Select should be closed after clicking the button a second time.');
+}, 'Select with appearance:base-select should open and close when clicking the button.');
+
+promise_test(async () => {
+ assert_false(select.matches(':open'),
+ 'Select should be closed at the start of the test.');
+ assert_equals(select.value, 'one',
+ 'Select.value should be one at the start of the test.');
+
+ await test_driver.click(button);
+ assert_true(select.matches(':open'),
+ 'Select should be open after clicking the button.');
+
+ await test_driver.click(optionTwo);
+ assert_false(select.matches(':open'),
+ 'Select should be closed after clicking an option.');
+ assert_equals(select.value, 'two',
+ 'Select.value should be two after clicking the option.');
+}, 'Clicking an option in an appearance:base-select select should choose the option and close the popover.');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-parsing.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-parsing.tentative.html
index 31133446d4..31133446d4 100644
--- a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-parsing.tentative.html
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/select-parsing.tentative.html
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/selectedoption.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/selectedoption.tentative.html
new file mode 100644
index 0000000000..16d711515c
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/stylable-select/selectedoption.tentative.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/whatwg/html/issues/9799">
+<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>
+ <select style="appearance:base-select">
+ <button>
+ <selectedoption></selectedoption>
+ </button>
+ <datalist>
+ <option class=one value=one>
+ <span class=one>span</span> one
+ </option>
+ <option class=two value=two>
+ <span class=two>span</span> two
+ </option>
+ </datalist>
+ </select>
+</form>
+
+<script>
+promise_test(async () => {
+ const optionOne = document.querySelector('option.one');
+ const optionTwo = document.querySelector('option.two');
+ const selectedOption = document.querySelector('selectedoption');
+ const select = document.querySelector('select');
+ const spanTwo = document.querySelector('span.two');
+ const form = document.querySelector('form');
+ const button = document.querySelector('button');
+
+ assert_equals(selectedOption.innerHTML, optionOne.innerHTML,
+ 'The innerHTML of <selectedoption> should initially match the innerHTML of the selected <option>.');
+
+ select.value = 'two';
+ assert_equals(selectedOption.innerHTML, optionTwo.innerHTML,
+ 'The innerHTML of <selectedoption> should change after the selected option is changed.');
+
+ spanTwo.textContent = 'new span';
+ assert_equals(selectedOption.innerHTML, optionTwo.innerHTML,
+ '<selectedoption> should respond to text content changes.');
+
+ spanTwo.appendChild(document.createElement('div'));
+ assert_equals(selectedOption.innerHTML, optionTwo.innerHTML,
+ '<selectedoption> should respond to new elements being added to descendants.');
+
+ spanTwo.setAttribute('data-foo', 'bar');
+ assert_equals(selectedOption.innerHTML, optionTwo.innerHTML,
+ '<selectedoption> should respond to attributes being added to descendants.');
+
+ form.reset();
+ assert_equals(select.value, 'one',
+ 'form.reset() should change the selects value to one.');
+ assert_equals(selectedOption.innerHTML, optionOne.innerHTML,
+ 'The innerHTML of <selectedoption> should be updated in response to a form reset.');
+
+ await test_driver.bless();
+ select.showPicker();
+ await test_driver.click(optionTwo);
+ assert_equals(select.value, 'two',
+ 'Clicking on another option should change select.value.');
+ assert_equals(selectedOption.innerHTML, optionTwo.innerHTML,
+ 'Clicking on an option element should update the <selectedoption>.');
+
+ selectedOption.remove();
+ assert_equals(selectedOption.innerHTML, '',
+ 'Removing the <selectedoption> from the <select> should make it clear its contents.');
+ button.appendChild(selectedOption);
+ assert_equals(selectedOption.innerHTML, optionTwo.innerHTML,
+ 'Re-inserting the <selectedoption> should make it update its contents.');
+
+ optionTwo.remove();
+ assert_equals(selectedOption.innerHTML, optionOne.innerHTML,
+ 'The innerHTML of <selectedoption> should be updated in response to selected <option> removal.');
+ optionOne.remove();
+ assert_equals(selectedOption.innerHTML, '',
+ 'The content of <selectedoption> should be cleared if there is no selected <option>.');
+}, 'The <selectedoption> element should reflect the HTML contents of the selected <option>.');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/idlharness.tentative.html b/testing/web-platform/tests/html/semantics/invokers/idlharness.tentative.html
index b215f65813..8a86a5aaa1 100644
--- a/testing/web-platform/tests/html/semantics/invokers/idlharness.tentative.html
+++ b/testing/web-platform/tests/html/semantics/invokers/idlharness.tentative.html
@@ -1,6 +1,6 @@
<!doctype html>
<meta charset="utf-8" />
-<meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" />
+<meta name="author" title="Keith Cirkel" href="mailto:wpt@keithcirkel.co.uk" />
<link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/interestelement-interface.tentative.html b/testing/web-platform/tests/html/semantics/invokers/interestelement-interface.tentative.html
index dc119de833..8b1e375695 100644
--- a/testing/web-platform/tests/html/semantics/invokers/interestelement-interface.tentative.html
+++ b/testing/web-platform/tests/html/semantics/invokers/interestelement-interface.tentative.html
@@ -1,5 +1,6 @@
<!doctype html>
<meta charset="utf-8" />
+<meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" />
<meta name="author" title="Luke Warlow" href="mailto:lwarlow@igalia.com" />
<link rel="help" href="https://open-ui.org/components/interest-invokers.explainer/" />
<script src="/resources/testharness.js"></script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/interestevent-dispatch-shadow.tentative.html b/testing/web-platform/tests/html/semantics/invokers/interestevent-dispatch-shadow.tentative.html
new file mode 100644
index 0000000000..d96907ec84
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/invokers/interestevent-dispatch-shadow.tentative.html
@@ -0,0 +1,104 @@
+<!doctype html>
+<meta charset="utf-8" />
+<meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" />
+<meta name="author" title="Luke Warlow" href="mailto:lwarlow@igalia.com" />
+<link rel="help" href="https://open-ui.org/components/interest-invokers.explainer/" />
+<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="resources/invoker-utils.js"></script>
+
+<div id="div"></div>
+<button id="button"></button>
+
+<script>
+ test(function () {
+ const host = document.createElement("div");
+ const shadow = host.attachShadow({ mode: "closed" });
+ const slot = shadow.appendChild(document.createElement("slot"));
+ let childEvent = null;
+ let childEventTarget = null;
+ let childEventInvoker = null;
+ let hostEvent = null;
+ let hostEventTarget = null;
+ let hostEventInvoker = null;
+ slot.addEventListener(
+ "interest",
+ (e) => {
+ childEvent = e;
+ childEventTarget = e.target;
+ childEventInvoker = e.invoker;
+ },
+ { once: true },
+ );
+ host.addEventListener(
+ "interest",
+ (e) => {
+ hostEvent = e;
+ hostEventTarget = e.target;
+ hostEventInvoker = e.invoker;
+ },
+ { once: true },
+ );
+ const event = new InterestEvent("interest", {
+ bubbles: true,
+ invoker: slot,
+ composed: true,
+ });
+ slot.dispatchEvent(event);
+ assert_true(childEvent instanceof InterestEvent, "slot saw interest event");
+ assert_equals(
+ childEventTarget,
+ slot,
+ "target is child inside shadow boundary",
+ );
+ assert_equals(
+ childEventInvoker,
+ slot,
+ "invoker is child inside shadow boundary",
+ );
+ assert_equals(
+ hostEvent,
+ childEvent,
+ "event dispatch propagates across shadow boundary",
+ );
+ assert_equals(
+ hostEventTarget,
+ host,
+ "target is retargeted to shadowroot host",
+ );
+ assert_equals(
+ hostEventInvoker,
+ host,
+ "invoker is retargeted to shadowroot host",
+ );
+ }, "InterestEvent propagates across shadow boundaries retargeting invoker");
+
+ test(function (t) {
+ const host = document.createElement("div");
+ document.body.append(host);
+ t.add_cleanup(() => host.remove());
+ const shadow = host.attachShadow({ mode: "open" });
+ const button = shadow.appendChild(document.createElement("button"));
+ const interestee = host.appendChild(document.createElement("div"));
+ button.interestTargetElement = interestee;
+ let event = null;
+ let eventTarget = null;
+ let eventInvoker = null;
+ interestee.addEventListener(
+ "interest",
+ (e) => {
+ event = e;
+ eventTarget = e.target;
+ eventInvoker = e.invoker;
+ },
+ { once: true },
+ );
+ button.focus();
+ assert_true(event instanceof InterestEvent);
+ assert_equals(eventTarget, interestee, "target is interestee");
+ assert_equals(eventInvoker, host, "interestee is host");
+ }, "cross shadow InterestEvent retargets interestee to host element");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/interestevent-interface.tentative.html b/testing/web-platform/tests/html/semantics/invokers/interestevent-interface.tentative.html
new file mode 100644
index 0000000000..ed7d82f1fb
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/invokers/interestevent-interface.tentative.html
@@ -0,0 +1,167 @@
+<!doctype html>
+<meta charset="utf-8" />
+<meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" />
+<meta name="author" title="Luke Warlow" href="mailto:lwarlow@igalia.com" />
+<link rel="help" href="https://open-ui.org/components/interest-invokers.explainer/" />
+<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="resources/invoker-utils.js"></script>
+
+<div id="div"></div>
+<button id="button"></button>
+
+<script>
+ test(function () {
+ const event = new InterestEvent("test");
+ assert_equals(event.action, "");
+ assert_readonly(event, "action", "readonly attribute value");
+ }, "action is a readonly defaulting to ''");
+
+ test(function () {
+ const event = new InterestEvent("test");
+ assert_equals(event.invoker, null);
+ assert_readonly(event, "invoker", "readonly attribute value");
+ }, "invoker is readonly defaulting to null");
+
+ test(function () {
+ const event = new InterestEvent("test", { action: "sAmPle" });
+ assert_equals(event.action, "sAmPle");
+ }, "action reflects initialized attribute");
+
+ test(function () {
+ const event = new InterestEvent("test", { action: undefined });
+ assert_equals(event.action, "");
+ }, "action set to undefined");
+
+ test(function () {
+ const event = new InterestEvent("test", { action: null });
+ assert_equals(event.action, "null");
+ }, "action set to null");
+
+ test(function () {
+ const event = new InterestEvent("test", { action: false });
+ assert_equals(event.action, "false");
+ }, "action set to false");
+
+ test(function () {
+ const event = new InterestEvent("test", { action: "" });
+ assert_equals(event.action, "");
+ }, "action explicitly set to empty string");
+
+ test(function () {
+ const event = new InterestEvent("test", { action: true });
+ assert_equals(event.action, "true");
+ }, "action set to true");
+
+ test(function () {
+ const event = new InterestEvent("test", { action: 0.5 });
+ assert_equals(event.action, "0.5");
+ }, "action set to a number");
+
+ test(function () {
+ const event = new InterestEvent("test", { action: [] });
+ assert_equals(event.action, "");
+ }, "action set to []");
+
+ test(function () {
+ const event = new InterestEvent("test", { action: [1, 2, 3] });
+ assert_equals(event.action, "1,2,3");
+ }, "action set to [1, 2, 3]");
+
+ test(function () {
+ const event = new InterestEvent("test", { action: { sample: 0.5 } });
+ assert_equals(event.action, "[object Object]");
+ }, "action set to an object");
+
+ test(function () {
+ const event = new InterestEvent("test", {
+ action: {
+ toString() {
+ return "sample";
+ },
+ },
+ });
+ assert_equals(event.action, "sample");
+ }, "action set to an object with a toString function");
+
+ test(function () {
+ const eventInit = { action: "sample", invoker: document.body };
+ const event = new InterestEvent("test", eventInit);
+ assert_equals(event.action, "sample");
+ assert_equals(event.invoker, document.body);
+ }, "InterestEventInit properties set value");
+
+ test(function () {
+ const eventInit = {
+ action: "open",
+ invoker: document.getElementById("div"),
+ };
+ const event = new InterestEvent("beforetoggle", eventInit);
+ assert_equals(event.action, "open");
+ assert_equals(event.invoker, document.getElementById("div"));
+ }, "InterestEventInit properties set value 2");
+
+ test(function () {
+ const eventInit = {
+ action: "closed",
+ invoker: document.getElementById("button"),
+ };
+ const event = new InterestEvent("toggle", eventInit);
+ assert_equals(event.action, "closed");
+ assert_equals(event.invoker, document.getElementById("button"));
+ }, "InterestEventInit properties set value 3");
+
+ test(function () {
+ const event = new InterestEvent("test", { invoker: undefined });
+ assert_equals(event.invoker, null);
+ }, "invoker set to undefined");
+
+ test(function () {
+ const event = new InterestEvent("test", { invoker: null });
+ assert_equals(event.invoker, null);
+ }, "invoker set to null");
+
+ test(function () {
+ assert_throws_js(
+ TypeError,
+ function () {
+ new InterestEvent("test", { invoker: false });
+ },
+ "invoker is not an object",
+ );
+ }, "invoker set to false");
+
+ test(function () {
+ assert_throws_js(
+ TypeError,
+ function () {
+ const event = new InterestEvent("test", { invoker: true });
+ },
+ "invoker is not an object",
+ );
+ }, "invoker set to true");
+
+ test(function () {
+ assert_throws_js(
+ TypeError,
+ function () {
+ const event = new InterestEvent("test", { invoker: {} });
+ },
+ "invoker is not an object",
+ );
+ }, "invoker set to {}");
+
+ test(function () {
+ assert_throws_js(
+ TypeError,
+ function () {
+ const eventInit = { action: "closed", invoker: new XMLHttpRequest() };
+ const event = new InterestEvent("toggle", eventInit);
+ },
+ "invoker is not an Element",
+ );
+ }, "invoker set to non-Element EventTarget");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/interesttarget-button-event-dispatch.tentative.html b/testing/web-platform/tests/html/semantics/invokers/interesttarget-button-event-dispatch.tentative.html
new file mode 100644
index 0000000000..7fdfdfaa70
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/invokers/interesttarget-button-event-dispatch.tentative.html
@@ -0,0 +1,155 @@
+<!doctype html>
+<meta charset="utf-8" />
+<meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" />
+<meta name="author" title="Luke Warlow" href="mailto:lwarlow@igalia.com" />
+<link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
+<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="resources/invoker-utils.js"></script>
+
+<div id="interestee"></div>
+<button id="interestbutton" interesttarget="interestee">Button</button>
+<a href="/" id="interestanchor" interesttarget="interestee">Anchor</a>
+<button id="otherbutton">Other Button</button>
+
+<script>
+ promise_test(async function (t) {
+ t.add_cleanup(() => otherbutton.focus());
+ let event = null;
+ interestee.addEventListener("interest", (e) => (event = e), { once: true });
+ interestbutton.focus();
+ assert_true(event instanceof InterestEvent, "event is InterestEvent");
+ assert_equals(event.type, "interest", "type");
+ assert_equals(event.bubbles, false, "bubbles");
+ assert_equals(event.composed, true, "composed");
+ assert_equals(event.isTrusted, true, "isTrusted");
+ assert_equals(event.action, "", "action");
+ assert_equals(event.target, interestee, "target");
+ assert_equals(event.invoker, interestbutton, "invoker");
+ }, "InterestEvent dispatches on button focus");
+
+ promise_test(async function (t) {
+ t.add_cleanup(() => otherbutton.focus());
+ let event = null;
+ interestee.addEventListener("interest", (e) => (event = e), { once: true });
+ await hoverOver(interestbutton);
+ assert_true(event instanceof InterestEvent, "event is InterestEvent");
+ assert_equals(event.type, "interest", "type");
+ assert_equals(event.bubbles, false, "bubbles");
+ assert_equals(event.composed, true, "composed");
+ assert_equals(event.isTrusted, true, "isTrusted");
+ assert_equals(event.action, "", "action");
+ assert_equals(event.target, interestee, "target");
+ assert_equals(event.invoker, interestbutton, "invoker");
+ }, "InterestEvent dispatches on button hover");
+
+ promise_test(async function (t) {
+ t.add_cleanup(() => otherbutton.focus());
+ let event = null;
+ interestee.addEventListener("interest", (e) => (event = e), { once: true });
+ interestanchor.focus();
+ assert_true(event instanceof InterestEvent, "event is InterestEvent");
+ assert_equals(event.type, "interest", "type");
+ assert_equals(event.bubbles, false, "bubbles");
+ assert_equals(event.composed, true, "composed");
+ assert_equals(event.isTrusted, true, "isTrusted");
+ assert_equals(event.action, "", "action");
+ assert_equals(event.target, interestee, "target");
+ assert_equals(event.invoker, interestanchor, "invoker");
+ }, "InterestEvent dispatches on anchor focus");
+
+ promise_test(async function (t) {
+ t.add_cleanup(() => otherbutton.focus());
+ let event = null;
+ interestee.addEventListener("interest", (e) => (event = e), { once: true });
+ await hoverOver(interestanchor);
+ assert_true(event instanceof InterestEvent, "event is InterestEvent");
+ assert_equals(event.type, "interest", "type");
+ assert_equals(event.bubbles, false, "bubbles");
+ assert_equals(event.composed, true, "composed");
+ assert_equals(event.isTrusted, true, "isTrusted");
+ assert_equals(event.action, "", "action");
+ assert_equals(event.target, interestee, "target");
+ assert_equals(event.invoker, interestanchor, "invoker");
+ }, "InterestEvent dispatches on anchor hover");
+
+ promise_test(async function (t) {
+ t.add_cleanup(() => otherbutton.focus());
+ let event = null;
+ interestee.addEventListener("interest", (e) => (event = e), { once: true });
+ interestbutton.interestAction = "fooBar";
+ interestbutton.focus();
+ assert_true(event instanceof InterestEvent, "event is InterestEvent");
+ assert_equals(event.type, "interest", "type");
+ assert_equals(event.bubbles, false, "bubbles");
+ assert_equals(event.composed, true, "composed");
+ assert_equals(event.isTrusted, true, "isTrusted");
+ assert_equals(event.action, "fooBar", "action");
+ assert_equals(event.target, interestee, "target");
+ assert_equals(event.invoker, interestbutton, "invoker");
+ }, "event action is set to interestAction");
+
+ promise_test(async function (t) {
+ t.add_cleanup(() => otherbutton.focus());
+ let event = null;
+ interestee.addEventListener("interest", (e) => (event = e), { once: true });
+ interestbutton.setAttribute("interestaction", "BaRbAz");
+ interestbutton.focus();
+ assert_true(event instanceof InterestEvent, "event is InterestEvent");
+ assert_equals(event.type, "interest", "type");
+ assert_equals(event.bubbles, false, "bubbles");
+ assert_equals(event.composed, true, "composed");
+ assert_equals(event.isTrusted, true, "isTrusted");
+ assert_equals(event.action, "BaRbAz", "action");
+ assert_equals(event.target, interestee, "target");
+ assert_equals(event.invoker, interestbutton, "invoker");
+ }, "event action is set to interestaction attribute");
+
+ promise_test(async function (t) {
+ t.add_cleanup(() => {
+ interestbutton.removeAttribute('disabled');
+ otherbutton.focus();
+ });
+ let called = false;
+ interestee.addEventListener(
+ "interest",
+ () => {
+ called = true;
+ },
+ { once: true },
+ );
+ interestbutton.setAttribute("disabled", "");
+ interestbutton.focus();
+ assert_false(called, "event was not called");
+ }, "event does not dispatch if invoker is disabled");
+
+ promise_test(async function (t) {
+ svgInterestee = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
+ t.add_cleanup(() => {
+ interestbutton.interestTargetElement = interestee;
+ svgInterestee.remove();
+ otherbutton.focus();
+ });
+ document.body.append(svgInterestee);
+ let called = false;
+ assert_false(svgInterestee instanceof HTMLElement);
+ assert_true(svgInterestee instanceof Element);
+ let event = null;
+ svgInterestee.addEventListener(
+ "interest",
+ (e) => {
+ event = e;
+ called = true;
+ },
+ { once: true },
+ );
+ interestbutton.interestTargetElement = svgInterestee;
+ interestbutton.focus();
+ assert_true(called, "event was called");
+ assert_equals(event.invoker, interestbutton, "event.invoker is set to right element");
+ assert_equals(event.target, svgInterestee, "event.target is set to right element");
+ }, "event dispatches if interestee is non-HTML Element");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/interesttarget-on-popover-behavior.tentative.html b/testing/web-platform/tests/html/semantics/invokers/interesttarget-on-popover-behavior.tentative.html
new file mode 100644
index 0000000000..b930fc645d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/invokers/interesttarget-on-popover-behavior.tentative.html
@@ -0,0 +1,113 @@
+<!doctype html>
+<meta charset="utf-8" />
+<meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" />
+<meta name="author" title="Luke Warlow" href="mailto:lwarlow@igalia.com" />
+<link rel="help" href="https://open-ui.org/components/interest-invokers.explainer/" />
+<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="resources/invoker-utils.js"></script>
+
+<div id="interestee" popover>
+ Popover Content
+</div>
+<button id="interestbutton" interesttarget="interestee">Interest Invoker</button>
+<button id="otherbutton">Other button</button>
+
+<script>
+ function reset() {
+ hoverOver(otherbutton);
+ otherbutton.focus();
+ interestee.hidePopover();
+ interestbutton.removeAttribute("interestaction");
+ }
+
+ // auto
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ assert_false(interestee.matches(":popover-open"));
+ await hoverOver(interestbutton);
+ assert_true(interestee.matches(":popover-open"));
+ }, "hover interest invoking (as auto) closed popover opens");
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ interestee.showPopover();
+ assert_true(interestee.matches(":popover-open"));
+ await hoverOver(interestbutton);
+ assert_false(interestee.matches(":popover-open"));
+ }, "hover interest invoking (as auto) open popover closes");
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ assert_false(interestee.matches(":popover-open"));
+ interestbutton.focus();
+ assert_true(interestee.matches(":popover-open"));
+ }, "focus interest invoking (as auto) closed popover opens");
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ interestee.showPopover();
+ assert_true(interestee.matches(":popover-open"));
+ interestbutton.focus();
+ assert_false(interestee.matches(":popover-open"));
+ }, "focus interest invoking (as auto) open popover closes");
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ assert_false(interestee.matches(":popover-open"));
+ interestee.addEventListener("interest", (e) => e.preventDefault(), {
+ once: true,
+ });
+ await hoverOver(interestbutton);
+ assert_false(interestee.matches(":popover-open"));
+ }, "interest invoking (as auto) closed popover with preventDefault does not open");
+
+ // togglepopover
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ assert_false(interestee.matches(":popover-open"));
+ interestbutton.setAttribute("interestaction", "togglepopover");
+ await hoverOver(interestbutton);
+ assert_true(interestee.matches(":popover-open"));
+ }, "hover interest invoking (as togglepopover) closed popover opens");
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ interestee.showPopover();
+ assert_true(interestee.matches(":popover-open"));
+ interestbutton.setAttribute("interestaction", "togglepopover");
+ await hoverOver(interestbutton);
+ assert_false(interestee.matches(":popover-open"));
+ }, "hover interest invoking (as togglepopover) open popover closes");
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ assert_false(interestee.matches(":popover-open"));
+ interestbutton.setAttribute("interestaction", "togglepopover");
+ interestbutton.focus();
+ assert_true(interestee.matches(":popover-open"));
+ }, "focus interest invoking (as togglepopover) closed popover opens");
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ interestee.showPopover();
+ assert_true(interestee.matches(":popover-open"));
+ interestbutton.setAttribute("interestaction", "togglepopover");
+ interestbutton.focus();
+ assert_false(interestee.matches(":popover-open"));
+ }, "focus interest invoking (as togglepopover) open popover closes");
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ assert_false(interestee.matches(":popover-open"));
+ interestbutton.setAttribute("interestaction", "tOgGlEpOpOvEr");
+ interestbutton.focus();
+ assert_true(interestee.matches(":popover-open"));
+ }, "interest invoking (as togglepopover - case insensitive) closed popover opens");
+
+</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/invokeelement-interface.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invokeelement-interface.tentative.html
index 5a2854fe31..5adacadabb 100644
--- a/testing/web-platform/tests/html/semantics/invokers/invokeelement-interface.tentative.html
+++ b/testing/web-platform/tests/html/semantics/invokers/invokeelement-interface.tentative.html
@@ -1,6 +1,6 @@
<!doctype html>
<meta charset="utf-8" />
-<meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" />
+<meta name="author" title="Keith Cirkel" href="mailto:wpt@keithcirkel.co.uk" />
<link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/invokeevent-dispatch-shadow.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invokeevent-dispatch-shadow.tentative.html
index 84337d5723..1ecff88760 100644
--- a/testing/web-platform/tests/html/semantics/invokers/invokeevent-dispatch-shadow.tentative.html
+++ b/testing/web-platform/tests/html/semantics/invokers/invokeevent-dispatch-shadow.tentative.html
@@ -1,6 +1,6 @@
<!doctype html>
<meta charset="utf-8" />
-<meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" />
+<meta name="author" title="Keith Cirkel" href="mailto:wpt@keithcirkel.co.uk" />
<link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/invokeevent-interface.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invokeevent-interface.tentative.html
index 382f808071..0cfb4d5ee5 100644
--- a/testing/web-platform/tests/html/semantics/invokers/invokeevent-interface.tentative.html
+++ b/testing/web-platform/tests/html/semantics/invokers/invokeevent-interface.tentative.html
@@ -1,6 +1,6 @@
<!doctype html>
<meta charset="utf-8" />
-<meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" />
+<meta name="author" title="Keith Cirkel" href="mailto:wpt@keithcirkel.co.uk" />
<link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/invoketarget-button-event-dispatch.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invoketarget-button-event-dispatch.tentative.html
index d8d9c04022..9120cc3192 100644
--- a/testing/web-platform/tests/html/semantics/invokers/invoketarget-button-event-dispatch.tentative.html
+++ b/testing/web-platform/tests/html/semantics/invokers/invoketarget-button-event-dispatch.tentative.html
@@ -1,6 +1,7 @@
<!doctype html>
<meta charset="utf-8" />
-<meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" />
+<meta name="author" title="Keith Cirkel" href="mailto:wpt@keithcirkel.co.uk" />
+<meta name="timeout" content="long" />
<link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
@@ -27,35 +28,63 @@
assert_equals(event.invoker, invokerbutton, "invoker");
}, "event dispatches on click");
- promise_test(async function (t) {
- let event = null;
- invokee.addEventListener("invoke", (e) => (event = e), { once: true });
- invokerbutton.invokeAction = "fooBar";
- await clickOn(invokerbutton);
- assert_true(event instanceof InvokeEvent, "event is InvokeEvent");
- assert_equals(event.type, "invoke", "type");
- assert_equals(event.bubbles, false, "bubbles");
- assert_equals(event.composed, true, "composed");
- assert_equals(event.isTrusted, true, "isTrusted");
- assert_equals(event.action, "fooBar", "action");
- assert_equals(event.target, invokee, "target");
- assert_equals(event.invoker, invokerbutton, "invoker");
- }, "event action is set to invokeAction");
+ // valid custom invokeactions
+ ["-foo", "foo-", "cAsE-cArRiEs", "-", "-a-", "a-b", "---", "show-picker"].forEach(
+ (action) => {
+ promise_test(async function (t) {
+ t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
+ let event = null;
+ invokee.addEventListener("invoke", (e) => (event = e), { once: true });
+ invokerbutton.invokeAction = action;
+ await clickOn(invokerbutton);
+ assert_true(event instanceof InvokeEvent, "event is InvokeEvent");
+ assert_equals(event.type, "invoke", "type");
+ assert_equals(event.bubbles, false, "bubbles");
+ assert_equals(event.composed, true, "composed");
+ assert_equals(event.isTrusted, true, "isTrusted");
+ assert_equals(event.action, action, "action");
+ assert_equals(event.target, invokee, "target");
+ assert_equals(event.invoker, invokerbutton, "invoker");
+ }, `setting custom invokeAction property to ${action} (must include dash) sets event action`);
- promise_test(async function (t) {
- let event = null;
- invokee.addEventListener("invoke", (e) => (event = e), { once: true });
- invokerbutton.setAttribute("invokeaction", "BaRbAz");
- await clickOn(invokerbutton);
- assert_true(event instanceof InvokeEvent, "event is InvokeEvent");
- assert_equals(event.type, "invoke", "type");
- assert_equals(event.bubbles, false, "bubbles");
- assert_equals(event.composed, true, "composed");
- assert_equals(event.isTrusted, true, "isTrusted");
- assert_equals(event.action, "BaRbAz", "action");
- assert_equals(event.target, invokee, "target");
- assert_equals(event.invoker, invokerbutton, "invoker");
- }, "event action is set to invokeaction attribute");
+ promise_test(async function (t) {
+ t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
+ let event = null;
+ invokee.addEventListener("invoke", (e) => (event = e), { once: true });
+ invokerbutton.setAttribute("invokeaction", action);
+ await clickOn(invokerbutton);
+ assert_true(event instanceof InvokeEvent, "event is InvokeEvent");
+ assert_equals(event.type, "invoke", "type");
+ assert_equals(event.bubbles, false, "bubbles");
+ assert_equals(event.composed, true, "composed");
+ assert_equals(event.isTrusted, true, "isTrusted");
+ assert_equals(event.action, action, "action");
+ assert_equals(event.target, invokee, "target");
+ assert_equals(event.invoker, invokerbutton, "invoker");
+ }, `setting custom invokeaction attribute to ${action} (must include dash) sets event action`);
+ },
+ );
+
+ // invalid custom invokeactions
+ ["foo", "foobar", "foo bar", "em—dash", "hidedocument"].forEach((action) => {
+ promise_test(async function (t) {
+ t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
+ let event = null;
+ invokee.addEventListener("invoke", (e) => (event = e), { once: true });
+ invokerbutton.invokeAction = action;
+ await clickOn(invokerbutton);
+ assert_equals(event, null, "event should not have fired");
+ }, `setting custom invokeAction property to ${action} (no dash) did not dispatch an event`);
+
+ promise_test(async function (t) {
+ t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
+ let event = null;
+ invokee.addEventListener("invoke", (e) => (event = e), { once: true });
+ invokerbutton.setAttribute("invokeaction", action);
+ await clickOn(invokerbutton);
+ assert_equals(event, null, "event should not have fired");
+ }, `setting custom invokeaction attribute to ${action} (no dash) did not dispatch an event`);
+ });
promise_test(async function (t) {
let called = false;
@@ -78,7 +107,7 @@
}, "event does not dispatch if click:preventDefault is called");
promise_test(async function (t) {
- t.add_cleanup(() => invokerbutton.removeAttribute('disabled'));
+ t.add_cleanup(() => invokerbutton.removeAttribute("disabled"));
let called = false;
invokee.addEventListener(
"invoke",
@@ -93,7 +122,7 @@
}, "event does not dispatch if invoker is disabled");
promise_test(async function (t) {
- svgInvokee = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
+ svgInvokee = document.createElementNS("http://www.w3.org/2000/svg", "svg");
t.add_cleanup(() => {
invokerbutton.invokeTargetElement = invokee;
svgInvokee.remove();
@@ -115,7 +144,15 @@
invokerbutton.invokeTargetElement = svgInvokee;
await clickOn(invokerbutton);
assert_true(called, "event was called");
- assert_equals(eventInvoker, invokerbutton, "event.invoker is set to right element");
- assert_equals(eventTarget, svgInvokee, "event.target is set to right element");
+ assert_equals(
+ eventInvoker,
+ invokerbutton,
+ "event.invoker is set to right element",
+ );
+ assert_equals(
+ eventTarget,
+ svgInvokee,
+ "event.target is set to right element",
+ );
}, "event dispatches if invokee is non-HTML Element");
</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/invoketarget-fullscreen-behavior.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invoketarget-fullscreen-behavior.tentative.html
index b72020283e..2e2c5f683f 100644
--- a/testing/web-platform/tests/html/semantics/invokers/invoketarget-fullscreen-behavior.tentative.html
+++ b/testing/web-platform/tests/html/semantics/invokers/invoketarget-fullscreen-behavior.tentative.html
@@ -1,6 +1,7 @@
<!doctype html>
<meta charset="utf-8" />
<meta name="author" title="Luke Warlow" href="mailto:luke@warlow.dev" />
+<meta name="timeout" content="long" />
<link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-audio-behavior.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-audio-behavior.tentative.html
index f3abeae165..37acb7a539 100644
--- a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-audio-behavior.tentative.html
+++ b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-audio-behavior.tentative.html
@@ -1,6 +1,7 @@
<!doctype html>
<meta charset="utf-8" />
<meta name="author" title="Luke Warlow" href="mailto:luke@warlow.dev" />
+<meta name="timeout" content="long" />
<link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
@@ -25,7 +26,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -43,7 +44,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "playpause");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_false(invokee.paused);
@@ -59,7 +60,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "playpause");
invokerbutton.click();
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_false(invokee.paused);
@@ -78,7 +79,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "playpause");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -91,12 +92,12 @@
invokee.currentTime = 0;
invokee.muted = false;
});
- await test_driver.bless('play audio');
+ await test_driver.bless("play audio");
invokee.play();
assert_false(invokee.paused);
invokerbutton.setAttribute("invokeaction", "playpause");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -114,7 +115,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "play");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_false(invokee.paused);
@@ -130,7 +131,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "play");
invokerbutton.click();
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_false(invokee.paused);
@@ -149,7 +150,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "play");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -162,12 +163,12 @@
invokee.currentTime = 0;
invokee.muted = false;
});
- await test_driver.bless('play audio');
+ await test_driver.bless("play audio");
invokee.play();
assert_false(invokee.paused);
invokerbutton.setAttribute("invokeaction", "play");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_false(invokee.paused);
@@ -185,8 +186,8 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "pause");
await clickOn(invokerbutton);
- await new Promise(resolve => {
- requestAnimationFrame(resolve);
+ await new Promise((resolve) => {
+ requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
}, "invoking audio with pause action is a no-op");
@@ -204,7 +205,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "pause");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -217,12 +218,12 @@
invokee.currentTime = 0;
invokee.muted = false;
});
- await test_driver.bless('play audio');
+ await test_driver.bless("play audio");
invokee.play();
assert_false(invokee.paused);
invokerbutton.setAttribute("invokeaction", "pause");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -240,7 +241,7 @@
assert_false(invokee.muted);
invokerbutton.setAttribute("invokeaction", "toggleMuted");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.muted);
@@ -259,7 +260,7 @@
assert_false(invokee.muted);
invokerbutton.setAttribute("invokeaction", "toggleMuted");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_false(invokee.muted);
@@ -276,10 +277,9 @@
assert_true(invokee.muted);
invokerbutton.setAttribute("invokeaction", "toggleMuted");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_false(invokee.muted);
}, "invoking muted audio with toggleMuted action unmutes it");
-
</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-audio-invalid-behavior.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-audio-invalid-behavior.tentative.html
new file mode 100644
index 0000000000..9e15ce38e8
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-audio-invalid-behavior.tentative.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<meta charset="utf-8" />
+<meta name="author" title="Keith Cirkel" href="mailto:wpt@keithcirkel.co.uk" />
+<meta name="timeout" content="long" />
+<link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
+<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="resources/invoker-utils.js"></script>
+
+<audio controls id="invokee" src="/media/sound_5.mp3"></audio>
+<button id="invokerbutton" invoketarget="invokee"></button>
+
+<script>
+ // invalid actions on audio
+ [
+ "foo-bar",
+ "showpopover",
+ "showmodal",
+ "showpicker",
+ "open",
+ "close",
+ ].forEach((action) => {
+ promise_test(async function (t) {
+ t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
+ invokerbutton.setAttribute("invokeaction", action);
+ assert_true(invokee.paused);
+ assert_false(invokee.muted);
+ await clickOn(invokerbutton);
+ await waitForRender();
+ assert_true(invokee.paused);
+ assert_false(invokee.muted);
+ }, `invoking (as ${action}) on audio does nothing`);
+ });
+</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-details-behavior.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-details-behavior.tentative.html
index c6735e2611..ad9b6caa57 100644
--- a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-details-behavior.tentative.html
+++ b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-details-behavior.tentative.html
@@ -1,6 +1,7 @@
<!doctype html>
<meta charset="utf-8" />
<meta name="author" title="Luke Warlow" href="mailto:luke@warlow.dev" />
+<meta name="timeout" content="long" />
<link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
@@ -9,210 +10,136 @@
<script src="/resources/testdriver-vendor.js"></script>
<script src="resources/invoker-utils.js"></script>
-<details id="invokee">
- Details Contents
-</details>
+<details id="invokee">Details Contents</details>
<button id="invokerbutton" invoketarget="invokee"></button>
<script>
- // auto
-
- promise_test(async function (t) {
- assert_false(invokee.matches("[open]"));
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.removeAttribute('open'));
- assert_true(invokee.matches("[open]"));
- }, "invoking closed details with auto action opens");
-
- promise_test(async function (t) {
- assert_false(invokee.matches("[open]"));
- invokee.addEventListener("invoke", (e) => e.preventDefault(), {
- once: true,
- });
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.removeAttribute('open'));
- assert_false(invokee.matches("[open]"));
- }, "invoking closed details with auto action and preventDefault does not open");
-
- promise_test(async function (t) {
- invokee.setAttribute('open', '');
- assert_true(invokee.matches("[open]"));
- await clickOn(invokerbutton);
- assert_false(invokee.matches("[open]"));
- }, "invoking open details with auto action closes");
-
- promise_test(async function (t) {
- invokee.setAttribute('open', '');
- t.add_cleanup(() => invokee.removeAttribute('open'));
- invokee.addEventListener("invoke", (e) => e.preventDefault(), {
- once: true,
- });
- assert_true(invokee.matches("[open]"));
- await clickOn(invokerbutton);
- assert_true(invokee.matches("[open]"));
- }, "invoking open details with auto action and preventDefault does not close");
-
- promise_test(async function (t) {
- t.add_cleanup(() => invokee.removeAttribute('open'));
- invokee.addEventListener("invoke", (e) => {
- invokee.setAttribute('open', '');
- }, {
- once: true,
- });
- assert_false(invokee.matches("[open]"));
- await clickOn(invokerbutton);
- assert_false(invokee.matches("[open]"));
- }, "invoking details with auto action where event listener opens leads to a closed details");
-
- promise_test(async function (t) {
- invokee.setAttribute('open', '');
- t.add_cleanup(() => invokee.removeAttribute('open'));
- invokee.addEventListener("invoke", (e) => {
- invokee.removeAttribute('open');
- }, {
- once: true,
- });
- assert_true(invokee.matches("[open]"));
- await clickOn(invokerbutton);
- assert_true(invokee.matches("[open]"));
- }, "invoking open details with auto action where event listener closes leads to an open details");
-
- // toggle
-
- promise_test(async function (t) {
- assert_false(invokee.matches("[open]"));
- invokerbutton.setAttribute("invokeaction", "toggle");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.removeAttribute('open'));
- assert_true(invokee.matches("[open]"));
- }, "invoking closed details with toggle action opens");
-
- promise_test(async function (t) {
- assert_false(invokee.matches("[open]"));
- invokerbutton.setAttribute("invokeaction", "tOgGlE");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.removeAttribute('open'));
- assert_true(invokee.matches("[open]"));
- }, "invoking closed details with toggle (case-insensitive) action opens");
-
- promise_test(async function (t) {
- assert_false(invokee.matches("[open]"));
- invokerbutton.setAttribute("invokeaction", "toggle");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- invokee.addEventListener("invoke", (e) => e.preventDefault(), {
+ function resetState() {
+ invokerbutton.removeAttribute("invokeaction");
+ invokee.removeAttribute("open");
+ }
+
+ // Open actions
+ [
+ null,
+ "",
+ "toggle",
+ "open",
+ /* test case sensitivity */
+ "tOgGlE",
+ "oPeN",
+ ].forEach((action) => {
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ if (action !== null) invokerbutton.invokeAction = action;
+ assert_false(invokee.matches("[open]"));
+ await clickOn(invokerbutton);
+ assert_true(invokee.matches("[open]"));
+ },
+ `invoking (as ${
+ action === null ? "auto" : action || "explicit empty"
+ }) closed details opens`,
+ );
+
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ if (action !== null) invokerbutton.invokeAction = action;
+ assert_false(invokee.matches("[open]"));
+ invokee.addEventListener("invoke", (e) => e.preventDefault(), {
+ once: true,
+ });
+ await clickOn(invokerbutton);
+ t.add_cleanup(() => invokee.removeAttribute("open"));
+ assert_false(invokee.matches("[open]"));
+ },
+ `invoking (as ${
+ action === null ? "auto" : action || "explicit empty"
+ }) closed details with preventDefault does not open`,
+ );
+ });
+
+ // Close actions
+ [
+ null,
+ "",
+ "toggle",
+ "close",
+ /* test case sensitivity */
+ "tOgGlE",
+ "cLoSe",
+ ].forEach((action) => {
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ if (action !== null) invokerbutton.invokeAction = action;
+ invokee.setAttribute("open", "");
+ assert_true(invokee.matches("[open]"));
+ await clickOn(invokerbutton);
+ assert_false(invokee.matches("[open]"));
+ },
+ `invoking (as ${
+ action === null ? "auto" : action || "explicit empty"
+ }) open details closes`,
+ );
+
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ if (action !== null) invokerbutton.invokeAction = action;
+ invokee.setAttribute("open", "");
+ invokerbutton.setAttribute("invokeaction", "toggle");
+ invokee.addEventListener("invoke", (e) => e.preventDefault(), {
+ once: true,
+ });
+ assert_true(invokee.matches("[open]"));
+ await clickOn(invokerbutton);
+ assert_true(invokee.matches("[open]"));
+ },
+ `invoking (as ${
+ action === null ? "auto" : action || "explicit empty"
+ }) open details with prevent default closes`,
+ );
+ });
+
+ // toggle specific
+
+ promise_test(async function (t) {
+ t.add_cleanup(resetState);
+ invokerbutton.invokeAction = "toggle";
+ invokee.addEventListener(
+ "invoke",
+ (e) => {
+ invokee.setAttribute("open", "");
+ },
+ {
once: true,
- });
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.removeAttribute('open'));
+ },
+ );
assert_false(invokee.matches("[open]"));
- }, "invoking closed details with toggle action and preventDefault does not open");
-
- promise_test(async function (t) {
- invokee.setAttribute('open', '');
- invokerbutton.setAttribute("invokeaction", "toggle");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- assert_true(invokee.matches("[open]"));
await clickOn(invokerbutton);
assert_false(invokee.matches("[open]"));
- }, "invoking open details with toggle action closes");
+ }, "invoking (as toggle) closed details where event listener opens leads to a closed details");
- promise_test(async function (t) {
- invokee.setAttribute('open', '');
- t.add_cleanup(() => invokee.removeAttribute('open'));
- invokerbutton.setAttribute("invokeaction", "toggle");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- invokee.addEventListener("invoke", (e) => e.preventDefault(), {
- once: true,
- });
- assert_true(invokee.matches("[open]"));
- await clickOn(invokerbutton);
- assert_true(invokee.matches("[open]"));
- }, "invoking open details with toggle action and preventDefault does not close");
-
- // open
-
- promise_test(async function (t) {
- invokerbutton.setAttribute("invokeaction", "open");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- assert_false(invokee.matches("[open]"));
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.removeAttribute('open'));
- assert_true(invokee.matches("[open]"));
- }, "invoking closed details with open action opens");
-
- promise_test(async function (t) {
- invokerbutton.setAttribute("invokeaction", "oPeN");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- assert_false(invokee.matches("[open]"));
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.removeAttribute('open'));
- assert_true(invokee.matches("[open]"));
- }, "invoking closed details with open (case insensitive) action opens");
+ // open specific
promise_test(async function (t) {
- invokerbutton.setAttribute("invokeaction", "open");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- invokee.setAttribute('open', '');
+ t.add_cleanup(resetState);
+ invokerbutton.invokeAction = "open";
+ invokee.setAttribute("open", "");
assert_true(invokee.matches("[open]"));
await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.removeAttribute('open'));
assert_true(invokee.matches("[open]"));
}, "invoking open details with open action is noop");
- promise_test(async function (t) {
- invokerbutton.setAttribute("invokeaction", "open");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- assert_false(invokee.matches("[open]"));
- invokee.addEventListener("invoke", (e) => e.preventDefault(), {
- once: true,
- });
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.removeAttribute('open'));
- assert_false(invokee.matches("[open]"));
- }, "invoking closed popover with open action and preventDefault does not open");
-
// close
promise_test(async function (t) {
- invokerbutton.setAttribute("invokeaction", "close");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
+ t.add_cleanup(resetState);
+ invokerbutton.invokeAction = "close";
assert_false(invokee.matches("[open]"));
await clickOn(invokerbutton);
assert_false(invokee.matches("[open]"));
}, "invoking closed details with close action is noop");
-
- promise_test(async function (t) {
- invokerbutton.setAttribute("invokeaction", "close");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- invokee.setAttribute('open', '');
- assert_true(invokee.matches("[open]"));
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.removeAttribute('open'));
- assert_false(invokee.matches("[open]"));
- }, "invoking open details with close action closes");
-
- promise_test(async function (t) {
- invokerbutton.setAttribute("invokeaction", "cLoSe");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- invokee.setAttribute('open', '');
- assert_true(invokee.matches("[open]"));
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.removeAttribute('open'));
- assert_false(invokee.matches("[open]"));
- }, "invoking open details with close (case insensitive) action closes");
-
- promise_test(async function (t) {
- invokerbutton.setAttribute("invokeaction", "close");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- invokee.setAttribute('open', '');
- t.add_cleanup(() => invokee.removeAttribute('open'));
- assert_true(invokee.matches("[open]"));
- invokee.addEventListener("invoke", (e) => e.preventDefault(), {
- once: true,
- });
- await clickOn(invokerbutton);
- assert_true(invokee.matches("[open]"));
- }, "invoking open details with close action with preventDefault does not close");
</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-details-invalid-behavior.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-details-invalid-behavior.tentative.html
new file mode 100644
index 0000000000..d5e90af9c0
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-details-invalid-behavior.tentative.html
@@ -0,0 +1,49 @@
+<!doctype html>
+<meta charset="utf-8" />
+<meta name="author" title="Keith Cirkel" href="mailto:wpt@keithcirkel.co.uk" />
+<meta name="timeout" content="long" />
+<link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
+<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="resources/invoker-utils.js"></script>
+
+<details id="invokee">Details Contents</details>
+<button id="invokerbutton" invoketarget="invokee"></button>
+
+<script>
+ function resetState() {
+ invokerbutton.removeAttribute("invokeaction");
+ invokee.removeAttribute("open");
+ }
+
+ // invalid actions on details
+ [
+ "foo-bar",
+ "showpopover",
+ "showmodal",
+ "showpicker",
+ "hidepopover",
+ "hide",
+ "toggleopen",
+ ].forEach((action) => {
+ promise_test(async function (t) {
+ t.add_cleanup(resetState);
+ invokerbutton.invokeAction = action;
+ assert_false(invokee.matches("[open]"));
+ await clickOn(invokerbutton);
+ assert_false(invokee.matches("[open]"));
+ }, `invoking (as ${action}) on details does nothing`);
+
+ promise_test(async function (t) {
+ t.add_cleanup(resetState);
+ invokerbutton.invokeAction = action;
+ invokee.setAttribute("open", "");
+ assert_true(invokee.matches("[open]"));
+ await clickOn(invokerbutton);
+ assert_true(invokee.matches("[open]"));
+ }, `invoking (as ${action}) on open details does nothing`);
+ });
+</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-dialog-behavior.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-dialog-behavior.tentative.html
index 774d308703..9f73e092b0 100644
--- a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-dialog-behavior.tentative.html
+++ b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-dialog-behavior.tentative.html
@@ -295,67 +295,6 @@
assert_false(invokee.matches(":modal"), "invokee :modal");
}, "invoking (as close) already closed dialog is noop");
- // invalid
- [
- "foo",
- "foo-bar",
- "auto",
- "showpopover",
- "hidepopover",
- "togglepopover",
- "showpicker",
- ].forEach((action) => {
- promise_test(async function (t) {
- t.add_cleanup(resetState);
- invokerbutton.setAttribute("invokeaction", action);
- assert_false(invokee.open, "invokee.open");
- assert_false(invokee.matches(":modal"), "invokee :modal");
- await clickOn(invokerbutton);
- assert_false(invokee.open, "invokee.open");
- assert_false(invokee.matches(":modal"), "invokee :modal");
- }, `invoking (as ${action}) on dialog does nothing`);
-
- promise_test(async function (t) {
- t.add_cleanup(resetState);
- containedinvoker.setAttribute("invokeaction", action);
- invokee.show();
- assert_true(invokee.open, "invokee.open");
- assert_false(invokee.matches(":modal"), "invokee :modal");
- await clickOn(containedinvoker);
- assert_true(invokee.open, "invokee.open");
- assert_false(invokee.matches(":modal"), "invokee :modal");
- }, `invoking (as ${action}) on open dialog does nothing`);
-
- promise_test(async function (t) {
- t.add_cleanup(resetState);
- containedinvoker.setAttribute("invokeaction", action);
- invokee.showModal();
- assert_true(invokee.open, "invokee.open");
- assert_true(invokee.matches(":modal"), "invokee :modal");
- await clickOn(containedinvoker);
- assert_true(invokee.open, "invokee.open");
- assert_true(invokee.matches(":modal"), "invokee :modal");
- }, `invoking (as ${action}) on open modal dialog does nothing`);
-
- promise_test(async function (t) {
- t.add_cleanup(resetState);
- containedinvoker.setAttribute("invokeaction", action);
- invokee.showModal();
- assert_true(invokee.open, "invokee.open");
- assert_true(invokee.matches(":modal"), "invokee :modal");
- invokee.addEventListener(
- "invoke",
- (e) => {
- containedinvoker.setAttribute("invokeaction", "");
- },
- { once: true },
- );
- await clickOn(containedinvoker);
- assert_true(invokee.open, "invokee.open");
- assert_true(invokee.matches(":modal"), "invokee :modal");
- }, `invoking (as ${action}) on open modal while changing the attributer does nothing`);
- });
-
// Open Popovers using Dialog actions
["showmodal", "close", ""].forEach((action) => {
["manual", "auto"].forEach((popoverState) => {
diff --git a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-dialog-invalid-behavior.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-dialog-invalid-behavior.tentative.html
new file mode 100644
index 0000000000..af84c22594
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-dialog-invalid-behavior.tentative.html
@@ -0,0 +1,120 @@
+<!doctype html>
+<meta charset="utf-8" />
+<meta name="author" title="Keith Cirkel" href="mailto:wpt@keithcirkel.co.uk" />
+<meta name="timeout" content="long">
+<link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
+<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="resources/invoker-utils.js"></script>
+
+<dialog id="invokee">
+ <button id="containedinvoker" invoketarget="invokee"></button>
+</dialog>
+<button id="invokerbutton" invoketarget="invokee"></button>
+
+<script>
+ function resetState() {
+ invokee.close();
+ try { invokee.hidePopover(); } catch {}
+ invokee.removeAttribute("popover");
+ invokerbutton.removeAttribute("invokeaction");
+ containedinvoker.removeAttribute("invokeaction");
+ }
+
+ // invalid
+ [
+ "foo",
+ "foo-bar",
+ "auto",
+ "showpopover",
+ "hidepopover",
+ "togglepopover",
+ "showpicker",
+ ].forEach((action) => {
+ promise_test(async function (t) {
+ t.add_cleanup(resetState);
+ invokerbutton.setAttribute("invokeaction", action);
+ assert_false(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ await clickOn(invokerbutton);
+ assert_false(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ }, `invoking (as ${action}) on dialog does nothing`);
+
+ promise_test(async function (t) {
+ t.add_cleanup(resetState);
+ containedinvoker.setAttribute("invokeaction", action);
+ invokee.show();
+ assert_true(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ await clickOn(containedinvoker);
+ assert_true(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ }, `invoking (as ${action}) on open dialog does nothing`);
+
+ promise_test(async function (t) {
+ t.add_cleanup(resetState);
+ containedinvoker.setAttribute("invokeaction", action);
+ invokee.showModal();
+ assert_true(invokee.open, "invokee.open");
+ assert_true(invokee.matches(":modal"), "invokee :modal");
+ await clickOn(containedinvoker);
+ assert_true(invokee.open, "invokee.open");
+ assert_true(invokee.matches(":modal"), "invokee :modal");
+ }, `invoking (as ${action}) on open modal dialog does nothing`);
+
+ promise_test(async function (t) {
+ t.add_cleanup(resetState);
+ containedinvoker.setAttribute("invokeaction", action);
+ invokee.showModal();
+ assert_true(invokee.open, "invokee.open");
+ assert_true(invokee.matches(":modal"), "invokee :modal");
+ invokee.addEventListener(
+ "invoke",
+ (e) => {
+ containedinvoker.setAttribute("invokeaction", "");
+ },
+ { once: true },
+ );
+ await clickOn(containedinvoker);
+ assert_true(invokee.open, "invokee.open");
+ assert_true(invokee.matches(":modal"), "invokee :modal");
+ }, `invoking (as ${action}) on open modal while changing the attributer does nothing`);
+ });
+
+ // Open Popovers using Dialog actions
+ ["showmodal", "close", ""].forEach((action) => {
+ ["manual", "auto"].forEach((popoverState) => {
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ invokee.setAttribute("popover", popoverState);
+ invokee.showPopover();
+ containedinvoker.setAttribute("invokeaction", action);
+ assert_true(
+ invokee.matches(":popover-open"),
+ "invokee :popover-open",
+ );
+ assert_false(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ invokee.addEventListener("invoke", (e) => e.preventDefault(), {
+ once: true,
+ });
+ await clickOn(containedinvoker);
+ assert_true(
+ invokee.matches(":popover-open"),
+ "invokee :popover-open",
+ );
+ assert_false(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ },
+ `invoking (as ${
+ action || "explicit empty"
+ }) dialog as open popover=${popoverState} is noop`,
+ );
+ });
+ });
+</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-popover-behavior.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-popover-behavior.tentative.html
index 2bddfa7621..f414559e55 100644
--- a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-popover-behavior.tentative.html
+++ b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-popover-behavior.tentative.html
@@ -1,6 +1,7 @@
<!doctype html>
<meta charset="utf-8" />
-<meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" />
+<meta name="author" title="Keith Cirkel" href="mailto:wpt@keithcirkel.co.uk" />
+<meta name="timeout" content="long" />
<link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
@@ -19,215 +20,138 @@
promise_test(async function (t) {
assert_false(invokee.matches(":popover-open"));
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.hidePopover());
- assert_true(invokee.matches(":popover-open"));
- }, "invoking (as auto) closed popover opens");
-
- promise_test(async function (t) {
- assert_false(invokee.matches(":popover-open"));
- invokee.addEventListener("invoke", (e) => e.preventDefault(), {
+ invokee.addEventListener("invoke", (e) => { invokerbutton.setAttribute('invokeaction', 'hidepopover'); }, {
once: true,
});
await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.hidePopover());
- assert_false(invokee.matches(":popover-open"));
- }, "invoking (as auto) closed popover with preventDefault does not open");
-
- promise_test(async function (t) {
- invokee.showPopover();
- assert_true(invokee.matches(":popover-open"));
- await clickOn(invokerbutton);
- assert_false(invokee.matches(":popover-open"));
- }, "invoking (as auto) open popover closes");
-
- promise_test(async function (t) {
- invokee.showPopover();
- assert_true(invokee.matches(":popover-open"));
- await clickOn(containedinvoker);
- assert_false(invokee.matches(":popover-open"));
- }, "invoking (as auto) from within open popover closes");
-
- promise_test(async function (t) {
- invokee.showPopover();
- t.add_cleanup(() => invokee.hidePopover());
- invokee.addEventListener("invoke", (e) => e.preventDefault(), {
- once: true,
+ t.add_cleanup(() => {
+ invokee.hidePopover();
+ invokerbutton.removeAttribute("invokeaction");
});
assert_true(invokee.matches(":popover-open"));
- await clickOn(containedinvoker);
- assert_true(invokee.matches(":popover-open"));
- }, "invoking (as auto) open popover with preventDefault does not close");
-
- // togglepopover
-
- promise_test(async function (t) {
- assert_false(invokee.matches(":popover-open"));
- invokerbutton.setAttribute("invokeaction", "togglepopover");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.hidePopover());
- assert_true(invokee.matches(":popover-open"));
- }, "invoking (as togglepopover) closed popover opens");
-
- promise_test(async function (t) {
- assert_false(invokee.matches(":popover-open"));
- invokerbutton.setAttribute("invokeaction", "tOgGlEpOpOvEr");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.hidePopover());
- assert_true(invokee.matches(":popover-open"));
- }, "invoking (as togglepopover - case insensitive) closed popover opens");
-
- promise_test(async function (t) {
- assert_false(invokee.matches(":popover-open"));
- invokerbutton.setAttribute("invokeaction", "togglepopover");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- invokee.addEventListener("invoke", (e) => e.preventDefault(), {
- once: true,
- });
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.hidePopover());
- assert_false(invokee.matches(":popover-open"));
- }, "invoking (as togglepopover) closed popover with preventDefault does not open");
-
- promise_test(async function (t) {
- invokee.showPopover();
- containedinvoker.setAttribute("invokeaction", "togglepopover");
- t.add_cleanup(() => containedinvoker.removeAttribute("invokeaction"));
- assert_true(invokee.matches(":popover-open"));
- await clickOn(invokerbutton);
- assert_false(invokee.matches(":popover-open"));
- }, "invoking (as togglepopover) open popover closes");
-
- promise_test(async function (t) {
- invokee.showPopover();
- containedinvoker.setAttribute("invokeaction", "togglepopover");
- t.add_cleanup(() => containedinvoker.removeAttribute("invokeaction"));
- assert_true(invokee.matches(":popover-open"));
- await clickOn(containedinvoker);
- assert_false(invokee.matches(":popover-open"));
- }, "invoking (as togglepopover) from within open popover closes");
-
- promise_test(async function (t) {
- invokee.showPopover();
- t.add_cleanup(() => invokee.hidePopover());
- containedinvoker.setAttribute("invokeaction", "togglepopover");
- t.add_cleanup(() => containedinvoker.removeAttribute("invokeaction"));
- invokee.addEventListener("invoke", (e) => e.preventDefault(), {
- once: true,
- });
- assert_true(invokee.matches(":popover-open"));
- await clickOn(containedinvoker);
- assert_true(invokee.matches(":popover-open"));
- }, "invoking (as togglepopover) open popover with preventDefault does not close");
-
- // showpopover
-
- promise_test(async function (t) {
+ }, "changing invokeaction attribute inside invokeevent doesn't impact the invocation");
+
+ function resetState() {
+ invokerbutton.removeAttribute("invokeaction");
+ containedinvoker.removeAttribute("invokeaction");
+ try {
+ invokee.hidePopover();
+ } catch {}
+ invokee.setAttribute("popover", "");
+ }
+
+ // Open actions
+ [
+ null,
+ "",
+ "togglepopover",
+ "showpopover",
+ /* test case sensitivity */
+ "tOgGlEpOpOvEr",
+ "sHoWpOpOvEr",
+ ].forEach((action) => {
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ if (action !== null) invokerbutton.invokeAction = action;
+ assert_false(invokee.matches(":popover-open"));
+ await clickOn(invokerbutton);
+ assert_true(invokee.matches(":popover-open"));
+ },
+ `invoking (as ${
+ action === null ? "auto" : action || "explicit empty"
+ }) closed popover opens`,
+ );
+
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ if (action !== null) invokerbutton.invokeAction = action;
+ assert_false(invokee.matches(":popover-open"));
+ invokee.addEventListener("invoke", (e) => e.preventDefault(), {
+ once: true,
+ });
+ await clickOn(invokerbutton);
+ assert_false(invokee.matches(":popover-open"));
+ },
+ `invoking (as ${
+ action === null ? "auto" : action || "explicit empty"
+ }) closed popover with preventDefault does not open`,
+ );
+ });
+
+ // Close actions
+ [
+ null,
+ "",
+ "togglepopover",
+ "hidepopover",
+ /* test case sensitivity */
+ "tOgGlEpOpOvEr",
+ "hIdEpOpOvEr",
+ ].forEach((action) => {
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ if (action !== null) invokerbutton.invokeAction = action;
+ invokee.showPopover();
+ assert_true(invokee.matches(":popover-open"));
+ await clickOn(invokerbutton);
+ assert_false(invokee.matches(":popover-open"));
+ },
+ `invoking (as ${
+ action === null ? "auto" : action || "explicit empty"
+ }) open popover closes`,
+ );
+
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ if (action !== null) containedinvoker.invokeAction = action;
+ invokee.showPopover();
+ assert_true(invokee.matches(":popover-open"));
+ await clickOn(containedinvoker);
+ assert_false(invokee.matches(":popover-open"));
+ },
+ `invoking (as ${
+ action === null ? "auto" : action || "explicit empty"
+ }) from within open popover closes`,
+ );
+
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ if (action !== null) invcontainedinvokervokeaction = action;
+ invokee.showPopover();
+ invokee.addEventListener("invoke", (e) => e.preventDefault(), {
+ once: true,
+ });
+ assert_true(invokee.matches(":popover-open"));
+ await clickOn(containedinvoker);
+ assert_true(invokee.matches(":popover-open"));
+ },
+ `invoking (as ${
+ action === null ? "auto" : action || "explicit empty"
+ }) open popover with preventDefault does not close`,
+ );
+ });
+
+ // showpopover specific
+ promise_test(async function (t) {
+ t.add_cleanup(resetState);
invokerbutton.setAttribute("invokeaction", "showpopover");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- assert_false(invokee.matches(":popover-open"));
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.hidePopover());
- assert_true(invokee.matches(":popover-open"));
- }, "invoking (as showpopover) closed popover opens");
-
- promise_test(async function (t) {
- invokerbutton.setAttribute("invokeaction", "sHoWpOpOvEr");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- assert_false(invokee.matches(":popover-open"));
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.hidePopover());
- assert_true(invokee.matches(":popover-open"));
- }, "invoking (as showpopover - case insensitive) closed popover opens");
-
- promise_test(async function (t) {
- invokerbutton.setAttribute("invokeaction", "showpopover");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
invokee.showPopover();
assert_true(invokee.matches(":popover-open"));
await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.hidePopover());
assert_true(invokee.matches(":popover-open"));
}, "invoking (as showpopover) open popover is noop");
+ // hidepopover specific
promise_test(async function (t) {
- invokerbutton.setAttribute("invokeaction", "showpopover");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- assert_false(invokee.matches(":popover-open"));
- invokee.addEventListener("invoke", (e) => e.preventDefault(), {
- once: true,
- });
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.hidePopover());
- assert_false(invokee.matches(":popover-open"));
- }, "invoking (as showpopover) closed popover with preventDefault does not open");
-
- // hidepopover
-
- promise_test(async function (t) {
+ t.add_cleanup(resetState);
invokerbutton.setAttribute("invokeaction", "hidepopover");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
assert_false(invokee.matches(":popover-open"));
await clickOn(invokerbutton);
assert_false(invokee.matches(":popover-open"));
}, "invoking (as hidepopover) closed popover is noop");
-
- promise_test(async function (t) {
- containedinvoker.setAttribute("invokeaction", "hidepopover");
- t.add_cleanup(() => containedinvoker.removeAttribute("invokeaction"));
- invokee.showPopover();
- assert_true(invokee.matches(":popover-open"));
- await clickOn(containedinvoker);
- t.add_cleanup(() => invokee.hidePopover());
- assert_false(invokee.matches(":popover-open"));
- }, "invoking (as hidepopover) open popover closes");
-
- promise_test(async function (t) {
- containedinvoker.setAttribute("invokeaction", "hIdEpOpOvEr");
- t.add_cleanup(() => containedinvoker.removeAttribute("invokeaction"));
- invokee.showPopover();
- assert_true(invokee.matches(":popover-open"));
- await clickOn(containedinvoker);
- t.add_cleanup(() => invokee.hidePopover());
- assert_false(invokee.matches(":popover-open"));
- }, "invoking (as hidepopover - case insensitive) open popover closes");
-
- promise_test(async function (t) {
- containedinvoker.setAttribute("invokeaction", "hidepopover");
- t.add_cleanup(() => containedinvoker.removeAttribute("invokeaction"));
- invokee.showPopover();
- t.add_cleanup(() => invokee.hidePopover());
- assert_true(invokee.matches(":popover-open"));
- invokee.addEventListener("invoke", (e) => e.preventDefault(), {
- once: true,
- });
- await clickOn(containedinvoker);
- assert_true(invokee.matches(":popover-open"));
- }, "invoking (as hidepopover) open popover with preventDefault does not close");
-
- // invalid
-
- ["foo", "togglemodal", "showpicker", "toggle", "open", "close"].forEach(action => {
- promise_test(async function (t) {
- invokerbutton.setAttribute("invokeaction", action);
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- assert_false(invokee.matches(":popover-open"));
- await clickOn(invokerbutton);
- assert_false(invokee.matches(":popover-open"));
- }, `invoking (as ${action}) on popover does nothing`);
-
- promise_test(async function (t) {
- invokerbutton.setAttribute("invokeaction", action);
- t.add_cleanup(() => {
- invokerbutton.removeAttribute("invokeaction")
- invokee.hidePopover();
- });
- invokee.showPopover()
- assert_true(invokee.matches(":popover-open"));
- await clickOn(invokerbutton);
- assert_true(invokee.matches(":popover-open"));
- }, `invoking (as ${action}) on open popover does nothing`);
- })
</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-popover-invalid-behavior.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-popover-invalid-behavior.tentative.html
new file mode 100644
index 0000000000..755f3a6777
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-popover-invalid-behavior.tentative.html
@@ -0,0 +1,47 @@
+<!doctype html>
+<meta charset="utf-8" />
+<meta name="author" title="Keith Cirkel" href="mailto:wpt@keithcirkel.co.uk" />
+<meta name="timeout" content="long" />
+<link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
+<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="resources/invoker-utils.js"></script>
+
+<div id="invokee" popover>
+ <button id="containedinvoker" invoketarget="invokee"></button>
+</div>
+<button id="invokerbutton" invoketarget="invokee"></button>
+
+<script>
+ function resetState() {
+ invokerbutton.removeAttribute("invokeaction");
+ containedinvoker.removeAttribute("invokeaction");
+ try {
+ invokee.hidePopover();
+ } catch {}
+ invokee.setAttribute("popover", "");
+ }
+
+ // invalid actions on showpopover
+ ["foo-bar", "showmodal", "showpicker", "open", "close"].forEach((action) => {
+ promise_test(async function (t) {
+ t.add_cleanup(resetState);
+ invokerbutton.invokeAction = action;
+ assert_false(invokee.matches(":popover-open"));
+ await clickOn(invokerbutton);
+ assert_false(invokee.matches(":popover-open"));
+ }, `invoking (as ${action}) on popover does nothing`);
+
+ promise_test(async function (t) {
+ t.add_cleanup(resetState);
+ invokerbutton.invokeAction = action;
+ invokee.showPopover();
+ assert_true(invokee.matches(":popover-open"));
+ await clickOn(invokerbutton);
+ assert_true(invokee.matches(":popover-open"));
+ }, `invoking (as ${action}) on open popover does nothing`);
+ });
+</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-video-behavior.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-video-behavior.tentative.html
index 5bbcd83e72..d15d6f9584 100644
--- a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-video-behavior.tentative.html
+++ b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-video-behavior.tentative.html
@@ -1,6 +1,7 @@
<!doctype html>
<meta charset="utf-8" />
<meta name="author" title="Luke Warlow" href="mailto:luke@warlow.dev" />
+<meta name="timeout" content="long" />
<link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
@@ -25,7 +26,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -43,7 +44,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "playpause");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_false(invokee.paused);
@@ -62,7 +63,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "playpause");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -75,12 +76,12 @@
invokee.currentTime = 0;
invokee.muted = false;
});
- await test_driver.bless('play video');
+ await test_driver.bless("play video");
invokee.play();
assert_false(invokee.paused);
invokerbutton.setAttribute("invokeaction", "playpause");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -98,7 +99,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "play");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_false(invokee.paused);
@@ -112,12 +113,12 @@
invokee.muted = false;
});
invokee.addEventListener("invoke", (e) => e.preventDefault(), {
- once: true,
+ once: true,
});
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "play");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -130,12 +131,12 @@
invokee.currentTime = 0;
invokee.muted = false;
});
- await test_driver.bless('play video');
+ await test_driver.bless("play video");
invokee.play();
assert_false(invokee.paused);
invokerbutton.setAttribute("invokeaction", "play");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_false(invokee.paused);
@@ -153,7 +154,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "pause");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -167,12 +168,12 @@
invokee.muted = false;
});
invokee.addEventListener("invoke", (e) => e.preventDefault(), {
- once: true,
+ once: true,
});
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "pause");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -185,12 +186,12 @@
invokee.currentTime = 0;
invokee.muted = false;
});
- await test_driver.bless('play video');
+ await test_driver.bless("play video");
invokee.play();
assert_false(invokee.paused);
invokerbutton.setAttribute("invokeaction", "pause");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -208,7 +209,7 @@
assert_false(invokee.muted);
invokerbutton.setAttribute("invokeaction", "toggleMuted");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.muted);
@@ -222,12 +223,12 @@
invokee.muted = false;
});
invokee.addEventListener("invoke", (e) => e.preventDefault(), {
- once: true,
+ once: true,
});
assert_false(invokee.muted);
invokerbutton.setAttribute("invokeaction", "toggleMuted");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_false(invokee.muted);
@@ -244,10 +245,9 @@
assert_true(invokee.muted);
invokerbutton.setAttribute("invokeaction", "toggleMuted");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_false(invokee.muted);
}, "invoking muted video with toggleMuted action unmutes it");
-
</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/resources/invoker-utils.js b/testing/web-platform/tests/html/semantics/invokers/resources/invoker-utils.js
index 8420f24b6f..4261f9c0d3 100644
--- a/testing/web-platform/tests/html/semantics/invokers/resources/invoker-utils.js
+++ b/testing/web-platform/tests/html/semantics/invokers/resources/invoker-utils.js
@@ -14,3 +14,14 @@ async function clickOn(element) {
.send();
await waitForRender();
}
+async function hoverOver(element) {
+ await waitForRender();
+ let rect = element.getBoundingClientRect();
+ let actions = new test_driver.Actions();
+ // FIXME: Switch to pointerMove(0, 0, {origin: element}) once
+ // https://github.com/web-platform-tests/wpt/issues/41257 is fixed.
+ await actions
+ .pointerMove(Math.round(rect.x + rect.width / 2), Math.round(rect.y + rect.height / 2), {})
+ .send();
+ await waitForRender();
+}
diff --git a/testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties-reference-expected.html b/testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties-reference-expected.html
new file mode 100644
index 0000000000..c62ff5b24d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties-reference-expected.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<body>
+ <div>
+ The permission element should have some limits for specific properties:
+ <ul>
+ <li>font-weight is adjusted to be at least 200.</li>
+ <li>font-style should only have "normal" or "italic" values.</li>
+ <li>word-spacing should be at most 0.5 of the font size, and non-negative.</li>
+ <li>letter-spacing should be between -0.05 and 0.2 of the font size.</li>
+ </ul>
+ </div>
+
+<style>
+ #id1 {
+ font-weight: 200;
+ font-style: normal;
+ word-spacing: 0.5em;
+ font-size: 100px;
+ height: auto;
+ width: auto;
+ letter-spacing: 20px;
+ }
+ #id2 {
+ word-spacing: 0em;
+ height: auto;
+ width: auto;
+ font-size: 10px;
+ letter-spacing: -0.5px;
+ }
+</style>
+
+<permission id="id1" type="geolocation">
+<permission id="id2" type="camera">
+</body> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties-reference.tentative.html b/testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties-reference.tentative.html
new file mode 100644
index 0000000000..b8337ab87d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties-reference.tentative.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<link rel="match" href="bounded-css-properties-reference-expected.html">
+<link rel="help" href="https://github.com/WICG/PEPC/blob/main/explainer.md#locking-the-pepc-style">
+<body>
+ <div>
+ The permission element should have some limits for specific properties:
+ <ul>
+ <li>font-weight is adjusted to be at least 200.</li>
+ <li>font-style should only have "normal" or "italic" values.</li>
+ <li>word-spacing should be at most 0.5 of the font size, and non-negative.</li>
+ <li>letter-spacing should be between -0.05 and 0.2 of the font size.</li>
+ </ul>
+ </div>
+
+<style>
+ #id1 {
+ font-weight: 100;
+ font-style: oblique 30deg;
+ word-spacing: 1em;
+ font-size: 100px;
+ height: auto;
+ width: auto;
+ letter-spacing: 25px;
+ }
+ #id2 {
+ word-spacing: -1000px;
+ height: auto;
+ width: auto;
+ font-size: 10px;
+ letter-spacing: -1px;
+ }
+</style>
+
+<permission id="id1" type="geolocation">
+<permission id="id2" type="camera">
+</body> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties.html b/testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties.html
deleted file mode 100644
index 98c3d70e98..0000000000
--- a/testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<body>
-<!--The permission element should have some limits for specific properties:
- * font-weight is adjusted to be at least 200.
- * font-style should only have "normal" or "italic" values.
--->
-<style>
- #id1 {
- font-weight: 100;
- font-style: oblique 30deg;
- }
- #id2 {
- font-weight: 300;
- font-style: italic;
- }
-</style>
-
-
-<permission id="id1" type="geolocation">
-<permission id="id2" type="camera">
-
-<script>
- test(function(){
- var el_outside_bounds = document.getElementById("id1");
- assert_equals(getComputedStyle(el_outside_bounds).fontWeight, "200", "font-weight");
- assert_equals(getComputedStyle(el_outside_bounds).fontStyle, "normal", "font-style");
- }, "Properties with out-of-bounds values should be corrected");
-
- test(function(){
- var el_inside_bounds = document.getElementById("id2");
- assert_equals(getComputedStyle(el_inside_bounds).fontWeight, "300", "font-weight");
- assert_equals(getComputedStyle(el_inside_bounds).fontStyle, "italic", "font-style");
- }, "Properties with values in bounds should not be modified");
-</script>
-</body> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties.tentative.html b/testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties.tentative.html
new file mode 100644
index 0000000000..c0f0fe3454
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/permission-element/bounded-css-properties.tentative.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<link rel="help" href="https://github.com/WICG/PEPC/blob/main/explainer.md#locking-the-pepc-style">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<!--The permission element should have some limits for specific properties:
+ * font-weight is adjusted to be at least 200.
+ * font-style should only have "normal" or "italic" values.
+ * word-spacing should be at most 0.5 of the font size, and non-negative.
+ * letter-spacing should be between -0.05 and 0.2 of the font size.
+-->
+<style>
+ #id-over-bounds {
+ font-weight: 100;
+ font-style: oblique 30deg;
+ word-spacing: 1em;
+ font-size: 100px;
+ letter-spacing: 21px;
+ }
+ #id-under-bounds {
+ word-spacing: -1px;
+ font-size: 100px;
+ letter-spacing: -6px;
+ }
+ #id-within-bounds {
+ font-weight: 300;
+ font-style: italic;
+ word-spacing: 0.4em;
+ font-size: 100px;
+ letter-spacing: 15px;
+ }
+</style>
+
+
+<permission id="id-over-bounds" type="geolocation">
+<permission id="id-under-bounds" type="camera">
+<permission id="id-within-bounds" type="microphone">
+
+<script>
+ test(function(){
+ var el = document.getElementById("id-over-bounds");
+ assert_equals(getComputedStyle(el).fontWeight, "200", "font-weight");
+ assert_equals(getComputedStyle(el).fontStyle, "normal", "font-style");
+ assert_equals(getComputedStyle(el).wordSpacing, "50px", "word-spacing");
+ assert_equals(getComputedStyle(el).letterSpacing, "20px", "letter-spacing");
+
+ el = document.getElementById("id-under-bounds");
+ assert_equals(getComputedStyle(el).wordSpacing, "0px", "word-spacing, negative");
+ assert_equals(getComputedStyle(el).letterSpacing, "-5px", "letter-spacing, negative");
+ }, "Properties with out-of-bounds values should be corrected");
+
+ test(function(){
+ var el = document.getElementById("id-within-bounds");
+ assert_equals(getComputedStyle(el).fontWeight, "300", "font-weight");
+ assert_equals(getComputedStyle(el).fontStyle, "italic", "font-style");
+ assert_equals(getComputedStyle(el).wordSpacing, "40px", "word-spacing");
+ assert_equals(getComputedStyle(el).letterSpacing, "15px", "letter-spacing");
+
+ el.style.letterSpacing = "-4px";
+ assert_equals(getComputedStyle(el).letterSpacing, "-4px", "letter-spacing, negative");
+ }, "Properties with values in bounds should not be modified");
+</script>
+</body> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/permission-element/display-css-property-reference-expected.html b/testing/web-platform/tests/html/semantics/permission-element/display-css-property-reference-expected.html
new file mode 100644
index 0000000000..6a04c94c03
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/permission-element/display-css-property-reference-expected.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<body>
+ <div>
+ The permission element should either be display 'none' or 'inline-block'
+ </div>
+
+<style>
+ #id1 {
+ display: inline-block;
+ }
+</style>
+
+<permission id="id1" type="geolocation">
+<span>After element</span>
+</body> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/permission-element/display-css-property-reference.tentative.html b/testing/web-platform/tests/html/semantics/permission-element/display-css-property-reference.tentative.html
new file mode 100644
index 0000000000..973a76d723
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/permission-element/display-css-property-reference.tentative.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<link rel="match" href="display-css-property-reference-expected.html">
+<link rel="help" href="https://github.com/WICG/PEPC/blob/main/explainer.md#locking-the-pepc-style">
+<body>
+ <div>
+ The permission element should either be display 'none' or 'inline-block'
+ </div>
+
+<style>
+ #id1 {
+ display: flex;
+ }
+ #id2 {
+ display: none;
+ }
+</style>
+
+<permission id="id1" type="geolocation">
+<permission id="id2" type="camera">
+<span>After element</span>
+</body> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/permission-element/display-css-property.tentative.html b/testing/web-platform/tests/html/semantics/permission-element/display-css-property.tentative.html
new file mode 100644
index 0000000000..7aa22ef4a2
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/permission-element/display-css-property.tentative.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<link rel="help" href="https://github.com/WICG/PEPC/blob/main/explainer.md#locking-the-pepc-style">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<!--
+ 'display' should either be 'none' or 'inline-block'
+-->
+<style>
+ #id1 {
+ display: inline-block;
+ }
+ #id2 {
+ display: block;
+ }
+ #id3 {
+ display: none;
+ }
+</style>
+
+
+<permission id="id1" type="geolocation">
+<permission id="id2" type="camera">
+<permission id="id3" type="microphone">
+
+<script>
+ test(function(){
+ assert_equals(getComputedStyle(document.getElementById("id1")).display, "inline-block", "'inline-block' should be kept");
+ assert_equals(getComputedStyle(document.getElementById("id2")).display, "inline-block", "'block' should be changed to 'inline-block'");
+ assert_equals(getComputedStyle(document.getElementById("id3")).display, "none", "'none' should be kept");
+ }, "'display' should be either 'inline-block' or 'none'");
+</script>
+</body> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/permission-element/invalid-css-properties.html b/testing/web-platform/tests/html/semantics/permission-element/invalid-css-properties.tentative.html
index c7186563f0..334280c83b 100644
--- a/testing/web-platform/tests/html/semantics/permission-element/invalid-css-properties.html
+++ b/testing/web-platform/tests/html/semantics/permission-element/invalid-css-properties.tentative.html
@@ -1,5 +1,6 @@
<!DOCTYPE html>
<meta charset=utf-8>
+<link rel="help" href="https://github.com/WICG/PEPC/blob/main/explainer.md#locking-the-pepc-style">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
diff --git a/testing/web-platform/tests/html/semantics/permission-element/negative-offset-and-margin.html b/testing/web-platform/tests/html/semantics/permission-element/negative-offset-and-margin.tentative.html
index 97290bb4df..de622bbb3e 100644
--- a/testing/web-platform/tests/html/semantics/permission-element/negative-offset-and-margin.html
+++ b/testing/web-platform/tests/html/semantics/permission-element/negative-offset-and-margin.tentative.html
@@ -1,5 +1,6 @@
<!DOCTYPE html>
<meta charset=utf-8>
+<link rel="help" href="https://github.com/WICG/PEPC/blob/main/explainer.md#locking-the-pepc-style">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
diff --git a/testing/web-platform/tests/html/semantics/permission-element/no-end-tag-no-contents.html b/testing/web-platform/tests/html/semantics/permission-element/no-end-tag-no-contents.tentative.html
index 5fcce1421b..bea3d7102c 100644
--- a/testing/web-platform/tests/html/semantics/permission-element/no-end-tag-no-contents.html
+++ b/testing/web-platform/tests/html/semantics/permission-element/no-end-tag-no-contents.tentative.html
@@ -1,5 +1,6 @@
<!DOCTYPE html>
<meta charset=utf-8>
+<link rel="help" href="https://github.com/WICG/PEPC/blob/main/explainer.md#locking-the-pepc-style">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
diff --git a/testing/web-platform/tests/html/semantics/popovers/button-type-reset-popovertarget.tentative.html b/testing/web-platform/tests/html/semantics/popovers/button-type-reset-popovertarget.tentative.html
new file mode 100644
index 0000000000..975eab0d66
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/popovers/button-type-reset-popovertarget.tentative.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://issues.chromium.org/issues/329118508">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id=mypopover popover=auto>popover</div>
+
+<iframe name=foo></iframe>
+<form target=foo action="about:blank">
+ <button id=reset-in-form type=reset popovertarget=mypopover>reset</button>
+ <button id=submit-in-form type=submit popovertarget=mypopover>submit</button>
+ <button id=button-in-form type=button popovertarget=mypopover>type=button</button>
+</form>
+
+<button id=reset-outside-form type=reset popovertarget=mypopover>reset</button>
+<button id=submit-outside-form type=submit popovertarget=mypopover>submit</button>
+<button id=button-outside-form type=button popovertarget=mypopover>type=button</button>
+
+<script>
+test(() => {
+ const testButton = (id, expectedToToggle) => {
+ document.getElementById(id).click();
+ if (expectedToToggle) {
+ assert_true(mypopover.matches(':popover-open'),
+ `${id}: button should open the popover.`);
+ } else {
+ assert_false(mypopover.matches(':popover-open'),
+ `${id}: button should not open the popover.`);
+ }
+ if (mypopover.matches(':popover-open')) {
+ mypopover.hidePopover();
+ }
+ };
+
+ testButton('reset-in-form', false);
+ testButton('submit-in-form', false);
+ testButton('button-in-form', true);
+ testButton('reset-outside-form', true);
+ testButton('submit-outside-form', true);
+ testButton('button-outside-form', true);
+}, 'Button type=reset and type=submit should not run popover algorithms when in a form.');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/popovers/popover-anchor-display.tentative.html b/testing/web-platform/tests/html/semantics/popovers/popover-anchor-display.tentative.html
index d50dd6c857..bddc44006d 100644
--- a/testing/web-platform/tests/html/semantics/popovers/popover-anchor-display.tentative.html
+++ b/testing/web-platform/tests/html/semantics/popovers/popover-anchor-display.tentative.html
@@ -94,7 +94,7 @@ showDefaultopenPopoversOnLoad();
top: anchor(top);
}
#popover5 {
- anchor-default: --anchor1; /* shouldn't be used */
+ position-anchor: --anchor1; /* shouldn't be used */
left: anchor(implicit right);
top: anchor(implicit top);
}
@@ -102,7 +102,7 @@ showDefaultopenPopoversOnLoad();
anchor-name: --anchor6;
}
#popover6 {
- anchor-default: --anchor6;
+ position-anchor: --anchor6;
left: anchor(right); /* shouldn't use the implicit anchor */
top: anchor(top);
}
diff --git a/testing/web-platform/tests/html/semantics/popovers/popover-anchor-scroll-display.tentative.html b/testing/web-platform/tests/html/semantics/popovers/popover-anchor-scroll-display.tentative.html
index 7ed6cf1adf..2c6b0bafb9 100644
--- a/testing/web-platform/tests/html/semantics/popovers/popover-anchor-scroll-display.tentative.html
+++ b/testing/web-platform/tests/html/semantics/popovers/popover-anchor-scroll-display.tentative.html
@@ -56,7 +56,7 @@
anchor-name: --anchor2;
}
#popover2 {
- anchor-default: --anchor2;
+ position-anchor: --anchor2;
left: anchor(right);
top: anchor(top);
}
diff --git a/testing/web-platform/tests/html/semantics/popovers/popover-light-dismiss.html b/testing/web-platform/tests/html/semantics/popovers/popover-light-dismiss.html
index 916d52ef5e..45db242e91 100644
--- a/testing/web-platform/tests/html/semantics/popovers/popover-light-dismiss.html
+++ b/testing/web-platform/tests/html/semantics/popovers/popover-light-dismiss.html
@@ -11,6 +11,19 @@
<script src="/resources/testdriver-vendor.js"></script>
<script src="resources/popover-utils.js"></script>
+<style>
+ [popover] {
+ /* Position most popovers at the bottom-right, out of the way */
+ inset:auto;
+ bottom:0;
+ right:0;
+ }
+ [popover]::backdrop {
+ /* This should *not* affect anything: */
+ pointer-events: auto;
+ }
+</style>
+
<button id=b1t popovertarget='p1'>Popover 1</button>
<button id=b1s popovertarget='p1' popovertargetaction=show>Popover 1</button>
<span id=outside>Outside all popovers</span>
@@ -26,11 +39,6 @@
<style>
#p1 {top: 50px;}
#p2 {top: 120px;}
- [popover] {bottom:auto;}
- [popover]::backdrop {
- /* This should *not* affect anything: */
- pointer-events: auto;
- }
</style>
<script>
const popover1 = document.querySelector('#p1');
@@ -584,24 +592,50 @@ promise_test(async () => {
<div id=p29 popover>Popover 29</div>
<button id=b29 popovertarget=p29>Open popover 29</button>
-<iframe id=iframe29 width=100 height=100></iframe>
+<iframe id=iframe29 width=100 height=30></iframe>
<script>
promise_test(async () => {
let iframe_url = (new URL("/common/blank.html", location.href)).href;
iframe29.src = iframe_url;
iframe29.contentDocument.body.style.height = '100%';
- assert_false(p29.matches(':popover-open'));
+ assert_false(p29.matches(':popover-open'),'initially hidden');
p29.showPopover();
- assert_true(p29.matches(':popover-open'));
+ assert_true(p29.matches(':popover-open'),'showing');
let actions = new test_driver.Actions();
await actions.pointerMove(0,0,{origin: b29})
.pointerDown({button: actions.ButtonType.LEFT})
.send();
+ await waitForRender();
+ assert_true(p29.matches(':popover-open'),'showing after pointerdown');
actions = new test_driver.Actions();
await actions.pointerMove(0,0,{origin: iframe29.contentDocument.body})
.pointerUp({button: actions.ButtonType.LEFT})
.send();
- assert_true(p29.matches(':popover-open'));
+ await waitForRender();
+ assert_true(p29.matches(':popover-open'),'showing after pointerup');
},`Pointer down in one document and pointer up in another document shouldn't dismiss popover`);
</script>
+
+<div id=p30 popover>Popover 30</div>
+<button id=b30 popovertarget=p30>Open popover 30</button>
+<button id=b30b>Non-invoker</button>
+<script>
+promise_test(async () => {
+ assert_false(p30.matches(':popover-open'),'initially hidden');
+ p30.showPopover();
+ assert_true(p30.matches(':popover-open'),'showing');
+ let actions = new test_driver.Actions();
+ await actions.pointerMove(0,0,{origin: b30})
+ .pointerDown({button: actions.ButtonType.LEFT})
+ .send();
+ await waitForRender();
+ assert_true(p30.matches(':popover-open'),'showing after pointerdown');
+ actions = new test_driver.Actions();
+ await actions.pointerMove(0,0,{origin: b30b})
+ .pointerUp({button: actions.ButtonType.LEFT})
+ .send();
+ await waitForRender();
+ assert_true(p30.matches(':popover-open'),'showing after pointerup');
+},`Pointer down inside invoker and up outside that invoker shouldn't dismiss popover`);
+</script>
diff --git a/testing/web-platform/tests/html/semantics/popovers/popover-top-layer-nesting.tentative.html b/testing/web-platform/tests/html/semantics/popovers/popover-top-layer-nesting.html
index a0b3b60b72..a0b3b60b72 100644
--- a/testing/web-platform/tests/html/semantics/popovers/popover-top-layer-nesting.tentative.html
+++ b/testing/web-platform/tests/html/semantics/popovers/popover-top-layer-nesting.html
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/css-module/integrity.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/css-module/integrity.html
index 1dd0dad470..7ee6452bcc 100644
--- a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/css-module/integrity.html
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/css-module/integrity.html
@@ -12,7 +12,7 @@ window.matchesEvents = [];
window.mismatchesLog = [];
window.mismatchesEvents = [];
</script>
-<script type="module" src="resources/integrity-matches.js" integrity="sha384-xvbfmg9iJFHqmCoOS4VNMCwnFPPxEoIlW1Ojzl+fgEd+Wf8Pyez+SMWue+KNovjA" onload="window.matchesEvents.push('load');" onerror="window.matchesEvents.push('error')"></script>
+<script type="module" src="resources/integrity-matches.js" integrity="sha384-KtvB2Fgbhx2NAEizVeuGMa+QgvBzlBvVRxdpRnIECuGUvzzQsnVejyDL5J0fVP9M" onload="window.matchesEvents.push('load');" onerror="window.matchesEvents.push('error')"></script>
<script type="module" src="resources/integrity-mismatches.js" integrity="sha384-doesnotmatch" onload="window.mismatchesEvents.push('load');" onerror="window.mismatchesEvents.push('error')"></script>
<script type="module">
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/integrity.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/integrity.html
index 68a794b973..0aa92d9fdc 100644
--- a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/integrity.html
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/integrity.html
@@ -12,7 +12,7 @@ window.matchesEvents = [];
window.mismatchesLog = [];
window.mismatchesEvents = [];
</script>
-<script type="module" src="integrity-matches.js" integrity="sha384-VmQQfGzBiLKdyzw4FA4kL4ohu4tyujV68ddgW1aN/1v3cBZNNBn2gDFdVQxfL7+a" onload="window.matchesEvents.push('load');" onerror="window.matchesEvents.push('error')"></script>
+<script type="module" src="integrity-matches.js" integrity="sha384-kc1K2KFKQhnYE1AdnpmUUpFVnxz1GCgGbQ19e3zmXrZw23rgpwa9il4/pHp7NYWA" onload="window.matchesEvents.push('load');" onerror="window.matchesEvents.push('error')"></script>
<script type="module" src="integrity-mismatches.js" integrity="sha384-doesnotmatch" onload="window.mismatchesEvents.push('load');" onerror="window.mismatchesEvents.push('error')"></script>
<script type="module">