Tests: Import some custom-property tests

To make it easier to track progress and regressions in subsequent
changes.
This commit is contained in:
Sam Atkins 2025-07-01 11:43:24 +01:00 committed by Tim Ledbetter
commit 59f2c8df7a
Notes: github-actions[bot] 2025-07-09 15:46:45 +00:00
6 changed files with 844 additions and 0 deletions

View file

@ -0,0 +1,21 @@
<!DOCTYPE html>
<title>CSS Custom Properties: var() parsing</title>
<link rel="help" href="https://drafts.csswg.org/css-variables">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../../css/support/parsing-testcommon.js"></script>
<div id="target"></div>
<script>
test_valid_value('width', 'var(--x)');
test_valid_value('width', 'var(--x,)');
test_valid_value('width', 'var(--x, )');
test_invalid_value('width', 'var(--x ())');
test_invalid_value('width', 'var(--x () )');
test_invalid_value('width', 'var(--x() )');
test_invalid_value('width', 'var(--x (),)');
test_invalid_value('width', 'var(--x(),)');
</script>

View file

@ -0,0 +1,331 @@
<!DOCTYPE html>
<head>
<title>CSS Custom Properties: Using CSS-wide keywords</title>
<link rel="help" href="https://drafts.csswg.org/css-variables/#defining-variables">
<meta name="assert" content="The CSS-wide keywords can be used in custom properties, with the same meaning as in any another property." />
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<style>
body {
--is-initial: initial;
--should-not-inherit: tomato;
--should-inherit: lightgreen;
--registered-inherits-should-not-inherit: tomato;
--registered-should-not-inherit: tomato;
--registered-inherits-should-inherit: lightgreen;
--registered-should-inherit: lightgreen;
--registered-should-revert: tomato;
--registered-inherits-should-revert: tomato;
}
@property --registered-inherits-should-not-inherit {
syntax: '<color>';
initial-value: lightgreen;
inherits: true;
}
@property --registered-should-not-inherit {
syntax: '<color>';
initial-value: lightgreen;
inherits: false;
}
@property --registered-inherits-should-inherit {
syntax: '<color>';
initial-value: tomato;
inherits: true;
}
@property --registered-should-inherit {
syntax: '<color>';
initial-value: tomato;
inherits: false;
}
@property --registered-should-revert {
syntax: '<color>';
initial-value: orange;
inherits: false;
}
@property --registered-inherits-should-revert {
syntax: '<color>';
initial-value: orange;
inherits: true;
}
</style>
<!-- Tests for values of unregistered custom properties -->
<div class="test" style="
background: var(--should-not-inherit, lightgreen);
--should-not-inherit: initial;
">
`initial` as a value for an unregistered custom property
</div>
<div class="test" style="
background: var(--should-inherit, tomato);
--should-inherit: inherit;
">
`inherit` as a value for an unregistered custom property
</div>
<div class="test" style="
background: var(--should-inherit, tomato);
--should-inherit: unset;
">
`unset` as a value for an unregistered custom property
</div>
<div class="test" style="
background: var(--should-inherit, tomato);
--should-inherit: revert;
">
`revert` as a value for an unregistered custom property
</div>
<style>
#regular-revert-layer {
@layer {
--should-not-inherit: lightgreen;
}
@layer {
--should-not-inherit: revert-layer;
}
}
</style>
<div class="test" id="regular-revert-layer" style="
background: var(--should-not-inherit);
">
`revert-layer` as a value for an unregistered custom property
</div>
<!-- Tests for values of registered custom properties -->
<div class="test" style="
background: var(--registered-should-not-inherit);
--registered-should-not-inherit: initial;
">
`initial` as a value for a non-inheriting registered custom property
</div>
<div class="test" style="
background: var(--registered-inherits-should-not-inherit);
--registered-inherits-should-not-inherit: initial;
">
`initial` as a value for an inheriting registered custom property
</div>
<div class="test" style="
background: var(--registered-should-inherit);
--registered-should-inherit: inherit;
">
`inherit` as a value for a non-inheriting registered custom property
</div>
<div class="test" style="
background: var(--registered-inherits-should-inherit);
--registered-inherits-should-inherit: inherit;
">
`inherit` as a value for an inheriting registered custom property
</div>
<div class="test" style="
background: var(--registered-should-not-inherit);
--registered-should-not-inherit: unset;
">
`unset` as a value for a non-inheriting registered custom property
</div>
<div class="test" style="
background: var(--registered-inherits-should-inherit);
--registered-inherits-should-inherit: unset;
">
`unset` as a value for an inheriting registered custom property
</div>
<div class="test" style="
background: var(--registered-should-not-inherit);
--registered-should-not-inherit: revert;
">
`revert` as a value for a non-inheriting registered custom property
</div>
<div class="test" style="
background: var(--registered-inherits-should-inherit);
--registered-inherits-should-inherit: revert;
">
`revert` as a value for an inheriting registered custom property
</div>
<style>
#registered-revert-layer {
@layer {
--registered-should-revert: lightgreen;
}
@layer {
--registered-should-revert: revert-layer;
}
}
</style>
<div class="test" id="registered-revert-layer" style="
background: var(--registered-should-revert);
">
`revert-layer` as a value for a non-inheriting registered custom property
</div>
<style>
#registered-revert-layer-inherits {
@layer {
--registered-inherits-should-revert: lightgreen;
}
@layer {
--registered-inherits-should-revert: revert-layer;
}
}
</style>
<div class="test" id="registered-revert-layer-inherits" style="
background: var(--registered-inherits-should-revert);
">
`revert-layer` as a value for an inheriting registered custom property
</div>
<!-- Tests for `var()` fallbacks of unregistered custom properties -->
<div class="test" style="
background: var(--should-not-inherit, lightgreen);
--should-not-inherit: var(--is-initial, initial);
">
`initial` as a `var()` fallback for an unregistered custom property
</div>
<div class="test" style="
background: var(--should-inherit, tomato);
--should-inherit: var(--is-initial, inherit);
">
`inherit` as a `var()` fallback for an unregistered custom property
</div>
<div class="test" style="
background: var(--should-inherit, tomato);
--should-inherit: var(--is-initial, unset);
">
`unset` as a `var()` fallback for an unregistered custom property
</div>
<div class="test" style="
background: var(--should-inherit, tomato);
--should-inherit: var(--is-initial, unset);
">
`revert` as a `var()` fallback for an unregistered custom property
</div>
<style>
#regular-fallback-revert-layer {
@layer {
--should-not-inherit: lightgreen;
}
@layer {
--should-not-inherit: var(--is-initial, revert-layer);
}
}
</style>
<div class="test" id="regular-fallback-revert-layer" style="
background: var(--should-not-inherit);
">
`revert-layer` as a `var()` fallback for an unregistered custom property
</div>
<!-- Tests for `var()` fallbacks of registered custom properties -->
<div class="test" style="
background: var(--registered-should-not-inherit);
--registered-should-not-inherit: var(--is-initial, initial);
">
`initial` as a `var()` fallback for a non-inheriting registered custom property
</div>
<div class="test" style="
background: var(--registered-inherits-should-not-inherit);
--registered-inherits-should-not-inherit: var(--is-initial, initial);
">
`initial` as a `var()` fallback for an inheriting registered custom property
</div>
<div class="test" style="
background: var(--registered-should-inherit);
--registered-should-inherit: var(--is-initial, inherit);
">
`inherit` as a `var()` fallback for a non-inheriting registered custom property
</div>
<div class="test" style="
background: var(--registered-inherits-should-inherit);
--registered-inherits-should-inherit: var(--is-initial, inherit);
">
`inherit` as a `var()` fallback for an inheriting registered custom property
</div>
<div class="test" style="
background: var(--registered-should-not-inherit);
--registered-should-not-inherit: var(--is-initial, unset);
">
`unset` as a `var()` fallback for a non-inheriting registered custom property
</div>
<div class="test" style="
background: var(--registered-inherits-should-inherit);
--registered-inherits-should-inherit: var(--is-initial, unset);
">
`unset` as a `var()` fallback for an inheriting registered custom property
</div>
<div class="test" style="
background: var(--registered-should-not-inherit);
--registered-should-not-inherit: var(--is-initial, revert);
">
`revert` as a `var()` fallback for a non-inheriting registered custom property
</div>
<div class="test" style="
background: var(--registered-inherits-should-inherit);
--registered-inherits-should-inherit: var(--is-initial, revert);
">
`revert` as a `var()` fallback for an inheriting registered custom property
</div>
<style>
#registered-fallback-revert-layer {
@layer {
--registered-should-revert: lightgreen;
}
@layer {
--registered-should-revert: var(--is-initial, revert-layer);
}
}
</style>
<div class="test" id="registered-fallback-revert-layer" style="
background: var(--registered-should-revert);
">
`revert-layer` as a `var()` fallback for a non-inheriting registered custom property
</div>
<style>
#registered-fallback-revert-layer-inherits {
@layer {
--registered-inherits-should-revert: lightgreen;
}
@layer {
--registered-inherits-should-revert: var(--is-initial, revert-layer);
}
}
</style>
<div class="test" id="registered-fallback-revert-layer-inherits" style="
background: var(--registered-inherits-should-revert);
">
`revert-layer` as a `var()` fallback for an inheriting registered custom property
</div>
<pre id="out"></pre>
<script>
[...document.querySelectorAll('.test')].map(el => test(() => assert_equals(getComputedStyle(el).getPropertyValue('background-color'), 'rgb(144, 238, 144)'), el.textContent.trim()));
</script>

