summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/css/css-toggle
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/web-platform/tests/css/css-toggle
parentInitial commit. (diff)
downloadfirefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz
firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--testing/web-platform/tests/css/css-toggle/animations/toggle-group-interpolation.tentative.html20
-rw-r--r--testing/web-platform/tests/css/css-toggle/animations/toggle-root-interpolation.tentative.html20
-rw-r--r--testing/web-platform/tests/css/css-toggle/animations/toggle-trigger-interpolation.tentative.html20
-rw-r--r--testing/web-platform/tests/css/css-toggle/idlharness.tentative.html32
-rw-r--r--testing/web-platform/tests/css/css-toggle/parsing/support/toggle-root-values.js107
-rw-r--r--testing/web-platform/tests/css/css-toggle/parsing/toggle-computed.tentative.html18
-rw-r--r--testing/web-platform/tests/css/css-toggle/parsing/toggle-group-computed.tentative.html24
-rw-r--r--testing/web-platform/tests/css/css-toggle/parsing/toggle-group-invalid.tentative.html26
-rw-r--r--testing/web-platform/tests/css/css-toggle/parsing/toggle-group-valid.tentative.html23
-rw-r--r--testing/web-platform/tests/css/css-toggle/parsing/toggle-invalid.tentative.html17
-rw-r--r--testing/web-platform/tests/css/css-toggle/parsing/toggle-root-computed.tentative.html18
-rw-r--r--testing/web-platform/tests/css/css-toggle/parsing/toggle-root-invalid.tentative.html17
-rw-r--r--testing/web-platform/tests/css/css-toggle/parsing/toggle-root-valid.tentative.html17
-rw-r--r--testing/web-platform/tests/css/css-toggle/parsing/toggle-trigger-computed.tentative.html46
-rw-r--r--testing/web-platform/tests/css/css-toggle/parsing/toggle-trigger-invalid.tentative.html31
-rw-r--r--testing/web-platform/tests/css/css-toggle/parsing/toggle-trigger-valid.tentative.html45
-rw-r--r--testing/web-platform/tests/css/css-toggle/parsing/toggle-valid.tentative.html17
-rw-r--r--testing/web-platform/tests/css/css-toggle/parsing/toggle-visibility-computed.tentative.html19
-rw-r--r--testing/web-platform/tests/css/css-toggle/parsing/toggle-visibility-invalid.tentative.html21
-rw-r--r--testing/web-platform/tests/css/css-toggle/parsing/toggle-visibility-valid.tentative.html18
-rw-r--r--testing/web-platform/tests/css/css-toggle/support/toggle-helpers.js16
-rw-r--r--testing/web-platform/tests/css/css-toggle/toggle-activation-with-groups.tentative.html336
-rw-r--r--testing/web-platform/tests/css/css-toggle/toggle-activation.tentative.html489
-rw-r--r--testing/web-platform/tests/css/css-toggle/toggle-api.tentative.html338
-rw-r--r--testing/web-platform/tests/css/css-toggle/toggle-creation.tentative.html73
-rw-r--r--testing/web-platform/tests/css/css-toggle/toggle-events.tentative.html52
-rw-r--r--testing/web-platform/tests/css/css-toggle/toggle-pseudo-class.tentative.html235
-rw-r--r--testing/web-platform/tests/css/css-toggle/toggle-shorthand-serialization.tentative.html77
-rw-r--r--testing/web-platform/tests/css/css-toggle/toggle-trigger-focus.tentative.html54
-rw-r--r--testing/web-platform/tests/css/css-toggle/toggle-trigger-multiple.tentative.html92
-rw-r--r--testing/web-platform/tests/css/css-toggle/toggle-visibility-z-ordering-001.tentative.html40
-rw-r--r--testing/web-platform/tests/css/css-toggle/toggle-visibility-z-ordering-002.tentative.html44
-rw-r--r--testing/web-platform/tests/css/css-toggle/toggle-visibility.tentative.html267
33 files changed, 2669 insertions, 0 deletions
diff --git a/testing/web-platform/tests/css/css-toggle/animations/toggle-group-interpolation.tentative.html b/testing/web-platform/tests/css/css-toggle/animations/toggle-group-interpolation.tentative.html
new file mode 100644
index 0000000000..bde6c2978c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/animations/toggle-group-interpolation.tentative.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>toggle-group is not animatable</title>
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-group-property">
+<meta name="assert" content="toggle-group is not animatable">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_not_animatable({
+ property: 'toggle-group',
+ from: 'atoggle',
+ to: 'yourtoggle',
+ underlying: 'mytoggle',
+});
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-toggle/animations/toggle-root-interpolation.tentative.html b/testing/web-platform/tests/css/css-toggle/animations/toggle-root-interpolation.tentative.html
new file mode 100644
index 0000000000..855b7e6551
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/animations/toggle-root-interpolation.tentative.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>toggle-root is not animatable</title>
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-root-property">
+<meta name="assert" content="toggle-root is not animatable">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_not_animatable({
+ property: 'toggle-root',
+ from: 'none',
+ to: 'yourtoggle 3 at 1',
+ underlying: 'mytoggle 2',
+});
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-toggle/animations/toggle-trigger-interpolation.tentative.html b/testing/web-platform/tests/css/css-toggle/animations/toggle-trigger-interpolation.tentative.html
new file mode 100644
index 0000000000..1ebec55ef0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/animations/toggle-trigger-interpolation.tentative.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>toggle-trigger is not animatable</title>
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-trigger-property">
+<meta name="assert" content="toggle-trigger is not animatable">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_not_animatable({
+ property: 'toggle-trigger',
+ from: 'atoggle set 4',
+ to: 'yourtoggle set 3',
+ underlying: 'mytoggle set 2',
+});
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-toggle/idlharness.tentative.html b/testing/web-platform/tests/css/css-toggle/idlharness.tentative.html
new file mode 100644
index 0000000000..1f0cf22e81
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/idlharness.tentative.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<meta charset=UTF-8>
+<title>css-toggles IDL tests</title>
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#dom">
+<link rel="help" href="https://github.com/tabatkins/css-toggle/issues/29">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/resources/WebIDLParser.js></script>
+<script src=/resources/idlharness.js></script>
+<script src="support/toggle-helpers.js"></script>
+<div id="toggles" style="toggle-root: mytoggle 3 at 1"></div>
+<script type="module">
+'use strict';
+
+await wait_for_toggle_creation(document.getElementById("toggles"));
+
+idl_test(
+ ['css-toggle.tentative'],
+ ['dom'],
+ idl_array => {
+ idl_array.add_objects({
+ CSSToggleMap: ['document.getElementById("toggles").toggles'],
+ CSSToggle: [
+ 'document.getElementById("toggles").toggles.get("mytoggle")',
+ 'new CSSToggle()',
+ 'new CSSToggle({ value: 3, states: 7, group: true, scope: "narrow", cycle: "cycle-on"})',
+ 'new CSSToggle({ value: "four", states: ["one", "two", "four", "eight"], group: false, scope: "wide", cycle: "sticky"})',
+ ],
+ });
+ }
+);
+</script>
diff --git a/testing/web-platform/tests/css/css-toggle/parsing/support/toggle-root-values.js b/testing/web-platform/tests/css/css-toggle/parsing/support/toggle-root-values.js
new file mode 100644
index 0000000000..de2061107a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/parsing/support/toggle-root-values.js
@@ -0,0 +1,107 @@
+
+function test_toggle_root_computed_values(property) {
+ test_computed_value(property, 'none');
+ test_computed_value(property, 'sticky sticky');
+ test_computed_value(property, 'group group');
+ test_computed_value(property, 'self self');
+ test_computed_value(property, 'mytoggle');
+ test_computed_value(property, 'mytoggle, yourtoggle');
+ test_computed_value(property, 'mytoggle, mytoggle');
+ test_computed_value(property, 'mytoggle 3 at 0 sticky self, yourtoggle 1 group self', 'mytoggle 3 sticky self, yourtoggle group self');
+ test_computed_value(property, 'mytoggle 3 at 1 sticky self, yourtoggle 2 group self');
+ test_computed_value(property, 'mytoggle 1 at 0', 'mytoggle');
+ test_computed_value(property, 'mytoggle 1 at +0', 'mytoggle');
+ test_computed_value(property, 'mytoggle +1 at 0', 'mytoggle');
+ test_computed_value(property, 'mytoggle 1 at -0', 'mytoggle');
+ test_computed_value(property, 'mytoggle +1 at 2', 'mytoggle 1 at 2');
+ test_computed_value(property, 'mytoggle 1 at calc(-3)', 'mytoggle');
+ test_computed_value(property, 'mytoggle calc(-3) at 0', 'mytoggle');
+ test_computed_value(property, 'mytoggle 7 at calc(-3)', 'mytoggle 7');
+ test_computed_value(property, 'mytoggle calc(-3) at 7', 'mytoggle 1 at 7');
+ test_computed_value(property, 'mytoggle calc(9) at calc(6)', 'mytoggle 9 at 6');
+ test_computed_value(property, 'mytoggle calc(9.6) at calc(6.4)', 'mytoggle 10 at 6');
+ test_computed_value(property, 'mytoggle calc(-9.5) at calc(6.5)', 'mytoggle 1 at 7');
+ test_computed_value(property, 'mytoggle group sticky self, yourtoggle self sticky', 'mytoggle sticky group self, yourtoggle sticky self');
+ test_computed_value(property, 'mytoggle group 2 at 1', 'mytoggle 2 at 1 group');
+ test_computed_value(property, 'mytoggle [one two]');
+ test_computed_value(property, 'mytoggle [one two three]');
+ test_computed_value(property, 'mytoggle [one two three] at 0', 'mytoggle [one two three]');
+ test_computed_value(property, 'mytoggle [ one two three ] at 0', 'mytoggle [one two three]');
+ test_computed_value(property, 'mytoggle[one two three]at 0', 'mytoggle [one two three]');
+ test_computed_value(property, 'mytoggle [one two three] at 1');
+ test_computed_value(property, 'mytoggle [ one two three ] at 1', 'mytoggle [one two three] at 1');
+ test_computed_value(property, 'mytoggle[one two three]at 1', 'mytoggle [one two three] at 1');
+ test_computed_value(property, 'mytoggle [ one two three ] at two', 'mytoggle [one two three] at two');
+ test_computed_value(property, 'mytoggle 3 at two');
+}
+
+function test_toggle_root_valid_values(property) {
+ test_valid_value(property, 'none');
+ test_valid_value(property, 'sticky sticky');
+ test_valid_value(property, 'group group');
+ test_valid_value(property, 'self self');
+ test_valid_value(property, 'mytoggle');
+ test_valid_value(property, 'mytoggle, yourtoggle');
+ test_valid_value(property, 'mytoggle, mytoggle');
+ test_valid_value(property, 'mytoggle 3 at 0 sticky self, yourtoggle 1 group self');
+ test_valid_value(property, 'mytoggle 1 at 0');
+ test_valid_value(property, 'mytoggle 1 at +0', 'mytoggle 1 at 0');
+ test_valid_value(property, 'mytoggle +1 at 0', 'mytoggle 1 at 0');
+ test_valid_value(property, 'mytoggle 1 at -0', 'mytoggle 1 at 0');
+ test_valid_value(property, 'mytoggle 1 at calc(-3)');
+ test_valid_value(property, 'mytoggle calc(-3) at 0');
+ test_valid_value(property, 'mytoggle 7 at calc(-3)');
+ test_valid_value(property, 'mytoggle calc(-3) at 7');
+ test_valid_value(property, 'mytoggle calc(9) at calc(6)');
+ test_valid_value(property, 'mytoggle calc(9.6) at calc(6.4)');
+ test_valid_value(property, 'mytoggle calc(-9.5) at calc(6.5)');
+ test_valid_value(property, 'mytoggle group sticky self, yourtoggle self sticky', 'mytoggle sticky group self, yourtoggle sticky self');
+ test_valid_value(property, 'mytoggle group 2 at 1', 'mytoggle 2 at 1 group');
+ test_valid_value(property, 'mytoggle [one two]');
+ test_valid_value(property, 'mytoggle [one two three]');
+ test_valid_value(property, 'mytoggle [one two three] at 0');
+ test_valid_value(property, 'mytoggle [ one two three ] at 0', 'mytoggle [one two three] at 0');
+ test_valid_value(property, 'mytoggle[one two three]at 0', 'mytoggle [one two three] at 0');
+ test_valid_value(property, 'mytoggle [ one two three ] at two', 'mytoggle [one two three] at two');
+ test_valid_value(property, 'mytoggle 3 at two');
+}
+
+function test_toggle_root_invalid_values(property) {
+ test_invalid_value(property, 'none 1');
+ test_invalid_value(property, 'none sticky');
+ test_invalid_value(property, 'none cycle');
+ test_invalid_value(property, 'none cycle-on');
+ test_invalid_value(property, 'none group');
+ test_invalid_value(property, 'none self');
+ test_invalid_value(property, 'None self');
+ test_invalid_value(property, 'NONE self');
+ test_invalid_value(property, 'mytoggle sticky sticky');
+ test_invalid_value(property, 'mytoggle group group');
+ test_invalid_value(property, 'mytoggle self self');
+ test_invalid_value(property, 'none sticky sticky');
+ test_invalid_value(property, 'none group group');
+ test_invalid_value(property, 'none self self');
+ test_invalid_value(property, 'none, mytoggle');
+ test_invalid_value(property, 'mytoggle, none');
+ test_invalid_value(property, 'mytoggle 1 at');
+ test_invalid_value(property, 'mytoggle []');
+ test_invalid_value(property, 'mytoggle [one]');
+ test_invalid_value(property, 'mytoggle [one two] at');
+ test_invalid_value(property, 'mytoggle [one two two three]');
+ test_invalid_value(property, 'mytoggle [one two one three]');
+ test_invalid_value(property, 'mytoggle 0 sticky self');
+ test_invalid_value(property, 'mytoggle 0 at 0 sticky self');
+ test_invalid_value(property, 'mytoggle -1 at 1 sticky self');
+ test_invalid_value(property, 'mytoggle 1 at -1 sticky self');
+ test_invalid_value(property, 'mytoggle -1 at -1 sticky self');
+ test_invalid_value(property, 'mytoggle -1 at 0');
+ test_invalid_value(property, 'mytoggle 0 at 0');
+ test_invalid_value(property, 'mytoggle -0 at 0');
+ test_invalid_value(property, 'mytoggle +0 at 0');
+ test_invalid_value(property, 'mytoggle sticky 3 at 1 group self sticky');
+ test_invalid_value(property, 'mytoggle sticky 3 at 1 group self group');
+ test_invalid_value(property, 'mytoggle sticky 3 at 1 group self self');
+ test_invalid_value(property, 'mytoggle sticky 3 at 1 group self 1');
+ test_invalid_value(property, 'mytoggle sticky group at 1');
+ test_invalid_value(property, 'mytoggle sticky group at 1 1');
+}
diff --git a/testing/web-platform/tests/css/css-toggle/parsing/toggle-computed.tentative.html b/testing/web-platform/tests/css/css-toggle/parsing/toggle-computed.tentative.html
new file mode 100644
index 0000000000..36445d312a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/parsing/toggle-computed.tentative.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: getComputedStyle() for toggle property</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<script src="support/toggle-root-values.js"></script>
+
+<body>
+<div id="target"></div>
+<script>
+
+test_toggle_root_computed_values('toggle');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-toggle/parsing/toggle-group-computed.tentative.html b/testing/web-platform/tests/css/css-toggle/parsing/toggle-group-computed.tentative.html
new file mode 100644
index 0000000000..39548ecaa8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/parsing/toggle-group-computed.tentative.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: getComputedStyle() for toggle-group property</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-group-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+
+<body>
+<div id="target"></div>
+<script>
+
+test_computed_value('toggle-group', 'none');
+test_computed_value('toggle-group', 'self self');
+test_computed_value('toggle-group', 'mytoggle');
+test_computed_value('toggle-group', 'mytoggle, yourtoggle');
+test_computed_value('toggle-group', 'mytoggle, mytoggle');
+test_computed_value('toggle-group', 'mytoggle self, yourtoggle');
+test_computed_value('toggle-group', 'mytoggle self , yourtoggle self', 'mytoggle self, yourtoggle self');
+test_computed_value('toggle-group', 'mytoggle,yourtoggle self', 'mytoggle, yourtoggle self');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-toggle/parsing/toggle-group-invalid.tentative.html b/testing/web-platform/tests/css/css-toggle/parsing/toggle-group-invalid.tentative.html
new file mode 100644
index 0000000000..faff3483f1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/parsing/toggle-group-invalid.tentative.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: parsing toggle-group with invalid values</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-group-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+
+<body>
+<script>
+
+test_invalid_value('toggle-group', 'none, none');
+test_invalid_value('toggle-group', 'none self');
+test_invalid_value('toggle-group', 'None self');
+test_invalid_value('toggle-group', 'NONE self');
+test_invalid_value('toggle-group', 'mytoggle self self');
+test_invalid_value('toggle-group', 'none, mytoggle');
+test_invalid_value('toggle-group', 'mytoggle, none');
+test_invalid_value('toggle-group', 'mytoggle 1 self');
+test_invalid_value('toggle-group', 'mytoggle self 1');
+test_invalid_value('toggle-group', 'mytoggle sticky self');
+test_invalid_value('toggle-group', 'mytoggle self sticky');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-toggle/parsing/toggle-group-valid.tentative.html b/testing/web-platform/tests/css/css-toggle/parsing/toggle-group-valid.tentative.html
new file mode 100644
index 0000000000..53587d3b09
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/parsing/toggle-group-valid.tentative.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: parsing toggle-group with valid values</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-group-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+
+<body>
+<script>
+
+test_valid_value('toggle-group', 'none');
+test_valid_value('toggle-group', 'self self');
+test_valid_value('toggle-group', 'mytoggle');
+test_valid_value('toggle-group', 'mytoggle, yourtoggle');
+test_valid_value('toggle-group', 'mytoggle, mytoggle');
+test_valid_value('toggle-group', 'mytoggle self, yourtoggle');
+test_valid_value('toggle-group', 'mytoggle self , yourtoggle self', 'mytoggle self, yourtoggle self');
+test_valid_value('toggle-group', 'mytoggle,yourtoggle self', 'mytoggle, yourtoggle self');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-toggle/parsing/toggle-invalid.tentative.html b/testing/web-platform/tests/css/css-toggle/parsing/toggle-invalid.tentative.html
new file mode 100644
index 0000000000..8f460ff144
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/parsing/toggle-invalid.tentative.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: parsing toggle with invalid values</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<script src="support/toggle-root-values.js"></script>
+
+<body>
+<script>
+
+test_toggle_root_invalid_values('toggle');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-toggle/parsing/toggle-root-computed.tentative.html b/testing/web-platform/tests/css/css-toggle/parsing/toggle-root-computed.tentative.html
new file mode 100644
index 0000000000..fa7fd7ad51
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/parsing/toggle-root-computed.tentative.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: getComputedStyle() for toggle-root property</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-root-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<script src="support/toggle-root-values.js"></script>
+
+<body>
+<div id="target"></div>
+<script>
+
+test_toggle_root_computed_values('toggle-root');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-toggle/parsing/toggle-root-invalid.tentative.html b/testing/web-platform/tests/css/css-toggle/parsing/toggle-root-invalid.tentative.html
new file mode 100644
index 0000000000..76e208a3e5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/parsing/toggle-root-invalid.tentative.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: parsing toggle-root with invalid values</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-root-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<script src="support/toggle-root-values.js"></script>
+
+<body>
+<script>
+
+test_toggle_root_invalid_values('toggle-root');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-toggle/parsing/toggle-root-valid.tentative.html b/testing/web-platform/tests/css/css-toggle/parsing/toggle-root-valid.tentative.html
new file mode 100644
index 0000000000..8f943f1cb9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/parsing/toggle-root-valid.tentative.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: parsing toggle-root with valid values</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-root-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<script src="support/toggle-root-values.js"></script>
+
+<body>
+<script>
+
+test_toggle_root_valid_values('toggle-root');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-toggle/parsing/toggle-trigger-computed.tentative.html b/testing/web-platform/tests/css/css-toggle/parsing/toggle-trigger-computed.tentative.html
new file mode 100644
index 0000000000..4dab2b6045
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/parsing/toggle-trigger-computed.tentative.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: getComputedStyle() for toggle-trigger property</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-trigger-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+
+<body>
+<div id="target"></div>
+<script>
+
+test_computed_value('toggle-trigger', 'none');
+test_computed_value('toggle-trigger', 'self set 1');
+test_computed_value('toggle-trigger', 'sticky set 1');
+test_computed_value('toggle-trigger', 'group set 1');
+test_computed_value('toggle-trigger', 'mytoggle');
+test_computed_value('toggle-trigger', 'mytoggle set 0');
+test_computed_value('toggle-trigger', 'mytoggle set +0', 'mytoggle set 0');
+test_computed_value('toggle-trigger', 'mytoggle set -0', 'mytoggle set 0');
+test_computed_value('toggle-trigger', 'mytoggle set +5', 'mytoggle set 5');
+test_computed_value('toggle-trigger', 'mytoggle, yourtoggle');
+test_computed_value('toggle-trigger', 'mytoggle, mytoggle');
+test_computed_value('toggle-trigger', 'mytoggle set 1, yourtoggle');
+test_computed_value('toggle-trigger', 'mytoggle set 1 , yourtoggle set 1', 'mytoggle set 1, yourtoggle set 1');
+test_computed_value('toggle-trigger', 'mytoggle,yourtoggle set 1', 'mytoggle, yourtoggle set 1');
+test_computed_value('toggle-trigger', 'mytoggle set calc(-3)', 'mytoggle set 0');
+test_computed_value('toggle-trigger', 'mytoggle set calc(6)', 'mytoggle set 6');
+test_computed_value('toggle-trigger', 'mytoggle set calc(6.4)', 'mytoggle set 6');
+test_computed_value('toggle-trigger', 'mytoggle set calc(6.5)', 'mytoggle set 7');
+test_computed_value('toggle-trigger', 'mytoggle set calc(6.6)', 'mytoggle set 7');
+test_computed_value('toggle-trigger', 'mytoggle set two');
+test_computed_value('toggle-trigger', 'mytoggle next 1', 'mytoggle');
+test_computed_value('toggle-trigger', 'mytoggle next 2');
+test_computed_value('toggle-trigger', 'mytoggle prev 1', 'mytoggle prev');
+test_computed_value('toggle-trigger', 'mytoggle prev 2');
+test_computed_value('toggle-trigger', 'mytoggle next calc(-3)', 'mytoggle');
+test_computed_value('toggle-trigger', 'mytoggle prev calc(-3)', 'mytoggle prev');
+test_computed_value('toggle-trigger', 'mytoggle next calc(6.4)', 'mytoggle next 6');
+test_computed_value('toggle-trigger', 'mytoggle next calc(6.5)', 'mytoggle next 7');
+test_computed_value('toggle-trigger', 'mytoggle prev calc(6.4)', 'mytoggle prev 6');
+test_computed_value('toggle-trigger', 'mytoggle prev calc(6.5)', 'mytoggle prev 7');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-toggle/parsing/toggle-trigger-invalid.tentative.html b/testing/web-platform/tests/css/css-toggle/parsing/toggle-trigger-invalid.tentative.html
new file mode 100644
index 0000000000..584c4986f7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/parsing/toggle-trigger-invalid.tentative.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: parsing toggle-trigger with invalid values</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-trigger-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+
+<body>
+<script>
+
+test_invalid_value('toggle-trigger', 'none, none');
+test_invalid_value('toggle-trigger', 'none set 1');
+test_invalid_value('toggle-trigger', 'None set 1');
+test_invalid_value('toggle-trigger', 'NONE set 1');
+test_invalid_value('toggle-trigger', 'mytoggle set 1 1');
+test_invalid_value('toggle-trigger', 'mytoggle set -1');
+test_invalid_value('toggle-trigger', 'none, mytoggle');
+test_invalid_value('toggle-trigger', 'mytoggle, none');
+test_invalid_value('toggle-trigger', 'mytoggle self 1');
+test_invalid_value('toggle-trigger', 'mytoggle 1 self');
+test_invalid_value('toggle-trigger', 'mytoggle sticky 1');
+test_invalid_value('toggle-trigger', 'mytoggle 1 sticky');
+test_invalid_value('toggle-trigger', 'mytoggle self set 1');
+test_invalid_value('toggle-trigger', 'mytoggle set 1 self');
+test_invalid_value('toggle-trigger', 'mytoggle sticky set 1');
+test_invalid_value('toggle-trigger', 'mytoggle set 1 sticky');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-toggle/parsing/toggle-trigger-valid.tentative.html b/testing/web-platform/tests/css/css-toggle/parsing/toggle-trigger-valid.tentative.html
new file mode 100644
index 0000000000..1b4a896f20
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/parsing/toggle-trigger-valid.tentative.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: parsing toggle-trigger with valid values</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-trigger-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+
+<body>
+<script>
+
+test_valid_value('toggle-trigger', 'none');
+test_valid_value('toggle-trigger', 'self set 1');
+test_valid_value('toggle-trigger', 'sticky set 1');
+test_valid_value('toggle-trigger', 'group set 1');
+test_valid_value('toggle-trigger', 'mytoggle');
+test_valid_value('toggle-trigger', 'mytoggle set 0');
+test_valid_value('toggle-trigger', 'mytoggle set +0', 'mytoggle set 0');
+test_valid_value('toggle-trigger', 'mytoggle set -0', 'mytoggle set 0');
+test_valid_value('toggle-trigger', 'mytoggle set +5', 'mytoggle set 5');
+test_valid_value('toggle-trigger', 'mytoggle, yourtoggle');
+test_valid_value('toggle-trigger', 'mytoggle, mytoggle');
+test_valid_value('toggle-trigger', 'mytoggle set 1, yourtoggle');
+test_valid_value('toggle-trigger', 'mytoggle set 1 , yourtoggle set 1', 'mytoggle set 1, yourtoggle set 1');
+test_valid_value('toggle-trigger', 'mytoggle,yourtoggle set 1', 'mytoggle, yourtoggle set 1');
+test_valid_value('toggle-trigger', 'mytoggle set calc(-3)');
+test_valid_value('toggle-trigger', 'mytoggle set calc(6)');
+test_valid_value('toggle-trigger', 'mytoggle set calc(6.4)');
+test_valid_value('toggle-trigger', 'mytoggle set calc(6.5)');
+test_valid_value('toggle-trigger', 'mytoggle set calc(6.6)');
+test_valid_value('toggle-trigger', 'mytoggle set two');
+test_valid_value('toggle-trigger', 'mytoggle next 1');
+test_valid_value('toggle-trigger', 'mytoggle next 2');
+test_valid_value('toggle-trigger', 'mytoggle prev 1');
+test_valid_value('toggle-trigger', 'mytoggle prev 2');
+test_valid_value('toggle-trigger', 'mytoggle next calc(-3)');
+test_valid_value('toggle-trigger', 'mytoggle prev calc(-3)');
+test_valid_value('toggle-trigger', 'mytoggle next calc(6.4)');
+test_valid_value('toggle-trigger', 'mytoggle next calc(6.5)');
+test_valid_value('toggle-trigger', 'mytoggle prev calc(6.4)');
+test_valid_value('toggle-trigger', 'mytoggle prev calc(6.5)');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-toggle/parsing/toggle-valid.tentative.html b/testing/web-platform/tests/css/css-toggle/parsing/toggle-valid.tentative.html
new file mode 100644
index 0000000000..a02099c996
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/parsing/toggle-valid.tentative.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: parsing toggle with valid values</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<script src="support/toggle-root-values.js"></script>
+
+<body>
+<script>
+
+test_toggle_root_valid_values('toggle');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-toggle/parsing/toggle-visibility-computed.tentative.html b/testing/web-platform/tests/css/css-toggle/parsing/toggle-visibility-computed.tentative.html
new file mode 100644
index 0000000000..89cc80aa70
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/parsing/toggle-visibility-computed.tentative.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: getComputedStyle() for toggle-visibility property</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-visibility-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+
+<body>
+<div id="target"></div>
+<script>
+
+test_computed_value('toggle-visibility', 'normal');
+test_computed_value('toggle-visibility', 'toggle t');
+test_computed_value('toggle-visibility', 'toggle toggle');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-toggle/parsing/toggle-visibility-invalid.tentative.html b/testing/web-platform/tests/css/css-toggle/parsing/toggle-visibility-invalid.tentative.html
new file mode 100644
index 0000000000..c238834901
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/parsing/toggle-visibility-invalid.tentative.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: parsing toggle-visibility with invalid values</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-visibility-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+
+<body>
+<script>
+
+test_invalid_value('toggle-visibility', 'none');
+test_invalid_value('toggle-visibility', 'toggle');
+test_invalid_value('toggle-visibility', 't');
+test_invalid_value('toggle-visibility', 'normal, toggle t');
+test_invalid_value('toggle-visibility', 'toggle t, normal');
+test_invalid_value('toggle-visibility', 'toggle a, toggle t');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-toggle/parsing/toggle-visibility-valid.tentative.html b/testing/web-platform/tests/css/css-toggle/parsing/toggle-visibility-valid.tentative.html
new file mode 100644
index 0000000000..3541a6f137
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/parsing/toggle-visibility-valid.tentative.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: parsing toggle-visibility with valid values</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-visibility-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+
+<body>
+<script>
+
+test_valid_value('toggle-visibility', 'normal');
+test_valid_value('toggle-visibility', 'toggle t');
+test_valid_value('toggle-visibility', 'toggle toggle');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-toggle/support/toggle-helpers.js b/testing/web-platform/tests/css/css-toggle/support/toggle-helpers.js
new file mode 100644
index 0000000000..48f0916b4e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/support/toggle-helpers.js
@@ -0,0 +1,16 @@
+async function wait_for_toggle_creation(element) {
+ // TODO(crbug.com/1250716): The spec is vague about when toggles need to be
+ // created, and whether :toggle() pseudo-classes will update within the same
+ // update. See https://github.com/tabatkins/css-toggle/issues/27 . For
+ // now, we call elementFromPoint (which in Chromium flushes to PrePaint
+ // clean), which isn't a long term solution!
+ document.elementFromPoint(10, 10);
+}
+
+async function set_up_single_toggle_in(container, toggle_style) {
+ let div = document.createElement("div");
+ div.style.toggle = toggle_style;
+ container.replaceChildren(div);
+ await wait_for_toggle_creation(div);
+ return div;
+}
diff --git a/testing/web-platform/tests/css/css-toggle/toggle-activation-with-groups.tentative.html b/testing/web-platform/tests/css/css-toggle/toggle-activation-with-groups.tentative.html
new file mode 100644
index 0000000000..d8aeeb4275
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/toggle-activation-with-groups.tentative.html
@@ -0,0 +1,336 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: activation of toggles</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-trigger-property">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#fire-a-toggle-activation">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/toggle-helpers.js"></script>
+<style id="style"></style>
+
+<body>
+
+<div id="container"></div>
+<script>
+
+let container = document.getElementById("container");
+
+function test_trigger_on_group(toggle_specifier, other_specifier, action, toggle_expected, group_expected)
+{
+ promise_test(async function() {
+ let group = document.createElement("div");
+ group.style.toggleGroup = "test-group";
+
+ let toggle = document.createElement("div");
+ toggle.style.toggle = `test-group ${toggle_specifier} group`;
+ toggle.style.toggleTrigger = `test-group ${action}`;
+ group.appendChild(toggle);
+
+ let other = document.createElement("div");
+ other.style.toggle = `test-group ${other_specifier} group`;
+ group.appendChild(other);
+
+ let style = document.getElementById("style");
+ style.textContent = `
+ :toggle(test-group ${toggle_expected}) { --v:${toggle_expected}; }
+ :toggle(test-group ${group_expected}) { --v:${group_expected}; }
+ `;
+
+ container.replaceChildren(group);
+ await wait_for_toggle_creation(toggle);
+
+ toggle.click();
+ assert_true(toggle.matches(`:toggle(test-group ${toggle_expected}`), "value of triggered toggle");
+ assert_equals(getComputedStyle(toggle).getPropertyValue("--v"), toggle_expected, "style on triggered toggle");
+ assert_true(other.matches(`:toggle(test-group ${group_expected}`), "value of other toggle in group");
+ assert_equals(getComputedStyle(other).getPropertyValue("--v"), group_expected, "style on other toggle in group");
+ }, `group behavior for toggle "${toggle_specifier}" and action "${action}" with other element in group "${other_specifier}"`);
+}
+
+test_trigger_on_group("", "", "next", "1", "0");
+test_trigger_on_group("1 at 0", "1 at 0", "next", "1", "0");
+test_trigger_on_group("", "1 at 1", "next", "1", "0");
+test_trigger_on_group("1 at 1", "1 at 1", "next", "0", "1");
+test_trigger_on_group("1 at 1 cycle", "1 at 1", "next", "0", "1");
+test_trigger_on_group("1 at 1 cycle-on", "1 at 1", "next", "1", "0");
+test_trigger_on_group("1 at 1 sticky", "1 at 1", "next", "1", "0");
+test_trigger_on_group("1 at 1", "1 at 1", "set 3", "3", "0");
+test_trigger_on_group("1 at 1", "1 at 1", "set 0", "0", "1");
+test_trigger_on_group("1 at 7", "1 at 5", "set 9", "9", "0");
+test_trigger_on_group("1 at 7", "1 at 5", "set 0", "0", "5");
+test_trigger_on_group("", "1 at 1 cycle", "next", "1", "0");
+test_trigger_on_group("", "1 at 1 cycle-on", "next", "1", "0");
+test_trigger_on_group("", "1 at 1 sticky", "next", "1", "0");
+test_trigger_on_group("1 at 0", "1 at 1", "prev", "1", "0");
+test_trigger_on_group("1 at 0", "1 at 0", "prev", "1", "0");
+test_trigger_on_group("1 at 1", "1 at 1", "prev", "0", "1");
+test_trigger_on_group("1 at 1 cycle", "1 at 1", "prev", "0", "1");
+test_trigger_on_group("1 at 1 cycle-on", "1 at 1", "prev", "1", "0");
+test_trigger_on_group("1 at 1 sticky", "1 at 1", "prev", "0", "1");
+test_trigger_on_group("", "1 at 1", "set 0", "0", "1");
+test_trigger_on_group("", "1 at 1", "set 1", "1", "0");
+test_trigger_on_group("", "1 at 1", "set 7", "7", "0");
+test_trigger_on_group("", "1 at 1", "set named-state", "named-state", "0");
+test_trigger_on_group("[a b c] at a", "1 at 1", "next", "b", "0");
+test_trigger_on_group("[a b c] at c", "1 at 1", "next", "a", "1");
+test_trigger_on_group("[a b c] at a", "1 at 1", "prev", "c", "0");
+test_trigger_on_group("[a b c] at b", "1 at 1", "prev", "a", "1");
+test_trigger_on_group("[a b c] at b", "1 at 1", "set 2", "c", "0");
+test_trigger_on_group("[a b c] at b", "1 at 1", "set c", "c", "0");
+test_trigger_on_group("[a b c] at b", "1 at 1", "set 0", "0", "1");
+test_trigger_on_group("[a b c] at b", "1 at 1", "set a", "0", "1");
+test_trigger_on_group("[a b c] at b", "1 at 1", "set new-state", "new-state", "0");
+test_trigger_on_group("", "[a b c] at b", "next", "1", "a");
+test_trigger_on_group("", "[a b c] at b", "prev", "1", "a");
+test_trigger_on_group("", "[a b c] at b", "set 1", "1", "a");
+test_trigger_on_group("", "[a b c] at b", "set 0", "0", "b");
+
+let finding_group_tests = [
+ // Markup to create the test assertions:
+ // class=assert-in: assert that this element's in-scope toggle is in the
+ // test-group group and was not the activated toggle
+ // class=assert-out: assert that this element's in-scope toggle is not in
+ // the test-group group and was not the activated toggle
+ // class=assert-activated: assert that this element's in-scope toggle was
+ // the activated toggle
+ //
+ // Helper markup to create more markup:
+ // class=establish: establish the group with the toggle-group property
+ // class=establish-self: same, but with the self keyword (narrow scope)
+ // class=root: create a test-group toggle with the toggle-root property
+ // class=root-nogroup: same, but without the 'group' keyword
+ // class=activate: toggle-trigger to activate test-group toggle
+ //
+ // class=activate (above) is *also* a helper to run the test; it will be
+ // activated. There must only be one element with class=activate.
+ `
+ <div class="establish"></div>
+ <div class="root assert-in"></div>
+ <div class="root-nogroup assert-out"></div>
+ <div class="root activate assert-activated"></div>
+ `,
+ `
+ <div class="establish"></div>
+ <div class="root assert-out"></div>
+ <div class="establish"></div>
+ <div class="root assert-in"></div>
+ <div class="root activate assert-activated"></div>
+ `,
+ `
+ <div class="establish"></div>
+ <div class="root activate assert-activated"></div>
+ <div class="root assert-in"></div>
+ <div class="establish"></div>
+ <div class="root assert-out"></div>
+ `,
+ `
+ <div class="establish"></div>
+ <div class="root assert-in"></div>
+ <div class="establish-self">
+ <div class="root assert-out"></div>
+ </div>
+ <div class="root assert-in"></div>
+ <div class="root activate assert-activated"></div>
+ `,
+ `
+ <div class="establish"></div>
+ <div class="root assert-out"></div>
+ <div class="establish">
+ <div class="root assert-in"></div>
+ </div>
+ <div class="root assert-in"></div>
+ <div class="root activate assert-activated"></div>
+ `,
+ `
+ <div class="establish"></div>
+ <div class="root activate assert-activated"></div>
+ <div class="root assert-in"></div>
+ <div class="establish">
+ <div class="root assert-out"></div>
+ </div>
+ <div class="root assert-out"></div>
+ `,
+ `
+ <div class="establish"></div>
+ <div class="root assert-in"></div>
+ <div class="establish-self"></div>
+ <div class="root assert-activated"></div>
+ <div class="activate"></div>
+ `,
+ `
+ <div class="root activate assert-activated"></div>
+ <div class="root assert-in"></div>
+ `,
+ `
+ <div class="root assert-out"></div>
+ <div class="establish-self">
+ <div class="root activate assert-activated"></div>
+ <div class="root assert-in"></div>
+ </div>
+ <div class="root assert-out"></div>
+ `,
+ `
+ <div class="root assert-out"></div>
+ <div style="toggle-group: test-group self, extra-group">
+ <div class="root activate assert-activated"></div>
+ <div class="root assert-in"></div>
+ </div>
+ <div class="root assert-out"></div>
+ `,
+ `
+ <div class="root assert-out"></div>
+ <div style="toggle-group: extra-group, test-group self">
+ <div class="root activate assert-activated"></div>
+ <div class="root assert-in"></div>
+ </div>
+ <div class="root assert-out"></div>
+ `,
+ `
+ <div class="root activate assert-activated">
+ <div class="establish">
+ <div class="root assert-out"></div>
+ </div>
+ <div class="root assert-out"></div>
+ </div>
+ `,
+ `
+ <div class="root activate assert-activated">
+ <div class="establish-self">
+ <div class="root assert-out"></div>
+ </div>
+ <div class="root assert-in"></div>
+ </div>
+ `,
+ `
+ <div class="root activate assert-activated">
+ <div class="root assert-in"></div>
+ <div>
+ <div class="root assert-in"></div>
+ <div class="establish">
+ <div class="root assert-out"></div>
+ </div>
+ <div class="root assert-out"></div>
+ </div>
+ <div class="root assert-in"></div>
+ </div>
+ `,
+];
+
+for (let t of finding_group_tests) {
+ promise_test(async function() {
+ document.getElementById("style").textContent = `
+ :toggle(test-group 0) { --v:0; }
+ :toggle(test-group 1) { --v:1; }
+ :toggle(test-group 2) { --v:2; }
+ `;
+ container.innerHTML = t;
+
+ for (let e of container.querySelectorAll('.establish')) {
+ e.style.toggleGroup = "test-group";
+ }
+ for (let e of container.querySelectorAll('.establish-self')) {
+ e.style.toggleGroup = "test-group self";
+ }
+ for (let e of container.querySelectorAll('.root')) {
+ e.style.toggleRoot = "test-group 1 at 1 cycle-on group";
+ }
+ for (let e of container.querySelectorAll('.root-nogroup')) {
+ e.style.toggleRoot = "test-group 1 at 1 cycle-on";
+ }
+ let activate = container.querySelector('.activate');
+ activate.style.toggleTrigger = "test-group set 2";
+
+ for (let e of container.querySelectorAll('.root, .root-nogroup')) {
+ await wait_for_toggle_creation(e);
+ }
+
+ activate.click();
+ for (let e of container.querySelectorAll('.assert-in')) {
+ assert_true(e.matches(":toggle(test-group 0)"), "element in group");
+ assert_equals(getComputedStyle(e).getPropertyValue("--v"), "0",
+ "style on element in group");
+ }
+ for (let e of container.querySelectorAll('.assert-out')) {
+ assert_true(e.matches(":toggle(test-group 1)"), "element not in group");
+ assert_equals(getComputedStyle(e).getPropertyValue("--v"), "1",
+ "style on element not in group");
+ }
+ for (let e of container.querySelectorAll('.assert-activated')) {
+ assert_true(e.matches(":toggle(test-group 2)"), "element was activated");
+ assert_equals(getComputedStyle(e).getPropertyValue("--v"), "2",
+ "style on activated element");
+ }
+ }, `toggle groups test: ${t}`);
+}
+
+promise_test(async () => {
+ container.innerHTML = `
+ <div id="e" style="toggle: tog [a b] at b self group"></div>
+ <div id="f" style="toggle: tog [a b] at a self group"></div>
+ `;
+ let e = document.getElementById("e");
+ let f = document.getElementById("f");
+ await Promise.all([wait_for_toggle_creation(e),
+ wait_for_toggle_creation(f)]);
+
+ let te = e.toggles.get("tog");
+ let tf = f.toggles.get("tog");
+ assert_equals(te.value, "b", "e value before first click");
+ assert_true(e.matches(':toggle(tog b):toggle(tog 1)'),
+ "e selector matching before first click");
+ assert_equals(tf.value, "a", "f value before first click");
+ assert_true(f.matches(':toggle(tog a):toggle(tog 0)'),
+ "f selector matching before first click");
+ f.click();
+ assert_equals(te.value, 0, "e value after first click");
+ assert_equals(tf.value, "b", "f value after first click");
+ f.click();
+ assert_equals(te.value, 0, "e value after second click");
+ assert_equals(tf.value, "a", "f value after second click");
+ te.value = "b";
+ assert_equals(te.value, "b", "e value after first value set");
+ assert_equals(tf.value, 0, "f value after first value set");
+ tf.value = "b";
+ assert_equals(te.value, 0, "e value after second value set");
+ assert_equals(tf.value, "b", "f value after second value set");
+ tf.value = "a";
+ assert_equals(te.value, 0, "e value after third value set");
+ assert_equals(tf.value, "a", "f value after third value set");
+
+ // Swap the order of the state names in 'toggle-root'. This does not affect
+ // the states on the toggle, but still affects the override specifier used
+ // in some algorithms.
+ e.style.toggleRoot = "tog [b a] at 0 self group";
+ f.style.toggleRoot = "tog [b a] at 0 self group";
+ await Promise.all([wait_for_toggle_creation(e),
+ wait_for_toggle_creation(f)]);
+
+ assert_equals(te.value, 0, "e value after changing toggle-root");
+ assert_equals(tf.value, "a", "f value after changing toggle-root");
+ e.click();
+ assert_equals(te.value, "a", "e value after third click");
+ assert_equals(tf.value, 0, "f value after third click");
+ e.click();
+ assert_equals(te.value, "b", "e value after fourth click");
+ assert_equals(tf.value, 0, "f value after fourth click");
+ assert_true(e.matches(':toggle(tog b):toggle(tog 1)'),
+ "e selector matching after changing toggle-root");
+ assert_true(f.matches(':toggle(tog a):toggle(tog 0)'),
+ "f selector matching after changing toggle-root");
+ tf.value = "a";
+ assert_equals(te.value, 0, "e value after fourth value set");
+ assert_equals(tf.value, "a", "f value after fourth value set");
+ tf.value = "b";
+ assert_equals(te.value, 0, "e value after fifth value set");
+ assert_equals(tf.value, "b", "f value after fifth value set");
+ te.value = "b";
+ assert_equals(te.value, "b", "e value after sixth value set");
+ assert_equals(tf.value, "b", "f value after sixth value set");
+}, "zeroing toggle group uses states from override specifier");
+
+// TODO(dbaron): This could probably use a few additional tests for multiple
+// values of the list-valued properties. (But they're hard to auto-generate.)
+
+</script>
diff --git a/testing/web-platform/tests/css/css-toggle/toggle-activation.tentative.html b/testing/web-platform/tests/css/css-toggle/toggle-activation.tentative.html
new file mode 100644
index 0000000000..2006460566
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/toggle-activation.tentative.html
@@ -0,0 +1,489 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: activation of toggles</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-trigger-property">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#fire-a-toggle-activation">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/toggle-helpers.js"></script>
+<style>
+:toggle(finding-test 0) { --finding-test:0; }
+:toggle(finding-test 1) { --finding-test:1; }
+:toggle(test-states 0) { --test-states:0; }
+:toggle(test-states 1) { --test-states:1; }
+:toggle(test-states 2) { --test-states:2; }
+:toggle(test-group 0) { --test-group:0; }
+:toggle(test-group 1) { --test-group:1; }
+:toggle(test-overflow 0) { --test-overflow:0; }
+:toggle(test-overflow 1) { --test-overflow:1; }
+:toggle(set-num 0) { --set-num:0; }
+:toggle(set-num 1) { --set-num:1; }
+:toggle(set-num 2) { --set-num:2; }
+:toggle(set-names zero) { --set-names:0; }
+:toggle(set-names one) { --set-names:1; }
+:toggle(set-names two) { --set-names:2; }
+:toggle(set-names three) { --set-names:3; }
+</style>
+
+<body>
+
+<div id="container"></div>
+<script>
+
+let container = document.getElementById("container");
+
+let toggle_finding_tests = [
+ {
+ description: "wide toggle on previous sibling",
+ markup: `<div>
+ <div id="toggle"></div>
+ <div id="target"></div>
+ </div>`,
+ found: true
+ },
+ {
+ description: "narrow toggle on previous sibling",
+ markup: `<div>
+ <div id="toggle"></div>
+ <div id="target"></div>
+ </div>`,
+ found: false,
+ self: true
+ },
+ {
+ description: "wide toggle on previous sibling with intervening narrow toggle",
+ markup: `<div>
+ <div id="toggle"></div>
+ <div style="toggle: finding-test self"></div>
+ <div id="target"></div>
+ </div>`,
+ found: true
+ },
+ {
+ description: "wide toggle on parent with intervening narrow toggle",
+ markup: `<div id="toggle">
+ <div style="toggle: finding-test self"></div>
+ <div id="target"></div>
+ </div>`,
+ found: true
+ },
+ {
+ description: "wide toggle on parent's prior sibling with intervening narrow toggle",
+ markup: `<div id="toggle"></div>
+ <div>
+ <div style="toggle: finding-test self"></div>
+ <div id="target"></div>
+ </div>`,
+ found: true
+ },
+ {
+ description: "wide toggle on later sibling",
+ markup: `<div id="target"></div>
+ <div id="toggle"></div>`,
+ found: false
+ },
+ {
+ description: "wide toggle on child",
+ markup: `<div id="target">
+ <div id="toggle"></div>
+ </div>`,
+ found: false
+ }
+];
+
+for (let toggle_finding_test of toggle_finding_tests) {
+ promise_test(async function() {
+ container.innerHTML = toggle_finding_test.markup;
+ let toggle = document.getElementById("toggle");
+ let toggle_cs = getComputedStyle(toggle);
+ let target = document.getElementById("target");
+ let toggle_root_style = "finding-test";
+ if (toggle_finding_test.self) {
+ toggle_root_style += " self";
+ }
+ toggle.style.toggleRoot = toggle_root_style;
+ target.style.toggleTrigger = "finding-test";
+ await wait_for_toggle_creation(toggle);
+ assert_true(toggle.matches(':toggle(finding-test 0)'),
+ "matches before click");
+ assert_equals(toggle_cs.getPropertyValue("--finding-test"), "0",
+ "computed style before click");
+ target.click();
+ if (toggle_finding_test.found) {
+ assert_true(toggle.matches(':toggle(finding-test 1)'),
+ "matches after click");
+ assert_equals(toggle_cs.getPropertyValue("--finding-test"), "1",
+ "computed style after click");
+ } else {
+ assert_true(toggle.matches(':toggle(finding-test 0)'),
+ "matches after click");
+ assert_equals(toggle_cs.getPropertyValue("--finding-test"), "0",
+ "computed style after click");
+ }
+ }, `finding toggle: ${toggle_finding_test.description}`);
+}
+
+promise_test(async function() {
+ let e = await set_up_single_toggle_in(container, "test-states 1 at 0");
+ let cs = getComputedStyle(e);
+ assert_true(e.matches(":toggle(test-states 0)"));
+ assert_equals(cs.getPropertyValue("--test-states"), "0");
+ e.click();
+ assert_true(e.matches(":toggle(test-states 1)"));
+ assert_equals(cs.getPropertyValue("--test-states"), "1");
+ e.click();
+ assert_true(e.matches(":toggle(test-states 0)"));
+ assert_equals(cs.getPropertyValue("--test-states"), "0");
+ e.style.toggleRoot = "test-states 2 at 2";
+ await wait_for_toggle_creation(e);
+ assert_true(e.matches(":toggle(test-states 0)"));
+ assert_equals(cs.getPropertyValue("--test-states"), "0");
+ e.click();
+ e.click();
+ assert_true(e.matches(":toggle(test-states 2)"));
+ assert_equals(cs.getPropertyValue("--test-states"), "2");
+ e.style.toggleRoot = "";
+ await wait_for_toggle_creation(e);
+ assert_true(e.matches(":toggle(test-states 2)"));
+ assert_equals(cs.getPropertyValue("--test-states"), "2");
+ e.click();
+ assert_true(e.matches(":toggle(test-states 0)"));
+ assert_equals(cs.getPropertyValue("--test-states"), "0");
+ e.click();
+ assert_true(e.matches(":toggle(test-states 1)"));
+ assert_equals(cs.getPropertyValue("--test-states"), "1");
+ e.click();
+ assert_true(e.matches(":toggle(test-states 0)"));
+ assert_equals(cs.getPropertyValue("--test-states"), "0");
+}, "states used from toggle or toggle specifier as appropriate (integer)");
+
+promise_test(async function() {
+ let e = await set_up_single_toggle_in(container, "test-states [one two] at 0");
+ let cs = getComputedStyle(e);
+ let t = e.toggles.get("test-states");
+ assert_equals(t.value, 0);
+ assert_true(e.matches(":toggle(test-states 0)"));
+ assert_true(e.matches(":toggle(test-states one)"));
+ assert_equals(cs.getPropertyValue("--test-states"), "0");
+ e.click();
+ assert_equals(t.value, "two");
+ assert_true(e.matches(":toggle(test-states 1)"));
+ assert_true(e.matches(":toggle(test-states two)"));
+ assert_equals(cs.getPropertyValue("--test-states"), "1");
+ e.click();
+ assert_equals(t.value, "one");
+ assert_true(e.matches(":toggle(test-states 0)"));
+ assert_true(e.matches(":toggle(test-states one)"));
+ assert_equals(cs.getPropertyValue("--test-states"), "0");
+ e.style.toggleRoot = "test-states [zero one two] at 2";
+ await wait_for_toggle_creation(e);
+ assert_equals(t.value, "one");
+ assert_true(e.matches(":toggle(test-states 0)"));
+ assert_true(e.matches(":toggle(test-states one)"));
+ assert_equals(cs.getPropertyValue("--test-states"), "0");
+ e.click();
+ assert_equals(t.value, "two");
+ assert_true(e.matches(":toggle(test-states 1)"));
+ assert_true(e.matches(":toggle(test-states two)"));
+ assert_equals(cs.getPropertyValue("--test-states"), "1");
+ e.click();
+ assert_equals(t.value, "zero");
+ assert_true(e.matches(":toggle(test-states zero)"));
+ assert_equals(cs.getPropertyValue("--test-states"), "");
+ e.style.toggleRoot = "";
+ await wait_for_toggle_creation(e);
+ assert_equals(t.value, "zero");
+ assert_true(e.matches(":toggle(test-states zero)"));
+ assert_equals(cs.getPropertyValue("--test-states"), "");
+ e.click();
+ assert_equals(t.value, "one");
+ assert_true(e.matches(":toggle(test-states 0)"));
+ assert_true(e.matches(":toggle(test-states one)"));
+ assert_equals(cs.getPropertyValue("--test-states"), "0");
+ e.click();
+ assert_equals(t.value, "two");
+ assert_true(e.matches(":toggle(test-states 1)"));
+ assert_true(e.matches(":toggle(test-states two)"));
+ assert_equals(cs.getPropertyValue("--test-states"), "1");
+ e.click();
+ assert_equals(t.value, "one");
+ assert_true(e.matches(":toggle(test-states 0)"));
+ assert_true(e.matches(":toggle(test-states one)"));
+ assert_equals(cs.getPropertyValue("--test-states"), "0");
+}, "states used from toggle or toggle specifier as appropriate (names)");
+
+promise_test(async function() {
+ container.innerHTML = `
+ <div style="toggle-group: test-group">
+ <div id="t" style="toggle: test-group 1 at 0 group"></div>
+ <div id="other" style="toggle: test-group 1 at 0 group"></div>
+ </div>
+ `;
+ let t = document.getElementById("t");
+ let other = document.getElementById("other");
+ let t_cs = getComputedStyle(t);
+ let other_cs = getComputedStyle(other);
+ await wait_for_toggle_creation(t);
+ await wait_for_toggle_creation(other);
+ other.click();
+ assert_true(t.matches(":toggle(test-group 0)"));
+ assert_equals(t_cs.getPropertyValue("--test-group"), "0");
+ assert_true(other.matches(":toggle(test-group 1)"));
+ assert_equals(other_cs.getPropertyValue("--test-group"), "1");
+ t.click();
+ assert_true(t.matches(":toggle(test-group 1)"));
+ assert_equals(t_cs.getPropertyValue("--test-group"), "1");
+ assert_true(other.matches(":toggle(test-group 0)"));
+ assert_equals(other_cs.getPropertyValue("--test-group"), "0");
+ other.click();
+ assert_true(t.matches(":toggle(test-group 0)"));
+ assert_equals(t_cs.getPropertyValue("--test-group"), "0");
+ assert_true(other.matches(":toggle(test-group 1)"));
+ assert_equals(other_cs.getPropertyValue("--test-group"), "1");
+
+ // Test that we use the group value from the toggle specifier when it's
+ // different from the toggle, but only when that's the toggle we're
+ // changing.
+ t.style.toggleRoot = "test-group 1 at 0";
+ t.click();
+ assert_true(t.matches(":toggle(test-group 1)"));
+ assert_equals(t_cs.getPropertyValue("--test-group"), "1");
+ assert_true(other.matches(":toggle(test-group 1)"));
+ assert_equals(other_cs.getPropertyValue("--test-group"), "1");
+ other.click();
+ assert_true(t.matches(":toggle(test-group 1)"));
+ assert_equals(t_cs.getPropertyValue("--test-group"), "1");
+ assert_true(other.matches(":toggle(test-group 0)"));
+ assert_equals(other_cs.getPropertyValue("--test-group"), "0");
+ other.click();
+ assert_true(t.matches(":toggle(test-group 0)"));
+ assert_equals(t_cs.getPropertyValue("--test-group"), "0");
+ assert_true(other.matches(":toggle(test-group 1)"));
+ assert_equals(other_cs.getPropertyValue("--test-group"), "1");
+
+ // Test that we use the group value from the toggle when there is no toggle
+ // specifier.
+ t.style.toggleRoot = "";
+ t.click();
+ assert_true(t.matches(":toggle(test-group 1)"));
+ assert_equals(t_cs.getPropertyValue("--test-group"), "1");
+ assert_true(other.matches(":toggle(test-group 0)"));
+ assert_equals(other_cs.getPropertyValue("--test-group"), "0");
+ other.click();
+ assert_true(t.matches(":toggle(test-group 0)"));
+ assert_equals(t_cs.getPropertyValue("--test-group"), "0");
+ assert_true(other.matches(":toggle(test-group 1)"));
+ assert_equals(other_cs.getPropertyValue("--test-group"), "1");
+ other.click();
+ assert_true(t.matches(":toggle(test-group 0)"));
+ assert_equals(t_cs.getPropertyValue("--test-group"), "0");
+ assert_true(other.matches(":toggle(test-group 0)"));
+ assert_equals(other_cs.getPropertyValue("--test-group"), "0");
+}, "group used from toggle or toggle specifier as appropriate");
+
+promise_test(async function() {
+ let e = await set_up_single_toggle_in(container, "test-overflow sticky");
+ let cs = getComputedStyle(e);
+ assert_true(e.matches(":toggle(test-overflow 0)"));
+ assert_equals(cs.getPropertyValue("--test-overflow"), "0");
+ e.click();
+ assert_true(e.matches(":toggle(test-overflow 1)"));
+ assert_equals(cs.getPropertyValue("--test-overflow"), "1");
+ e.click();
+ assert_true(e.matches(":toggle(test-overflow 1)"));
+ assert_equals(cs.getPropertyValue("--test-overflow"), "1");
+ e.style.toggleRoot = "test-overflow";
+ await wait_for_toggle_creation(e);
+ assert_true(e.matches(":toggle(test-overflow 1)"));
+ assert_equals(cs.getPropertyValue("--test-overflow"), "1");
+ e.click();
+ assert_true(e.matches(":toggle(test-overflow 0)"));
+ assert_equals(cs.getPropertyValue("--test-overflow"), "0");
+ e.style.toggleRoot = "";
+ await wait_for_toggle_creation(e);
+ assert_true(e.matches(":toggle(test-overflow 0)"));
+ assert_equals(cs.getPropertyValue("--test-overflow"), "0");
+ e.click();
+ assert_true(e.matches(":toggle(test-overflow 1)"));
+ assert_equals(cs.getPropertyValue("--test-overflow"), "1");
+ e.click();
+ assert_true(e.matches(":toggle(test-overflow 1)"));
+ assert_equals(cs.getPropertyValue("--test-overflow"), "1");
+}, "overflow used from toggle or toggle specifier as appropriate");
+
+promise_test(async function() {
+ container.innerHTML = `<div id="t" style="toggle-root: set-num 5 at 1"></div>
+ <div id="a" style="toggle-trigger: set-num set 2"></div>
+ <div id="b" style="toggle-trigger: set-num set 0"></div>
+ <div id="c" style="toggle-trigger: set-num set named-state"></div>
+ <div id="m"></div>
+ `;
+ let t = document.getElementById("t");
+ let a = document.getElementById("a");
+ let b = document.getElementById("b");
+ let c = document.getElementById("c");
+ let m = document.getElementById("m");
+ let cs = getComputedStyle(m);
+ await wait_for_toggle_creation(t);
+ assert_true(m.matches(':toggle(set-num 1)'), "initial state");
+ assert_equals(cs.getPropertyValue("--set-num"), "1");
+ a.click();
+ assert_true(m.matches(':toggle(set-num 2)'), "state after clicking a");
+ assert_equals(cs.getPropertyValue("--set-num"), "2");
+ b.click();
+ assert_true(m.matches(':toggle(set-num 0)'), "state after clicking b");
+ assert_equals(cs.getPropertyValue("--set-num"), "0");
+ c.click();
+ assert_true(m.matches(':toggle(set-num named-state)'), "state after clicking c");
+ assert_equals(cs.getPropertyValue("--set-num"), "");
+}, "changing with toggle-trigger: set (numbers)");
+
+promise_test(async function() {
+ container.innerHTML = `<div id="t" style="toggle-root: set-names [zero one two three four five] at two"></div>
+ <div id="a" style="toggle-trigger: set-names set one"></div>
+ <div id="b" style="toggle-trigger: set-names set 3"></div>
+ <div id="c" style="toggle-trigger: set-names set zero"></div>
+ <div id="d" style="toggle-trigger: set-names set named-state"></div>
+ <div id="m"></div>
+ `;
+ let t = document.getElementById("t");
+ let a = document.getElementById("a");
+ let b = document.getElementById("b");
+ let c = document.getElementById("c");
+ let d = document.getElementById("d");
+ let m = document.getElementById("m");
+ let cs = getComputedStyle(m);
+ await wait_for_toggle_creation(t);
+ assert_true(m.matches(':toggle(set-names two)'));
+ assert_true(m.matches(':toggle(set-names 2)'));
+ assert_equals(cs.getPropertyValue("--set-names"), "2");
+ a.click();
+ assert_true(m.matches(':toggle(set-names one)'));
+ assert_true(m.matches(':toggle(set-names 1)'));
+ assert_equals(cs.getPropertyValue("--set-names"), "1");
+ b.click();
+ assert_true(m.matches(':toggle(set-names three)'));
+ assert_true(m.matches(':toggle(set-names 3)'));
+ assert_equals(cs.getPropertyValue("--set-names"), "3");
+ c.click();
+ assert_true(m.matches(':toggle(set-names zero)'));
+ assert_true(m.matches(':toggle(set-names 0)'));
+ assert_equals(cs.getPropertyValue("--set-names"), "0");
+ d.click();
+ assert_true(m.matches(':toggle(set-names named-state)'));
+ assert_false(m.matches(':toggle(set-names 0)'));
+ assert_equals(cs.getPropertyValue("--set-names"), "");
+ b.click();
+ assert_true(m.matches(':toggle(set-names 3)'));
+ assert_equals(cs.getPropertyValue("--set-names"), "3");
+ d.click();
+ assert_false(m.matches(':toggle(set-names 3)'));
+ assert_equals(cs.getPropertyValue("--set-names"), "");
+}, "changing with toggle-trigger: set (named states)");
+
+function test_action_and_cycle(states_and_cycle, start, action, result) {
+ promise_test(async function() {
+ container.innerHTML = `
+ <div id="toggle" style="toggle-root: test ${states_and_cycle}"></div>
+ <div id="start" style="toggle-trigger: test set ${start}"></div>
+ <div id="action" style="toggle-trigger: test ${action}"></div>
+ `;
+ let toggle = document.getElementById("toggle");
+ await wait_for_toggle_creation(toggle);
+ document.getElementById("start").click();
+ assert_true(toggle.matches(`:toggle(test ${start})`), "value after set");
+ document.getElementById("action").click();
+ assert_true(toggle.matches(`:toggle(test ${result})`), "value after action");
+ }, `toggle with "${states_and_cycle}" changing from "${start}" with action "${action}"`);
+}
+
+function test_action_and_all_cycles(states, start, action, result_cycle, result_cycle_on, result_sticky) {
+ test_action_and_cycle(states, start, action, result_cycle);
+ test_action_and_cycle(`${states} cycle`, start, action, result_cycle);
+ test_action_and_cycle(`${states} cycle-on`, start, action, result_cycle_on);
+ test_action_and_cycle(`${states} sticky`, start, action, result_sticky);
+}
+
+test_action_and_all_cycles("2", "0", "next", "1", "1", "1");
+test_action_and_all_cycles("2", "1", "next", "2", "2", "2");
+test_action_and_all_cycles("2", "2", "next", "0", "1", "2");
+test_action_and_all_cycles("3", "5", "next", "0", "1", "3");
+test_action_and_all_cycles("4", "3", "next", "4", "4", "4");
+test_action_and_all_cycles("4", "3", "next 3", "0", "1", "4");
+test_action_and_all_cycles("3", "named-value", "next", "0", "1", "3");
+test_action_and_all_cycles("[a b c d]", "a", "next", "b", "b", "b");
+test_action_and_all_cycles("[a b c d]", "a", "next 5", "a", "b", "d");
+test_action_and_all_cycles("[a b c d]", "c", "next", "d", "d", "d");
+test_action_and_all_cycles("[a b c d]", "d", "next", "a", "b", "d");
+test_action_and_all_cycles("[a b c d]", "extra-state", "next", "a", "b", "d");
+
+test_action_and_all_cycles("2", "0", "prev", "2", "2", "0");
+test_action_and_all_cycles("2", "1", "prev", "0", "2", "0");
+test_action_and_all_cycles("2", "2", "prev", "1", "1", "1");
+test_action_and_all_cycles("2", "5", "prev", "2", "2", "2");
+test_action_and_all_cycles("3", "5", "prev 3", "2", "2", "2");
+test_action_and_all_cycles("3", "2", "prev 3", "3", "3", "0");
+test_action_and_all_cycles("3", "named-value", "prev", "3", "3", "3");
+test_action_and_all_cycles("[a b c d]", "a", "prev", "d", "d", "a");
+test_action_and_all_cycles("[a b c d]", "b", "prev", "a", "d", "a");
+test_action_and_all_cycles("[a b c d]", "d", "prev", "c", "c", "c");
+test_action_and_all_cycles("[a b c d]", "c", "prev 5", "d", "d", "a");
+test_action_and_all_cycles("[a b c d]", "extra-state", "prev", "d", "d", "d");
+
+// TODO(https://github.com/tabatkins/css-toggle/issues/39): This set of
+// tests is testing proposed behavior; the spec currently says something
+// that we agree is wrong.
+promise_test(async function() {
+ container.innerHTML = `
+ <button id="toggle" style="toggle: test"></button>
+ `;
+ let toggle = document.getElementById("toggle");
+ await wait_for_toggle_creation(toggle);
+ assert_true(!toggle.matches(`:toggle(test)`), "value before click");
+ toggle.click();
+ assert_true(toggle.matches(`:toggle(test)`), "value after click");
+}, "toggle activation on button with toggle-trigger (1)");
+promise_test(async function() {
+ container.innerHTML = `
+ <div id="toggle" style="toggle-root: test">
+ <button id="trigger" style="toggle-trigger: test"></button>
+ </div>
+ `;
+ let toggle = document.getElementById("toggle");
+ await wait_for_toggle_creation(toggle);
+ assert_true(!toggle.matches(`:toggle(test)`), "value before click");
+ document.getElementById("trigger").click();
+ assert_true(toggle.matches(`:toggle(test)`), "value after click");
+}, "toggle activation on button with toggle-trigger (2)");
+promise_test(async function() {
+ container.innerHTML = `
+ <div id="toggle" style="toggle: test">
+ <button id="button"></button>
+ </div>
+ `;
+ let toggle = document.getElementById("toggle");
+ await wait_for_toggle_creation(toggle);
+ assert_true(!toggle.matches(`:toggle(test)`), "value before click");
+ document.getElementById("button").click();
+ assert_true(!toggle.matches(`:toggle(test)`), "value after button click");
+ toggle.click();
+ assert_true(toggle.matches(`:toggle(test)`), "value after div click");
+}, "toggle activation on button inside element with toggle-trigger");
+promise_test(async function() {
+ container.innerHTML = `
+ <div id="toggle" style="toggle: test">
+ <div id="div"></div>
+ </div>
+ `;
+ let toggle = document.getElementById("toggle");
+ await wait_for_toggle_creation(toggle);
+ assert_true(!toggle.matches(`:toggle(test)`), "value before click");
+ document.getElementById("div").click();
+ assert_true(toggle.matches(`:toggle(test)`), "value after inner div click");
+ toggle.click();
+ assert_true(!toggle.matches(`:toggle(test)`), "value after outer div click");
+}, "toggle activation on div inside element with toggle-trigger");
+
+</script>
diff --git a/testing/web-platform/tests/css/css-toggle/toggle-api.tentative.html b/testing/web-platform/tests/css/css-toggle/toggle-api.tentative.html
new file mode 100644
index 0000000000..f47ec55ed0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/toggle-api.tentative.html
@@ -0,0 +1,338 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: CSSToggle and CSSToggleMap API</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#dom">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/toggle-helpers.js"></script>
+
+<div id="test"></div>
+
+<script>
+
+let container = document.getElementById("test");
+
+promise_test(async function() {
+ container.innerHTML = `
+ <style>
+ :toggle(mytoggle) { --t:4; }
+ :toggle(newtoggle) { --t:7; }
+ :toggle(newname) { --t:9; }
+ </style>
+ <div>
+ <div id="a" style="toggle-root: mytoggle 2 at 1 self"></div>
+ </div>
+ <div>
+ <div id="b"></div>
+ </div>
+ `;
+ let a = document.getElementById("a");
+ let b = document.getElementById("b");
+ assert_equals(a.toggles.size, 0, "a.toggles.size before creation");
+ assert_equals(b.toggles.size, 0, "b.toggles.size before creation");
+ await wait_for_toggle_creation(a);
+ assert_equals(a.toggles.size, 1, "a.toggles.size after creation");
+ assert_equals(b.toggles.size, 0, "b.toggles.size after creation");
+ let t = a.toggles.get("mytoggle");
+ for (let item of a.toggles) {
+ assert_equals(item[0], "mytoggle", "iteration of a.toggles");
+ assert_equals(item[1], t, "iteration of a.toggles");
+ }
+ for (let item of a.toggles.entries()) {
+ assert_equals(item[0], "mytoggle", "iteration of a.toggles.entries()");
+ assert_equals(item[1], t, "iteration of a.toggles.entries()");
+ }
+ for (let item of a.toggles.keys()) {
+ assert_equals(item, "mytoggle", "iteration of a.toggles.keys()");
+ }
+ for (let item of a.toggles.values()) {
+ assert_equals(item, t, "iteration of a.toggles.values()");
+ }
+ assert_equals(Object.getPrototypeOf(a.toggles), CSSToggleMap.prototype);
+ assert_equals(Object.getPrototypeOf(t), CSSToggle.prototype);
+ let computed = (element) => getComputedStyle(element).getPropertyValue("--t");
+ assert_equals(computed(a), "4", "computed style before move");
+ assert_equals(computed(b), "", "computed style before move");
+
+ b.toggles.set("newtoggle", t);
+ assert_equals(a.toggles.size, 0, "a.toggles.size after move");
+ assert_equals(b.toggles.size, 1, "b.toggles.size after move");
+ assert_equals(computed(a), "", "computed style after move");
+ assert_equals(computed(b), "7", "computed style after move");
+
+ assert_equals(a.toggles.get("mytoggle"), undefined, 'a.toggles.get("mytoggle") after move');
+ assert_equals(a.toggles.get("newtoggle"), undefined, 'a.toggles.get("newtoggle") after move');
+ assert_equals(b.toggles.get("mytoggle"), undefined, 'b.toggles.get("mytoggle") after move');
+ assert_equals(b.toggles.get("newtoggle"), t, 'b.toggles.get("newtoggle") after move');
+
+ b.toggles.set("newname", t);
+ assert_equals(a.toggles.size, 0, "a.toggles.size after rename");
+ assert_equals(b.toggles.size, 1, "b.toggles.size after rename");
+ assert_equals(computed(a), "", "computed style after rename");
+ assert_equals(computed(b), "9", "computed style after rename");
+ assert_equals(a.toggles.get("mytoggle"), undefined, 'a.toggles.get("mytoggle") after rename');
+ assert_equals(a.toggles.get("newtoggle"), undefined, 'a.toggles.get("newtoggle") after rename');
+ assert_equals(a.toggles.get("newname"), undefined, 'a.toggles.get("newname") after rename');
+ assert_equals(b.toggles.get("mytoggle"), undefined, 'b.toggles.get("mytoggle") after rename');
+ assert_equals(b.toggles.get("newtoggle"), undefined, 'b.toggles.get("newtoggle") after rename');
+ assert_equals(b.toggles.get("newname"), t, 'b.toggles.get("newname") after rename');
+
+ assert_throws_dom("SyntaxError", () => { a.toggles.set("none", t); },
+ "setting toggle_name to 'none'");
+ assert_equals(a.toggles.size, 0, "a.toggles.size after failed set");
+ assert_equals(b.toggles.size, 1, "b.toggles.size after failed set");
+ assert_equals(b.toggles.get("newname"), t, "b.toggles.get after failed set");
+
+ assert_throws_dom("SyntaxError", () => { let t = new CSSToggle({ "states": [] }); },
+ "toggle constructor with empty list of states");
+ assert_throws_dom("SyntaxError", () => { let t = new CSSToggle({ "states": ["one"] }); },
+ "toggle constructor with only one state");
+ assert_throws_dom("SyntaxError", () => { let t = new CSSToggle({ "states": ["one", "two", "one"] }); },
+ "toggle constructor with duplicate states");
+ let c = new CSSToggle({ "states": ["one", "two", "three"] });
+ assert_throws_dom("SyntaxError", () => { c.states = []; },
+ "toggle states setter with empty list of states");
+ assert_throws_dom("SyntaxError", () => { c.states = ["one"]; },
+ "toggle states setter with only one state");
+ assert_throws_dom("SyntaxError", () => { c.states = ["one", "two", "one"]; },
+ "toggle states setter with duplicate states");
+
+ // TODO(https://crbug.com/1250716): Should the toggle on a be
+ // re-created at some point? If so, when?
+
+}, "CSSToggleMap basic API usage and moving toggle");
+
+promise_test(async function() {
+ container.innerHTML = `
+ <style>
+ :toggle(mytoggle 0) { --t:0; }
+ :toggle(mytoggle 1) { --t:1; }
+ :toggle(mytoggle 2) { --t:2; }
+ :toggle(mytoggle 3) { --t:3; }
+ :toggle(mytoggle 4) { --t:4; }
+ </style>
+ <div id="a" style="toggle: mytoggle 2 at 1 self"></div>
+ <div id="b"></div>
+ `;
+ let a = document.getElementById("a");
+ let b = document.getElementById("b");
+ let computed = (elt) => getComputedStyle(elt).getPropertyValue("--t");
+
+ await wait_for_toggle_creation(a);
+ let t = a.toggles.get("mytoggle");
+
+ assert_equals(computed(a), "1", "initial state of toggle");
+ assert_equals(t.value, 1, "CSSToggle.value in initial state");
+ assert_equals(t.valueAsNumber, 1, "CSSToggle.valueAsNumber in initial state");
+ assert_equals(t.valueAsString, null, "CSSToggle.valueAsString in initial state");
+ assert_equals(t.states, 2, "CSSToggle.states in initial state");
+ assert_equals(t.group, false, "CSSToggle.group in initial state");
+ assert_equals(t.scope, "narrow", "CSSToggle.scope in initial state");
+ assert_equals(t.cycle, "cycle", "CSSToggle.cycle in initial state");
+ a.click();
+ assert_equals(computed(a), "2", "state of toggle after click");
+ assert_equals(t.value, 2, "CSSToggle.value after click");
+ assert_equals(t.valueAsNumber, 2, "CSSToggle.valueAsNumber after click");
+ assert_equals(t.valueAsString, null, "CSSToggle.valueAsString after click");
+
+ t.value = 1;
+ assert_equals(computed(a), "1", "state after setting value");
+ assert_equals(t.value, 1, "CSSToggle.value after setting value");
+ assert_equals(t.valueAsNumber, 1, "CSSToggle.valueAsNumber after setting value");
+ assert_equals(t.valueAsString, null, "CSSToggle.valueAsString after setting value");
+
+ t.states = ["zero", "one", "two", "three", "four"]
+ assert_equals(computed(a), "1", "state after setting states");
+ assert_equals(t.value, 1, "CSSToggle.value after setting states");
+ assert_equals(t.valueAsNumber, 1, "CSSToggle.valueAsNumber after setting states");
+ assert_equals(t.valueAsString, "one", "CSSToggle.valueAsString after setting states");
+
+ t.value = "three";
+ assert_equals(computed(a), "3", "state after changing value with new states");
+ assert_equals(t.value, "three", "CSSToggle.value after changing value with new states");
+ assert_equals(t.valueAsNumber, 3, "CSSToggle.valueAsNumber after changing value with new states");
+ assert_equals(t.valueAsString, "three", "CSSToggle.valueAsString after changing value with new states");
+
+ // dynamic changes to group are tested in a separate test below
+
+ assert_equals(computed(a), "3", "a state before changing scope");
+ assert_equals(computed(b), "", "b state before changing scope");
+ t.scope = "wide";
+ assert_equals(computed(a), "3", "a state after changing scope");
+ assert_equals(computed(b), "3", "b state after changing scope");
+ t.scope = "narrow";
+ assert_equals(computed(a), "3", "a state after changing scope again");
+ assert_equals(computed(b), "", "b state after changing scope again");
+
+ t.value = 4;
+ assert_equals(computed(a), "4", "state after changing value again")
+ a.click();
+ assert_equals(computed(a), "0", "state after cycling with initial cycle")
+ t.value = 4;
+ t.cycle = "cycle-on";
+ assert_equals(computed(a), "4", "state after changing cycle to cycle-on, with toggle-root still set")
+ a.click();
+ assert_equals(computed(a), "0", "state after cycling with cycle-on, with toggle-root still set")
+ // now remove the toggle-root property so that it no longer overrides the
+ // toggle when changing a toggle.
+ a.style.toggleRoot = "";
+ t.value = 4;
+ t.cycle = "cycle-on";
+ assert_equals(computed(a), "4", "state after changing cycle to cycle-on")
+ a.click();
+ assert_equals(computed(a), "1", "state after cycling with cycle-on")
+ t.value = 4;
+ t.cycle = "sticky";
+ assert_equals(computed(a), "4", "state after changing cycle to sticky")
+ a.click();
+ assert_equals(computed(a), "4", "state after cycling with sticky")
+ t.value = 4;
+ t.cycle = "cycle";
+ assert_equals(computed(a), "4", "state after changing cycle to cycle")
+ a.click();
+ assert_equals(computed(a), "0", "state after cycling with cycle")
+}, "CSSToggle basic API usage on existing toggle");
+
+
+promise_test(async function() {
+ container.innerHTML = `
+ <style>
+ :toggle(grouptoggle 0) { --g:0; }
+ :toggle(grouptoggle 1) { --g:1; }
+ :toggle(grouptoggle 2) { --g:2; }
+ </style>
+ <!-- use the document-wide implicit toggle group -->
+ <div id="a" style="toggle: grouptoggle 2 at 1 self cycle-on"></div>
+ <div id="b" style="toggle: grouptoggle 2 at 1 self cycle-on"></div>
+ `;
+ let a = document.getElementById("a");
+ let b = document.getElementById("b");
+ let computed = (elt) => getComputedStyle(elt).getPropertyValue("--g");
+
+ await wait_for_toggle_creation(a);
+ await wait_for_toggle_creation(b);
+ let ta = a.toggles.get("grouptoggle");
+ let tb = b.toggles.get("grouptoggle");
+
+ assert_equals(computed(a), "1", "initial state of a");
+ assert_equals(computed(b), "1", "initial state of b");
+ assert_equals(ta.group, false, "initial group of a");
+ assert_equals(tb.group, false, "initial group of b");
+
+ // Remove the toggle-root property so it doesn't override the group
+ // on the toggle.
+ a.style.toggleRoot = "";
+ b.style.toggleRoot = "";
+
+ ta.group = true;
+ a.click();
+ assert_equals(computed(a), "2", "state of a after first click");
+ assert_equals(computed(b), "1", "state of b after first click");
+
+ tb.group = true;
+ assert_equals(computed(a), "2", "state of a after both in group");
+ assert_equals(computed(b), "1", "state of b after both in group");
+ a.click();
+ assert_equals(computed(a), "1", "state of a after second click");
+ assert_equals(computed(b), "0", "state of b after second click");
+ b.click();
+ assert_equals(computed(a), "0", "state of a after third click");
+ assert_equals(computed(b), "1", "state of b after third click");
+ ta.group = false;
+ a.click();
+ assert_equals(computed(a), "1", "state of a after fourth click");
+ assert_equals(computed(b), "1", "state of b after fourth click");
+
+ ta.group = true;
+ tb.group = true;
+ a.click();
+ assert_equals(computed(a), "2", "state of a after fifth click");
+ assert_equals(computed(b), "0", "state of b after fifth click");
+ // Put the toggle-root property back so that it overrides the group
+ // on the toggle, but only when changing *that* toggle.
+ b.style.toggleRoot = "grouptoggle 2 at 1 self cycle-on";
+ b.click();
+ assert_equals(computed(a), "2", "state of a after sixth click");
+ assert_equals(computed(b), "1", "state of b after sixth click");
+ a.click();
+ assert_equals(computed(a), "1", "state of a after seventh click");
+ assert_equals(computed(b), "0", "state of b after seventh click");
+}, "CSSToggle usage of group setter on existing toggle");
+
+promise_test(async function() {
+ container.innerHTML = `
+ <style>
+ :toggle(d 0) { --d:0; }
+ :toggle(d 1) { --d:1; }
+ :toggle(d 2) { --d:2; }
+ :toggle(e 0) { --e:0; }
+ :toggle(e 1) { --e:1; }
+ :toggle(e 2) { --e:2; }
+ :toggle(f 0) { --f:0; }
+ :toggle(f 1) { --f:1; }
+ :toggle(f 2) { --f:2; }
+ </style>
+ <div id="a"></div>
+ <!-- TODO(https://crbug.com/1250716): This toggle-trigger should probably
+ also work if I set it dynamically right before the first click. -->
+ <div id="b" style="toggle-trigger: d next, e prev"></div>
+ `;
+ let a = document.getElementById("a");
+ let b = document.getElementById("b");
+ assert_equals(a.toggles.size, 0, "a.toggles.size before creation");
+ assert_equals(b.toggles.size, 0, "b.toggles.size before creation");
+
+ let computed = (elt, prop) => getComputedStyle(elt).getPropertyValue(`--${prop}`);
+
+ assert_equals(computed(a, "d"), "", "initial computed(a, d)");
+ assert_equals(computed(a, "e"), "", "initial computed(a, e)");
+ assert_equals(computed(b, "d"), "", "initial computed(b, d)");
+ assert_equals(computed(b, "e"), "", "initial computed(b, e)");
+
+ let t1 = new CSSToggle({states: 2, cycle: "cycle-on"});
+ let t2 = new CSSToggle({states: 2, value: 1, scope: "narrow"});
+
+ a.toggles.set("d", t1);
+ assert_equals(a.toggles.size, 1, "step 2 a.toggles.size");
+ assert_equals(b.toggles.size, 0, "step 2 b.toggles.size");
+ assert_equals(computed(a, "d"), "0", "step 2 computed(a, d)");
+ assert_equals(computed(b, "d"), "0", "step 2 computed(b, d)");
+ assert_equals(computed(a, "e"), "", "step 2 computed(a, e)");
+ assert_equals(computed(b, "e"), "", "step 2 computed(b, e)");
+
+ b.toggles.set("e", t2);
+ assert_equals(a.toggles.size, 1, "step 3 a.toggles.size");
+ assert_equals(b.toggles.size, 1, "step 3 b.toggles.size");
+ assert_equals(computed(a, "d"), "0", "step 3 computed(a, d)");
+ assert_equals(computed(b, "d"), "0", "step 3 computed(b, d)");
+ assert_equals(computed(a, "e"), "", "step 3 computed(a, e)");
+ assert_equals(computed(b, "e"), "1", "step 3 computed(b, e)");
+
+ b.click();
+ assert_equals(computed(a, "d"), "1", "step 4 computed(a, d)");
+ assert_equals(computed(b, "d"), "1", "step 4 computed(b, d)");
+ assert_equals(computed(a, "e"), "", "step 4 computed(a, e)");
+ assert_equals(computed(b, "e"), "0", "step 4 computed(b, e)");
+
+ a.toggles.set("f", t2);
+ assert_equals(a.toggles.size, 2, "step 5 a.toggles.size");
+ assert_equals(b.toggles.size, 0, "step 5 b.toggles.size");
+ assert_equals(computed(a, "d"), "1", "step 5 computed(a, d)");
+ assert_equals(computed(b, "d"), "1", "step 5 computed(b, d)");
+ assert_equals(computed(a, "e"), "", "step 5 computed(a, e)");
+ assert_equals(computed(b, "e"), "", "step 5 computed(b, e)");
+ assert_equals(computed(a, "f"), "0", "step 5 computed(a, f)");
+ assert_equals(computed(b, "f"), "", "step 5 computed(b, f)");
+
+ b.click();
+ assert_equals(computed(a, "d"), "2", "step 6 computed(a, d)");
+ assert_equals(computed(b, "d"), "2", "step 6 computed(b, d)");
+ assert_equals(computed(a, "e"), "", "step 6 computed(a, e)");
+ assert_equals(computed(b, "e"), "", "step 6 computed(b, e)");
+ assert_equals(computed(a, "f"), "0", "step 6 computed(a, f)");
+ assert_equals(computed(b, "f"), "", "step 6 computed(b, f)");
+}, "dynamic creation of CSSToggle and their use");
+
+</script>
diff --git a/testing/web-platform/tests/css/css-toggle/toggle-creation.tentative.html b/testing/web-platform/tests/css/css-toggle/toggle-creation.tentative.html
new file mode 100644
index 0000000000..583e1631d3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/toggle-creation.tentative.html
@@ -0,0 +1,73 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: creation of toggles</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-root-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/toggle-helpers.js"></script>
+
+<body>
+
+<div id="container"></div>
+<script>
+
+let container = document.getElementById("container");
+
+promise_test(async () => {
+ container.innerHTML = '<div id="t" style="toggle: mytoggle"></div>';
+ let t = document.getElementById("t");
+ await wait_for_toggle_creation(t);
+ assert_false(t.matches(':toggle(mytoggle)'));
+ assert_true(t.matches(':toggle(mytoggle 0)'));
+ assert_false(t.matches(':toggle(mytoggle 1)'));
+ t.click();
+ assert_true(t.matches(':toggle(mytoggle)'));
+ assert_false(t.matches(':toggle(mytoggle 0)'));
+ assert_true(t.matches(':toggle(mytoggle 1)'));
+ t.click();
+ assert_true(t.matches(':toggle(mytoggle 0)'));
+ assert_false(t.matches(':toggle(mytoggle 1)'));
+}, "basic toggle creation");
+
+promise_test(async () => {
+ // Test that changing the toggle-root property to add 'self' doesn't change
+ // the toggle's scope from wide to narrow.
+ container.innerHTML = `
+ <div id="a" style="toggle-root: changing-scope 3 at 2">
+ <div id="b" style="toggle-trigger: changing-scope"></div>
+ </div>
+ <div id="c"></div>
+ `;
+ let a = document.getElementById("a");
+ let b = document.getElementById("b");
+ let c = document.getElementById("c");
+ await wait_for_toggle_creation(a);
+ assert_true(b.matches(':toggle(changing-scope 2)'));
+ assert_true(c.matches(':toggle(changing-scope 2)'));
+ a.style.toggleRoot = "changing-scope 3 at 2 self";
+ await wait_for_toggle_creation(a);
+ assert_true(b.matches(':toggle(changing-scope 2)'));
+ assert_true(c.matches(':toggle(changing-scope 2)'));
+
+ // The reverse -- removing 'self'.
+ container.innerHTML = `
+ <div id="a" style="toggle-root: changing-scope 3 at 2 self">
+ <div id="b" style="toggle-trigger: changing-scope"></div>
+ </div>
+ <div id="c"></div>
+ `;
+ a = document.getElementById("a");
+ b = document.getElementById("b");
+ c = document.getElementById("c");
+ await wait_for_toggle_creation(a);
+ assert_true(b.matches(':toggle(changing-scope 2)'));
+ assert_false(c.matches(':toggle(changing-scope 2)'));
+ a.style.toggleRoot = "changing-scope 3 at 2";
+ await wait_for_toggle_creation(a);
+ assert_true(b.matches(':toggle(changing-scope 2)'));
+ assert_false(c.matches(':toggle(changing-scope 2)'));
+}, "changing toggle-root doesn't change toggle");
+
+</script>
diff --git a/testing/web-platform/tests/css/css-toggle/toggle-events.tentative.html b/testing/web-platform/tests/css/css-toggle/toggle-events.tentative.html
new file mode 100644
index 0000000000..bc4db7d5f6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/toggle-events.tentative.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: CSSToggle and CSSToggleMap API</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#csstoggleevent">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/toggle-helpers.js"></script>
+
+<div id="test"></div>
+
+<script>
+
+let container = document.getElementById("test");
+
+function click_while_waiting_for_togglechange(event_watcher, element) {
+ let p = event_watcher.wait_for("togglechange");
+ element.click();
+ return p;
+}
+
+promise_test(async test => {
+ container.innerHTML = `
+ <div id="element" style="toggle: mytoggle 2 at 1 self sticky"></div>
+ `;
+ const element = document.getElementById("element");
+
+ await wait_for_toggle_creation(element);
+ let toggle = element.toggles.get("mytoggle");
+
+ assert_equals(toggle.value, 1, "initial value of toggle");
+
+ const watcher = new EventWatcher(test, element, [ "togglechange" ]);
+
+ await click_while_waiting_for_togglechange(watcher, element).then(ev => {
+ assert_equals(Object.getPrototypeOf(ev), CSSToggleEvent.prototype);
+ assert_equals(ev.toggleName, "mytoggle", "event.toggleName after first change");
+ assert_equals(ev.toggle, toggle, "event.toggle after first change");
+ assert_equals(toggle.value, 2, "value after first change");
+ });
+
+ // Test that the event does not fire when the toggle doesn't change due to
+ // being "sticky" and stuck. EventWatcher will assert if there is an event.
+ element.click();
+ assert_equals(toggle.value, 2, "value after second change");
+
+ toggle.value = 0;
+ // there should be no event; EventWatcher will assert if there is one.
+}, "basic toggle event firing");
+
+</script>
diff --git a/testing/web-platform/tests/css/css-toggle/toggle-pseudo-class.tentative.html b/testing/web-platform/tests/css/css-toggle/toggle-pseudo-class.tentative.html
new file mode 100644
index 0000000000..7fb5c26d91
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/toggle-pseudo-class.tentative.html
@@ -0,0 +1,235 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: creation of toggles</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#checked-pseudoclass">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../support/parsing-testcommon.js"></script>
+<script src="support/toggle-helpers.js"></script>
+
+<body>
+
+<div id="container"></div>
+
+<script>
+
+test_valid_selector(":toggle(my-toggle)");
+test_valid_selector(":toggle(my-toggle 0)");
+test_valid_selector(":toggle(my-toggle 1)");
+test_valid_selector(":toggle( my-toggle 1 )", ":toggle(my-toggle 1)");
+test_valid_selector(":toggle(my-toggle named-state)");
+test_valid_selector(":toggle( my-toggle named-state )", ":toggle(my-toggle named-state)");
+test_invalid_selector(":toggle(my-toggle, 0)");
+test_invalid_selector(":toggle(my-toggle, named-state)");
+test_invalid_selector(":toggle(my-toggle named-state 0)");
+
+// In these tests, the following class attributes lead to markup creation:
+// class=toggle, class=toggle-self, class=variant-toggle,
+// class=variant-toggle-self. These all lead to the creation of a toggle
+// called "markup-test". If "-self" is present then the toggle has narrow
+// scope (otherwise wide scope). If "variant-" is present then the toggle has
+// a value different from what the primary test assertions target (otherwise
+// it is what the test assertions target).
+//
+// The following class attributes lead to test assertions:
+// class=assert-match: Assert the :toggle() selector matches the toggle
+// class=assert-no-match: Assert the :toggle() selector does not match the
+// toggle.
+// class=assert-variant-match: Assert the :toggle() selector matches the
+// variant toggle.
+let scope_search_tests = [
+ `
+ <div>
+ <div class="assert-no-match"></div>
+ <div class="toggle assert-match">
+ <div class="assert-match"></div>
+ </div>
+ <div class="assert-match"></div>
+ </div>
+ <div class="assert-no-match"></div>
+ `,
+ `
+ <div>
+ <div class="assert-no-match"></div>
+ <div class="toggle-self assert-match">
+ <div class="assert-match"></div>
+ </div>
+ <div class="assert-no-match"></div>
+ </div>
+ <div class="assert-no-match"></div>
+ `,
+ `
+ <div class="toggle"></div>
+ <div class="variant-toggle-self">
+ <div class="assert-variant-match"></div>
+ </div>
+ <div class="assert-match"></div>
+ `,
+ `
+ <div class="toggle"></div>
+ <div class="assert-match"></div>
+ <div class="variant-toggle">
+ <div class="assert-variant-match"></div>
+ </div>
+ <div class="assert-variant-match"></div>
+ `,
+];
+
+for (let t of scope_search_tests) {
+ promise_test(async function() {
+ container.innerHTML = t;
+ for (let e of container.querySelectorAll(".toggle")) {
+ e.style.toggleRoot = "scope-test 10 at 3";
+ }
+ for (let e of container.querySelectorAll(".toggle-self")) {
+ e.style.toggleRoot = "scope-test 10 at 3 self";
+ }
+ for (let e of container.querySelectorAll(".variant-toggle")) {
+ e.style.toggleRoot = "scope-test 10 at 8";
+ }
+ for (let e of container.querySelectorAll(".variant-toggle-self")) {
+ e.style.toggleRoot = "scope-test 10 at 8 self";
+ }
+ for (let e of container.querySelectorAll(
+ ".toggle, .toggle-self, .variant-toggle, .variant-toggle-self")) {
+ await wait_for_toggle_creation(e);
+ }
+
+ let assert_match = (e, selector) => {
+ assert_true(e.matches(selector),
+ `matches ${selector} (class ${e.className})`);
+ };
+ let assert_nomatch = (e, selector) => {
+ assert_false(e.matches(selector),
+ `does not match ${selector} (class ${e.className})`);
+ };
+ for (let e of container.querySelectorAll(".assert-match")) {
+ assert_match(e, ":toggle(scope-test)");
+ assert_match(e, ":toggle(scope-test 3)");
+ assert_nomatch(e, ":toggle(scope-test 8)");
+ }
+ for (let e of container.querySelectorAll(".assert-variant-match")) {
+ assert_match(e, ":toggle(scope-test)");
+ assert_nomatch(e, ":toggle(scope-test 3)");
+ assert_match(e, ":toggle(scope-test 8)");
+ }
+ for (let e of container.querySelectorAll(".assert-no-match")) {
+ assert_nomatch(e, ":toggle(scope-test)");
+ assert_nomatch(e, ":toggle(scope-test 3)");
+ assert_nomatch(e, ":toggle(scope-test 8)");
+ }
+ }, `scope search test for markup ${t}`);
+}
+
+let selector_match_tests = [
+ {
+ specifier: [ "my-toggle 2 at 1" ],
+ matching_selectors: [
+ ":toggle(my-toggle)",
+ ":toggle(my-toggle 1)",
+ ],
+ not_matching_selectors: [
+ ":toggle(my-toggle 0)",
+ ":toggle(my-toggle 2)",
+ ":toggle(my-toggle named-state)",
+ ],
+ },
+ {
+ specifier: [ "my-toggle 2 at 0" ],
+ matching_selectors: [
+ ":toggle(my-toggle 0)",
+ ],
+ not_matching_selectors: [
+ ":toggle(my-toggle)",
+ ":toggle(my-toggle 1)",
+ ":toggle(my-toggle 2)",
+ ":toggle(my-toggle named-state)",
+ ],
+ },
+ {
+ specifier: [ "my-toggle 2 at named-state" ],
+ matching_selectors: [
+ ":toggle(my-toggle)",
+ ":toggle(my-toggle named-state)",
+ ],
+ not_matching_selectors: [
+ ":toggle(my-toggle 0)",
+ ":toggle(my-toggle 1)",
+ ":toggle(my-toggle 2)",
+ ":toggle(my-toggle infinite)",
+ ":toggle(my-toggle infinity)",
+ ],
+ },
+ {
+ specifier: [
+ "my-toggle [a b c d] at 0",
+ "my-toggle [a b c d] at a",
+ ],
+ matching_selectors: [
+ ":toggle(my-toggle 0)",
+ ":toggle(my-toggle a)",
+ ],
+ not_matching_selectors: [
+ ":toggle(my-toggle)",
+ ":toggle(my-toggle 1)",
+ ":toggle(my-toggle 2)",
+ ":toggle(my-toggle b)",
+ ":toggle(my-toggle d)",
+ ":toggle(my-toggle named-state)",
+ ],
+ },
+ {
+ specifier: [
+ "my-toggle [a b c d] at 1",
+ "my-toggle [a b c d] at b",
+ ],
+ matching_selectors: [
+ ":toggle(my-toggle)",
+ ":toggle(my-toggle 1)",
+ ":toggle(my-toggle b)",
+ ],
+ not_matching_selectors: [
+ ":toggle(my-toggle 0)",
+ ":toggle(my-toggle a)",
+ ":toggle(my-toggle 2)",
+ ":toggle(my-toggle d)",
+ ":toggle(my-toggle named-state)",
+ ],
+ },
+ {
+ specifier: [
+ "my-toggle [a b c d] at unnamed-state",
+ ],
+ matching_selectors: [
+ ":toggle(my-toggle)",
+ ":toggle(my-toggle unnamed-state)",
+ ],
+ not_matching_selectors: [
+ ":toggle(my-toggle 0)",
+ ":toggle(my-toggle a)",
+ ":toggle(my-toggle 1)",
+ ":toggle(my-toggle c)",
+ ":toggle(my-toggle 3)",
+ ],
+ },
+];
+
+for (let t of selector_match_tests) {
+ for (let specifier of t.specifier) {
+ promise_test(async function() {
+ container.innerHTML = `<div style="toggle-root: ${specifier}"></div>`;
+ let e = container.firstChild;
+ await wait_for_toggle_creation(e);
+ for (let sel of t.matching_selectors) {
+ assert_true(e.matches(sel), `${sel} matches`);
+ }
+ for (let sel of t.not_matching_selectors) {
+ assert_false(e.matches(sel), `${sel} does not match`);
+ }
+ }, `:toggle() selector matching tests for ${specifier}`);
+ }
+}
+
+</script>
diff --git a/testing/web-platform/tests/css/css-toggle/toggle-shorthand-serialization.tentative.html b/testing/web-platform/tests/css/css-toggle/toggle-shorthand-serialization.tentative.html
new file mode 100644
index 0000000000..682945c2e2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/toggle-shorthand-serialization.tentative.html
@@ -0,0 +1,77 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: serialization of toggle shorthand</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+<script>
+
+let tests = [
+ { "toggle-root": null,
+ "toggle-trigger": "mytoggle",
+ "expected": "" },
+ { "toggle-root": "mytoggle",
+ "toggle-trigger": null,
+ "expected": "" },
+ { "toggle-root": "none",
+ "toggle-trigger": "mytoggle",
+ "expected": "" },
+ { "toggle-root": "mytoggle",
+ "toggle-trigger": "none",
+ "expected": "" },
+ { "toggle-root": "none",
+ "toggle-trigger": "none",
+ "expected": "none" },
+ { "toggle-root": "mytoggle",
+ "toggle-trigger": "mytoggle",
+ "expected": "mytoggle" },
+ { "toggle-root": "mytoggle, yourtoggle",
+ "toggle-trigger": "mytoggle",
+ "expected": "" },
+ { "toggle-root": "mytoggle",
+ "toggle-trigger": "mytoggle, yourtoggle",
+ "expected": "" },
+ { "toggle-root": "mytoggle 2",
+ "toggle-trigger": "mytoggle",
+ "expected": "mytoggle 2" },
+ { "toggle-root": "mytoggle 2",
+ "toggle-trigger": "mytoggle 2",
+ "expected": "" },
+ { "toggle-root": "mytoggle 2 at 1",
+ "toggle-trigger": "mytoggle",
+ "expected": "mytoggle 2 at 1" },
+ { "toggle-root": "mytoggle 2 at 1",
+ "toggle-trigger": "mytoggle 1",
+ "expected": "" },
+ { "toggle-root": "mytoggle 2 at 1",
+ "toggle-trigger": "mytoggle 2",
+ "expected": "" },
+ { "toggle-root": "mytoggle 2 at 1 sticky group self",
+ "toggle-trigger": "mytoggle",
+ "expected": "mytoggle 2 at 1 sticky group self" },
+ { "toggle-root": "mytoggle 4 at 2 self sticky group",
+ "toggle-trigger": "mytoggle",
+ "expected": "mytoggle 4 at 2 sticky group self" },
+ { "toggle-root": "mytoggle [one two three] at two self cycle-on group",
+ "toggle-trigger": "mytoggle",
+ "expected": "mytoggle [one two three] at two cycle-on group self" },
+];
+
+for (let t of tests) {
+ test(function() {
+ let element = document.createElement("div");
+ document.body.appendChild(element);
+ if (typeof(t["toggle-root"]) == "string")
+ element.style["toggle-root"] = t["toggle-root"];
+ if (typeof(t["toggle-trigger"]) == "string")
+ element.style["toggle-trigger"] = t["toggle-trigger"];
+ assert_equals(element.style.toggle, t["expected"]);
+ element.remove();
+ }, `Serialization of toggle shorthand with${t["toggle-root"] ? (" toggle-root: " + t["toggle-root"] + ";") : ""}${t["toggle-trigger"] ? (" toggle-trigger: " + t["toggle-trigger"] + ";") : ""}`);
+}
+
+</script>
diff --git a/testing/web-platform/tests/css/css-toggle/toggle-trigger-focus.tentative.html b/testing/web-platform/tests/css/css-toggle/toggle-trigger-focus.tentative.html
new file mode 100644
index 0000000000..bc93ba3631
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/toggle-trigger-focus.tentative.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: focusability of elements with toggle-trigger</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-trigger-property">
+<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="support/toggle-helpers.js"></script>
+
+<div id="test"></div>
+
+<script>
+
+// From shadow-dom/focus/resources/shadow-utils.js
+function navigateFocusForward() {
+ // TAB = '\ue004'
+ return test_driver.send_keys(document.body, "\ue004");
+}
+
+let container = document.getElementById("test");
+
+promise_test(async test => {
+ container.innerHTML = `
+ <input id="input" type="text">
+ <div id="e1" style="toggle-root: tab"></div>
+ <div id="e2" style="toggle-trigger: tab"></div>
+ <div id="e3" style="toggle-trigger: tab"></div>
+ <div id="e4" style="toggle-trigger: nonexistent"></div>
+ `;
+
+ let input = document.getElementById("input");
+ let e1 = document.getElementById("e1");
+ let e2 = document.getElementById("e2");
+ let e3 = document.getElementById("e3");
+ let e4 = document.getElementById("e4");
+
+ await wait_for_toggle_creation(e1);
+ input.focus();
+ assert_equals(document.activeElement, input);
+
+ await navigateFocusForward();
+ assert_equals(document.activeElement, e2);
+
+ await navigateFocusForward();
+ assert_equals(document.activeElement, e3);
+
+ await navigateFocusForward();
+ assert_equals(document.activeElement, e4);
+}, "elements with toggle-trigger are tabbable");
+
+</script>
diff --git a/testing/web-platform/tests/css/css-toggle/toggle-trigger-multiple.tentative.html b/testing/web-platform/tests/css/css-toggle/toggle-trigger-multiple.tentative.html
new file mode 100644
index 0000000000..bc972bd729
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/toggle-trigger-multiple.tentative.html
@@ -0,0 +1,92 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: triggering multiple toggles with a style change</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-trigger-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/toggle-helpers.js"></script>
+
+<div id="test"></div>
+
+<script>
+
+let container = document.getElementById("test");
+
+promise_test(async test => {
+ container.innerHTML = `
+ <style>
+ #t {
+ toggle-root: t1, t2, t3, t4;
+ toggle-trigger: t1, t2, t3;
+ }
+ </style>
+ <div id="t"></div>
+ `;
+ let t = document.getElementById("t");
+ await wait_for_toggle_creation(t);
+ assert_equals(t.toggles.size, 4, "t.toggles.size after creation");
+ assert_equals(t.toggles.get("t1").value, 0, "t1 after creation");
+ assert_equals(t.toggles.get("t2").value, 0, "t2 after creation");
+ assert_equals(t.toggles.get("t3").value, 0, "t3 after creation");
+ assert_equals(t.toggles.get("t4").value, 0, "t4 after creation");
+
+ let event_count = 0;
+ t.addEventListener("togglechange", event => {
+ switch (++event_count) {
+ case 1:
+ assert_equals(event.toggleName, "t1", "name of first event");
+ assert_equals(t.toggles.get("t1"), event.toggle);
+ assert_equals(t.toggles.get("t1").value, 1, "t1 after first event");
+ assert_equals(t.toggles.get("t2").value, 0, "t2 after first event");
+ assert_equals(t.toggles.get("t3").value, 0, "t3 after first event");
+ assert_equals(t.toggles.get("t4").value, 0, "t4 after first event");
+ break;
+ case 2:
+ assert_equals(event.toggleName, "t2", "name of second event");
+ assert_equals(t.toggles.get("t2"), event.toggle);
+ assert_equals(t.toggles.get("t1").value, 1, "t1 after second event");
+ assert_equals(t.toggles.get("t2").value, 1, "t2 after second event");
+ assert_equals(t.toggles.get("t3").value, 0, "t3 after second event");
+ assert_equals(t.toggles.get("t4").value, 0, "t4 after second event");
+ // This changes the value of 'toggle-trigger' in the middle of
+ // firing the toggle. We want to test that toggles continue firing
+ // as expected.
+ //
+ // It's constructed this way to avoid the old style being cached
+ // in Chromium's MatchedPropertiesCache, which allows this testcase
+ // to trigger a crash before the fix that introduced it.
+ t.previousElementSibling.sheet.cssRules[0].style.toggleTrigger = "t4";
+ // This assertion is mainly to force the style to be recomputed:
+ assert_equals(getComputedStyle(t).toggleTrigger, "t4");
+ break;
+ case 3:
+ assert_equals(event.toggleName, "t3", "name of third event");
+ assert_equals(t.toggles.get("t3"), event.toggle);
+ assert_equals(t.toggles.get("t1").value, 1, "t1 after third event");
+ assert_equals(t.toggles.get("t2").value, 1, "t2 after third event");
+ assert_equals(t.toggles.get("t3").value, 1, "t3 after third event");
+ assert_equals(t.toggles.get("t4").value, 0, "t4 after third event");
+ break;
+ case 4:
+ assert_equals(event.toggleName, "t4", "name of fourth event");
+ assert_equals(t.toggles.get("t4"), event.toggle);
+ assert_equals(t.toggles.get("t1").value, 1, "t1 after fourth event");
+ assert_equals(t.toggles.get("t2").value, 1, "t2 after fourth event");
+ assert_equals(t.toggles.get("t3").value, 1, "t3 after fourth event");
+ assert_equals(t.toggles.get("t4").value, 1, "t4 after fourth event");
+ break;
+ default:
+ assert_unreached("should get four events");
+ break;
+ }
+ });
+
+ t.click();
+ assert_equals(event_count, 3);
+ t.click();
+ assert_equals(event_count, 4);
+}, "triggering of multiple toggles with a change to toggle-trigger in the middle");
+
+</script>
diff --git a/testing/web-platform/tests/css/css-toggle/toggle-visibility-z-ordering-001.tentative.html b/testing/web-platform/tests/css/css-toggle/toggle-visibility-z-ordering-001.tentative.html
new file mode 100644
index 0000000000..50f5d35f19
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/toggle-visibility-z-ordering-001.tentative.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: toggle-visibility</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-visibility-property">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<style>
+
+body {
+ toggle-root: inactive-toggle 1 at 0;
+}
+
+#container {
+ toggle-visibility: toggle inactive-toggle;
+ background: green;
+ width: 100px;
+ height: 100px;
+}
+
+#child, #sibling {
+ height: 100px;
+ width: 100px;
+ background: red;
+}
+
+#sibling {
+ margin-top: -100px;
+}
+
+</style>
+
+<body>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+
+<div id="container">
+ <div id="child"></div>
+</div>
+<div id="sibling"></div>
diff --git a/testing/web-platform/tests/css/css-toggle/toggle-visibility-z-ordering-002.tentative.html b/testing/web-platform/tests/css/css-toggle/toggle-visibility-z-ordering-002.tentative.html
new file mode 100644
index 0000000000..cc1ecb2a9c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/toggle-visibility-z-ordering-002.tentative.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: toggle-visibility</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-visibility-property">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<style>
+
+body {
+ toggle-root: active-toggle 1 at 1;
+}
+
+#container {
+ toggle-visibility: toggle active-toggle;
+ background: red;
+ width: 100px;
+ height: 100px;
+}
+
+#child, #sibling {
+ height: 100px;
+ width: 100px;
+}
+
+#child {
+ background: green;
+}
+
+#sibling {
+ background: red;
+ margin-top: -100px;
+}
+
+</style>
+
+<body>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+
+<div id="container">
+ <div id="child"></div>
+</div>
+<div id="sibling"></div>
diff --git a/testing/web-platform/tests/css/css-toggle/toggle-visibility.tentative.html b/testing/web-platform/tests/css/css-toggle/toggle-visibility.tentative.html
new file mode 100644
index 0000000000..0a720fd454
--- /dev/null
+++ b/testing/web-platform/tests/css/css-toggle/toggle-visibility.tentative.html
@@ -0,0 +1,267 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: toggle-visibility</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-visibility-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/toggle-helpers.js"></script>
+<style id="style">
+
+</style>
+
+<body>
+
+<div id="container"></div>
+<script>
+
+let style = document.getElementById("style");
+let container = document.getElementById("container");
+
+promise_test(async function() {
+ style.innerText = `
+ #container { toggle-group: t self; }
+ #t, #t2 { toggle-root: t 1 at 0 group; }
+ #trigger, #t2 { toggle-trigger: t; }
+ #vis { toggle-visibility: toggle t; }
+ #child { height: 100px; }
+ `;
+ container.innerHTML = `
+ <div id="t"></div>
+ <div id="vis">
+ <div id="child"></div>
+ </div>
+ <div id="trigger"></div>
+ <div id="t2"></div>
+ `;
+
+ let t = document.getElementById("t");
+ let trigger = document.getElementById("trigger");
+ let t2 = document.getElementById("t2");
+ let vis = document.getElementById("vis");
+
+ await wait_for_toggle_creation(t);
+
+ const kVisibleHeight = 100;
+ const kHiddenHeight = 0;
+
+ assert_equals(vis.clientHeight, kHiddenHeight, "before first click");
+ trigger.click();
+ assert_equals(vis.clientHeight, kVisibleHeight, "after first click");
+ trigger.click();
+ assert_equals(vis.clientHeight, kHiddenHeight, "after second click");
+ t.toggles.get("t").value = 1;
+ assert_equals(vis.clientHeight, kVisibleHeight, "after toggle value setter");
+ t2.click();
+ assert_equals(vis.clientHeight, kHiddenHeight, "after click on other element in group");
+}, "showing and hiding in response to toggle changes");
+
+const action_tests = [
+ {
+ name: "focus",
+ markup: `<input type="checkbox" id="check">`,
+ action: () => {
+ document.getElementById("check").focus();
+ },
+ },
+ {
+ name: "scrollIntoView",
+ markup: `<input type="checkbox" id="check">`,
+ action: () => {
+ document.getElementById("check").scrollIntoView();
+ },
+ },
+];
+
+for (let test of action_tests) {
+ promise_test(async function() {
+ style.innerText = `
+ #container { toggle-group: tab self; }
+ #tab { toggle: tab 1 at 0 group; }
+ #panel { toggle-visibility: toggle tab; }
+ `;
+ container.innerHTML = `
+ <div id="tab">Tab</div>
+ <div id="panel">
+ ${test.markup}
+ </div>
+ `;
+
+ let tab = document.getElementById("tab");
+ let panel = document.getElementById("panel");
+
+ await wait_for_toggle_creation(tab);
+
+ let tab_toggle = tab.toggles.get("tab");
+
+ assert_equals(tab_toggle.value, 0, "toggle value before focus");
+ assert_equals(panel.clientHeight, 0, "panel height before focus");
+
+ test.action();
+
+ assert_equals(tab_toggle.value, 1, "toggle value after focus");
+ assert_not_equals(panel.clientHeight, 0, "panel height after focus");
+ }, `${test.name} inside hidden element changes a toggle to show it`);
+}
+
+const scope_tests = [
+ `
+ <div class="root-inactive">
+ <div class="vis expect-hidden"></div>
+ </div>
+ <div class="vis expect-hidden"></div>
+ `,
+ `
+ <div class="root-inactive-self">
+ <div class="vis expect-hidden"></div>
+ </div>
+ <div class="vis expect-shown"></div>
+ `,
+ `
+ <div class="root-active">
+ <div class="vis expect-shown"></div>
+ </div>
+ <div class="vis expect-shown"></div>
+ `,
+ `
+ <div class="root-active-self">
+ <div class="vis expect-shown"></div>
+ </div>
+ <div class="vis expect-shown"></div>
+ `,
+];
+
+for (let test of scope_tests) {
+ promise_test(async function() {
+ container.innerHTML = test;
+ style.innerText = `
+ .root-inactive { toggle-root: t 1 at 0; }
+ .root-active { toggle-root: t 1 at 1; }
+ .root-inactive-self { toggle-root: t 1 at 0 self; }
+ .root-active-self { toggle-root: t 1 at 1 self; }
+
+ .vis {
+ toggle-visibility: toggle t;
+ }
+
+ .vis::before {
+ content: "";
+ display: block;
+ height: 100px;
+ width: 100px;
+ }
+ `;
+
+ await wait_for_toggle_creation(container.querySelector('[class^="root-"]'));
+
+ for (let e of container.querySelectorAll('.expect-hidden')) {
+ assert_equals(e.clientHeight, 0);
+ }
+ for (let e of container.querySelectorAll('.expect-shown')) {
+ assert_equals(e.clientHeight, 100);
+ }
+ }, `scope test: ${test}`);
+}
+
+async function wait_for_content_visibility_auto() {
+ return new Promise(resolve => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(resolve);
+ });
+ });
+}
+
+promise_test(async function() {
+ style.innerText = `
+ #t { toggle-root: t 1 at 0; }
+ #vis {
+ toggle-visibility: toggle t;
+ content-visibility: auto;
+ min-height: 50px;
+ }
+ #child { height: 100px; }
+ #spacer { height: 300vh; }
+ `;
+ // TODO (dbaron): Why doesn't padding-top on #container have the same effect
+ // as this spacer?
+ container.innerHTML = `
+ <div id="spacer"></div>
+ <div id="t"></div>
+ <div id="vis">
+ <div id="child"></div>
+ </div>
+ `;
+
+ let t = document.getElementById("t");
+ let vis = document.getElementById("vis");
+ let spacer = document.getElementById("spacer");
+
+ await wait_for_toggle_creation(t);
+
+ let toggle = t.toggles.get("t");
+
+ const kVisibleHeight = 100;
+ const kHiddenHeight = 50;
+
+ await wait_for_content_visibility_auto();
+ assert_equals(vis.clientHeight, kHiddenHeight, "with toggle inactive and offscreen");
+ toggle.value = 1;
+ await wait_for_content_visibility_auto();
+ assert_equals(vis.clientHeight, kHiddenHeight, "with toggle active and offscreen");
+ spacer.remove();
+ await wait_for_content_visibility_auto();
+ assert_equals(vis.clientHeight, kVisibleHeight, "with toggle active and onscreen");
+ toggle.value = 0;
+ await wait_for_content_visibility_auto();
+ assert_equals(vis.clientHeight, kHiddenHeight, "with toggle inactive and onscreen");
+ toggle.value = 1;
+ await wait_for_content_visibility_auto();
+ assert_equals(vis.clientHeight, kVisibleHeight, "with toggle active and onscreen (2)");
+ toggle.value = 0;
+ t.before(spacer);
+ await wait_for_content_visibility_auto();
+ assert_equals(vis.clientHeight, kHiddenHeight, "with toggle inactive and offscreen (2)");
+ spacer.remove();
+ await wait_for_content_visibility_auto();
+ assert_equals(vis.clientHeight, kHiddenHeight, "with toggle inactive and onscreen (2)");
+ toggle.value = 1;
+ await wait_for_content_visibility_auto();
+ assert_equals(vis.clientHeight, kVisibleHeight, "with toggle active and onscreen (3)");
+ t.before(spacer);
+ await wait_for_content_visibility_auto();
+ assert_equals(vis.clientHeight, kHiddenHeight, "with toggle active and offscreen (2)");
+}, "interaction of toggle-visibility and content-visibility: auto");
+
+promise_test(async function() {
+ style.innerText = `
+ #t { toggle-root: t 1 at 0; }
+ #vis {
+ toggle-visibility: toggle t;
+ content-visibility: hidden;
+ }
+ #child { height: 100px; }
+ `;
+ container.innerHTML = `
+ <div id="t"></div>
+ <div id="vis">
+ <div id="child"></div>
+ </div>
+ `;
+
+ let t = document.getElementById("t");
+ let vis = document.getElementById("vis");
+
+ await wait_for_toggle_creation(t);
+
+ let toggle = t.toggles.get("t");
+
+ const kVisibleHeight = 100;
+ const kHiddenHeight = 0;
+
+ assert_equals(vis.clientHeight, kHiddenHeight, "with toggle inactive and offscreen");
+ toggle.value = 1;
+ assert_equals(vis.clientHeight, kHiddenHeight, "with toggle active and offscreen");
+}, "interaction of toggle-visibility and content-visibility: hidden");
+
+</script>