View file

@ -0,0 +1,425 @@
<!DOCTYPE html>
<meta charset="utf8">
<title>Test that custom property cycles behave correctly</title>
<link rel="help" href="https://drafts.csswg.org/css-variables/#cycles">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<main id=main></main>
<script>
// Test that, for the given list of |declarations|, the computed values
// of properties listed in |expected_invalid| are invalid (i.e. empty string),
// and the computed values listed in |expected_valid| are *not* invalid
// (i.e. not the empty string).
function test_cycles(declarations, expected_invalid, expected_valid, description) {
test(() => {
let element = document.createElement('div');
try {
declarations.push('--sanity:valid');
element.style = declarations.join(';');
main.append(element);
let cs = getComputedStyle(element);
for (let e of expected_invalid)
assert_equals(cs.getPropertyValue(e), '', `${e}`);
for (let e of expected_valid)
assert_not_equals(cs.getPropertyValue(e), '', `${e}`);
assert_equals(cs.getPropertyValue('--sanity'), 'valid', '--sanity');
} finally {
element.remove();
}
}, description);
}
// (Diagrams produced with graph-easy).
// ┌───┐
// │ │ ───┐
// │ a │ │
// │ │ ◀──┘
// └───┘
test_cycles(
['--a:var(--a)'],
['--a'],
[],
'Self-cycle');
// ┌───┐
// │ a │ ◀┐
// └───┘ │
// │ │
// │ │
// ▼ │
// ┌───┐ │
// │ b │ ─┘
// └───┘
test_cycles(
[
'--a:var(--b)',
'--b:var(--a)',
],
['--a', '--b'],
[],
'Simple a/b cycle');
// ┌───┐
// │ a │ ◀┐
// └───┘ │
// │ │
// │ │
// ▼ │
// ┌───┐ │
// │ b │ │
// └───┘ │
// │ │
// │ │
// ▼ │
// ┌───┐ │
// │ c │ ─┘
// └───┘
test_cycles(
[
'--a:var(--b, cycle)',
'--b:var(--c, cycle)',
'--c:var(--a, cycle)',
],
['--a', '--b', '--c'],
[],
'Three-var cycle');
// ┌───┐
// │ x │
// └───┘
// │
// │
// ▼
// ┌───┐
// │ y │
// └───┘
// │
// │
// ▼
// ┌───┐
// │ a │ ◀┐
// └───┘ │
// │ │
// │ │
// ▼ │
// ┌───┐ │
// │ b │ │
// └───┘ │
// │ │
// │ │
// ▼ │
// ┌───┐ │
// │ c │ ─┘
// └───┘
test_cycles(
[
'--x:var(--y, valid)',
'--y:var(--a, valid)',
'--a:var(--b, cycle)',
'--b:var(--c, cycle)',
'--c:var(--a, cycle)',
],
['--a', '--b', '--c'],
['--x', '--y'],
'Cycle that starts in the middle of a chain');
// ┌───┐
// │ x │
// └───┘
// │
// │
// ▼
// ┌───┐
// │ a │ ◀┐
// └───┘ │
// │ │
// │ │
// ▼ │
// ┌───┐ │
// │ b │ │
// └───┘ │
// │ │
// │ │
// ▼ │
// ┌───┐ │
// │ c │ ─┘
// └───┘
// │
// │
// ▼
// ┌───┐
// │ y │
// └───┘
test_cycles(
[
'--x:var(--a, valid)',
'--a:var(--b, cycle)',
'--b:var(--c, cycle)',
'--c:var(--a, cycle) var(--y)',
'--y:valid'
],
['--a', '--b', '--c'],
['--x', '--y'],
'Cycle with extra edge');
// ┌───┐
// │ x │
// └───┘
// │
// │
// ▼
// ┌───┐
// │ a │ ◀┐
// └───┘ │
// │ │
// │ │
// ▼ │
// ┌───┐ ┌───┐ │
// │ y │ ◀── │ b │ │
// └───┘ └───┘ │
// │ │
// │ │
// ▼ │
// ┌───┐ │
// │ c │ ─┘
// └───┘
test_cycles(
[
'--x:var(--a, valid)',
'--a:var(--b, cycle)',
'--b:var(--c, cycle) var(--y)',
'--c:var(--a, cycle)',
'--y:valid'
],
['--a', '--b', '--c'],
['--x', '--y'],
'Cycle with extra edge (2)');
// ┌───┐
// │ x │
// └───┘
// │
// │
// ▼
// ┌───┐
// │ a │ ◀┐
// └───┘ │
// │ │
// │ │
// ▼ │
// ┌───┐ │
// │ b │ │
// └───┘ │
// │ │
// │ │
// ▼ │
// ┌───┐ │
// │ c │ ─┘
// └───┘
// │
// │
// ▼
// ┌───┐
// │ y │
// └───┘
// │
// │
// ▼
// ┌───┐
// │ z │
// └───┘
test_cycles(
[
'--x:var(--a, valid)',
'--a:var(--b, cycle)',
'--b:var(--c, cycle)',
'--c:var(--a, cycle) var(--y)',
'--y:var(--z)',
'--z:valid'
],
['--a', '--b', '--c'],
['--x', '--y', '--z'],
'Cycle with extra edge (3)');
// ┌───┐
// │ x │
// └───┘
// │
// │
// ▼
// ┌───┐
// │ a │ ◀┐
// └───┘ │
// │ │
// │ │
// ▼ │
// ┌───┐ │
// ┌▶ │ b │ ─┘
// │ └───┘
// │ │
// │ │
// │ ▼
// │ ┌───┐
// │ │ c │
// │ └───┘
// │ │
// │ │
// │ ▼
// │ ┌───┐
// └─ │ d │
// └───┘
test_cycles(
[
'--x:var(--a, valid)',
'--a:var(--b, cycle)',
'--b:var(--c, cycle) var(--a, cycle)',
'--c:var(--d, cycle)',
'--d:var(--b, cycle)',
],
['--a', '--b', '--c', '--d'],
['--x'],
'Cycle with secondary cycle');
// ┌───┐
// │ x │
// └───┘
// │
// │
// ▼
// ┌───┐
// │ a │ ◀┐
// └───┘ │
// │ │
// │ │
// ▼ │
// ┌───┐ │
// ┌▶ │ b │ │
// │ └───┘ │
// │ │ │
// │ │ │
// │ ▼ │
// │ ┌───┐ │
// │ │ c │ ─┘
// │ └───┘
// │ │
// │ │
// │ ▼
// │ ┌───┐
// └─ │ d │
// └───┘
// │
// │
// ▼
// ┌───┐
// │ y │
// └───┘
test_cycles(
[
'--x:var(--a, valid)',
'--a:var(--b, cycle)',
'--b:var(--c, cycle)',
'--c:var(--d, cycle) var(--a, cycle)',
'--d:var(--b, cycle) var(--y)',
'--y:valid'
],
['--a', '--b', '--c', '--d'],
['--x', '--y'],
'Cycle with overlapping secondary cycle');
// ┌──────────────┐
// │ │
// │ ┌───┐ │
// │ │ x │ │
// │ └───┘ │
// │ │ │
// │ │ │
// │ ▼ ▼
// ┌───┐ ┌────────┐ ┌───┐
// │ b │ ◀── │ a │ ──▶ │ y │
// └───┘ └────────┘ └───┘
// │ ▲
// │ │
// ▼ │
// ┌───┐ │
// │ c │ │
// └───┘ │
// │ │
// │ │
// ▼ │
// ┌───┐ │
// │ d │ ─┘
// └───┘
test_cycles(
[
'--x:var(--a, valid)',
'--a:var(--b, cycle) var(--y, valid) var(--c, cycle)',
'--b:var(--a, cycle) ',
'--c:var(--d, cycle)',
'--d:var(--a, cycle)',
'--y:valid',
],
['--a', '--b', '--c', '--d'],
['--x', '--y'],
'Cycle with deeper secondary cycle');
// If we cared about cycles in unused fallbacks,
// then --a/--b/--c would be in a cycle in this case:
//
// ┌───┐
// │ x │
// └───┘
// │
// │
// ▼
// ┌───┐
// ┌─────▶ │ a │ ─┐
// │ └───┘ │
// │ │ │
// │ │ │
// │ ▼ │
// │ ┌───┐ │
// │ ┌─ │ b │ │
// │ │ └───┘ │
// │ │ │ │
// │ │ │ │
// │ │ ▼ │
// │ │ ┌───┐ │
// └────┼─ │ c │ │
// │ └───┘ │
// │ │ │
// │ │ │
// │ ▼ │
// │ ┌───┐ │
// └▶ │ y │ ◀┘
// └───┘
//
// However, as of https://github.com/w3c/csswg-drafts/issues/11500,
// we no longer care about such cycles.
test_cycles(
[
'--x:var(--a, valid)',
'--a:var(--y, var(--b, cycle))',
'--b:var(--y, var(--c, cycle))',
'--c:var(--y, var(--a, cycle))',
'--y:valid'
],
[], // Nothing is invalid.
['--a', '--b', '--c', '--x', '--y'],
'Cycle in unused fallback');
</script>