Tests: Import some @property tests

This commit is contained in:
Sam Atkins 2025-10-14 14:02:30 +01:00
parent dab994c4f3
commit c619c90e23
4 changed files with 553 additions and 0 deletions

View File

@ -0,0 +1,112 @@
Harness status: OK
Found 106 tests
52 Pass
54 Fail
Pass Attribute 'syntax' returns expected value for ["<color>"]
Pass Attribute 'syntax' returns expected value for ["<color> | none"]
Pass Attribute 'syntax' returns expected value for ["<color># | <image> | none"]
Pass Attribute 'syntax' returns expected value for ["foo | <length>#"]
Pass Attribute 'syntax' returns expected value for ["foo | bar | baz"]
Pass Attribute 'syntax' returns expected value for ["notasyntax"]
Pass Attribute 'syntax' returns expected value for ["*"]
Pass Attribute 'syntax' returns expected value for [" * "]
Pass Attribute 'syntax' returns expected value for ["* "]
Pass Attribute 'syntax' returns expected value for [" * "]
Pass Attribute 'syntax' returns expected value for ["red"]
Pass Attribute 'syntax' makes the @property rule invalid for ["rgb(255, 0, 0)"]
Pass Attribute 'syntax' makes the @property rule invalid for [<color>]
Pass Attribute 'syntax' makes the @property rule invalid for [foo | bar]
Fail Attribute 'syntax' makes the @property rule invalid for ["default"]
Fail Attribute 'syntax' makes the @property rule invalid for ["Default"]
Fail Attribute 'syntax' makes the @property rule invalid for ["initial"]
Fail Attribute 'syntax' makes the @property rule invalid for ["Initial"]
Fail Attribute 'syntax' makes the @property rule invalid for ["inherit"]
Fail Attribute 'syntax' makes the @property rule invalid for ["Inherit"]
Fail Attribute 'syntax' makes the @property rule invalid for ["unset"]
Fail Attribute 'syntax' makes the @property rule invalid for ["Unset"]
Fail Attribute 'syntax' makes the @property rule invalid for ["revert"]
Fail Attribute 'syntax' makes the @property rule invalid for ["Revert"]
Fail Attribute 'syntax' makes the @property rule invalid for ["revert-layer"]
Fail Attribute 'syntax' makes the @property rule invalid for ["Revert-layer"]
Pass Attribute 'syntax' makes the @property rule invalid for ["foo bar"]
Pass Attribute 'syntax' makes the @property rule invalid for ["Foo <length>"]
Pass Attribute 'syntax' makes the @property rule invalid for ["foo, bar"]
Pass Attribute 'syntax' makes the @property rule invalid for ["<length> <percentage>"]
Pass Attribute 'syntax' makes the @property rule invalid for ["|<length>"]
Pass Attribute 'initial-value' returns expected value for [10px]
Pass Attribute 'initial-value' returns expected value for [rgb(1, 2, 3)]
Pass Attribute 'initial-value' returns expected value for [red]
Pass Attribute 'initial-value' returns expected value for [foo]
Fail Attribute 'initial-value' returns expected value for [foo(){}]
Fail Attribute 'initial-value' makes the @property rule invalid for [3em]
Fail Attribute 'initial-value' makes the @property rule invalid for [var(--x)]
Pass Attribute 'inherits' returns expected value for [true]
Pass Attribute 'inherits' returns expected value for [false]
Pass Attribute 'inherits' makes the @property rule invalid for [none]
Pass Attribute 'inherits' makes the @property rule invalid for [0]
Pass Attribute 'inherits' makes the @property rule invalid for [1]
Pass Attribute 'inherits' makes the @property rule invalid for ["true"]
Pass Attribute 'inherits' makes the @property rule invalid for ["false"]
Pass Attribute 'inherits' makes the @property rule invalid for [calc(0)]
Pass Invalid property name does not parse [foo]
Pass Invalid property name does not parse [-foo]
Fail Rule applied [*, foo(){}, false]
Fail Rule applied [<angle>, 42deg, false]
Fail Rule applied [<angle>, 1turn, false]
Fail Rule applied [<color>, green, false]
Fail Rule applied [<color>, rgb(1, 2, 3), false]
Fail Rule applied [<image>, url("http://a/"), false]
Fail Rule applied [<integer>, 5, false]
Fail Rule applied [<length-percentage>, 10px, false]
Fail Rule applied [<length-percentage>, 10%, false]
Fail Rule applied [<length-percentage>, calc(10% + 10px), false]
Fail Rule applied [<length>, 10px, false]
Fail Rule applied [<number>, 2.5, false]
Fail Rule applied [<percentage>, 10%, false]
Fail Rule applied [<resolution>, 50dppx, false]
Fail Rule applied [<resolution>, 96dpi, false]
Fail Rule applied [<time>, 10s, false]
Fail Rule applied [<time>, 1000ms, false]
Fail Rule applied [<transform-function>, rotateX(0deg), false]
Fail Rule applied [<transform-list>, rotateX(0deg), false]
Fail Rule applied [<transform-list>, rotateX(0deg) translateX(10px), false]
Fail Rule applied [<url>, url("http://a/"), false]
Fail Rule applied [<string>, 'foo bar', false]
Fail Rule applied [<string>, 'foo bar' , false]
Fail Rule applied [<string>, '"foo" bar', false]
Fail Rule applied [<string>, "bar baz", false]
Fail Rule applied [<string>, "bar 'baz'", false]
Fail Rule applied [<string>+, 'foo' 'bar', false]
Fail Rule applied [<string>#, 'foo', 'bar', false]
Fail Rule applied [<string>+ | <string>#, 'foo' 'bar', false]
Fail Rule applied [<string>+ | <string>#, 'foo' 'bar', false]
Fail Rule applied [<string>+ | <string>#, 'foo' "bar", false]
Fail Rule applied [<string># | <string>+, 'foo', 'bar', false]
Fail Rule applied [<string># | <string>+, 'foo', 'bar' , false]
Fail Rule applied [<string># | <string>+, "foo", 'bar', false]
Pass Rule not applied [<string>, 1px, false]
Pass Rule not applied [<string>, foo, false]
Pass Rule not applied [<string>, calc(1 + 2), false]
Pass Rule not applied [<string>, rgb(255, 99, 71), false]
Pass Rule not applied [<string>, 'foo' 2px, false]
Fail Rule applied [<color>, tomato, false]
Fail Rule applied [<color>, tomato, true]
Pass Rule applied for "*", even with no initial value
Pass Rule not applied [undefined, green, false]
Pass Rule not applied [<color>, undefined, false]
Pass Rule not applied [<color>, green, undefined]
Pass Rule not applied [<gandalf>, grey, false]
Pass Rule not applied [gandalf, grey, false]
Pass Rule not applied [<color>, notacolor, false]
Pass Rule not applied [<length>, 10em, false]
Pass Rule not applied [<transform-function>, translateX(1em), false]
Pass Rule not applied [<transform-function>, translateY(1lh), false]
Pass Rule not applied [<transform-list>, rotate(10deg) translateX(1em), false]
Pass Rule not applied [<transform-list>, rotate(10deg) translateY(1lh), false]
Fail Non-inherited properties do not inherit
Pass Inherited properties inherit
Fail Initial values substituted as computed value
Pass Non-universal registration are invalid without an initial value
Fail Initial value may be omitted for universal registration

View File

@ -0,0 +1,34 @@
Harness status: OK
Found 29 tests
29 Fail
Fail Initial value for <length> correctly computed [calc(10px + 15px)]
Fail Initial value for <length> correctly computed [1in]
Fail Initial value for <length> correctly computed [2.54cm]
Fail Initial value for <length> correctly computed [25.4mm]
Fail Initial value for <length> correctly computed [6pc]
Fail Initial value for <length> correctly computed [72pt]
Fail Initial value for <percentage> correctly computed [calc(10% + 20%)]
Fail Initial value for <length-percentage> correctly computed [calc(1in + 10% + 4px)]
Fail Initial value for <color> correctly computed [pink, inherits]
Fail Initial value for <color> correctly computed [purple]
Fail Initial value for <transform-function> correctly computed [rotate(42deg)]
Fail Initial value for <transform-list> correctly computed [scale(calc(2 + 2))]
Fail Initial value for <transform-list> correctly computed [scale(calc(2 + 1)) translateX(calc(3px + 1px))]
Fail Initial value for <url> correctly computed [url(a)]
Fail Initial value for <url>+ correctly computed [url(a) url(a)]
Fail Initial inherited value can be substituted [purple, color]
Fail Initial non-inherited value can be substituted [pink, background-color]
Fail Initial non-inherited value can be substituted [ foo , --x]
Fail Initial non-inherited value can be substituted [ 1turn, --x]
Fail Initial non-inherited value can be substituted [ pink , --x]
Fail Initial non-inherited value can be substituted [ test, --x]
Fail Initial non-inherited value can be substituted [calc(20 + 20 + 10), --x]
Fail Initial non-inherited value can be substituted [ calc(13% + 37px), --x]
Fail Initial non-inherited value can be substituted [calc(10px + 15px), --x]
Fail Initial non-inherited value can be substituted [calc(13 + 37), --x]
Fail Initial non-inherited value can be substituted [calc(13% + 37%), --x]
Fail Initial non-inherited value can be substituted [2000ms, --x]
Fail Initial non-inherited value can be substituted [scale(calc(2 + 2)), --x]
Fail Initial non-inherited value can be substituted [scale(calc(2 + 2)) translateX(calc(3px + 1px)), --x]

View File

@ -0,0 +1,336 @@
<!DOCTYPE html>
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1/#at-property-rule">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="./resources/utils.js"></script>
<div id="outer">
<div id="target"></div>
</div>
<script>
// Parsing:
let uppercase_first = (x) => x.charAt(0).toUpperCase() + x.slice(1);
let to_camel_case = (x) => x.split('-')[0] + x.split('-').slice(1).map(uppercase_first).join('');
function get_cssom_descriptor_value(rule, descriptor) {
switch (descriptor) {
case 'syntax':
return rule.syntax;
case 'inherits':
return rule.inherits;
case 'initial-value':
return rule.initialValue;
default:
assert_true(false, 'Should not reach here');
return null;
}
}
// Test that for the given descriptor (e.g. 'syntax'), the specified value
// will yield the expected_value when observed using CSSOM. If the expected_value
// is omitted, it is the same as the specified value.
function test_descriptor(descriptor, specified_value, expected_value, other_descriptors) {
// Try and build a valid @property form the specified descriptor.
let at_property = { [to_camel_case(descriptor)]: specified_value };
// If extra values are specified in other_descriptors, just use them.
if (typeof(other_descriptors) !== 'unspecified') {
for (let name in other_descriptors) {
if (other_descriptors.hasOwnProperty(name)) {
if (name == descriptor) {
throw `Unexpected ${name} in other_descriptors`;
}
at_property[to_camel_case(name)] = other_descriptors[name];
}
}
}
if (!('syntax' in at_property)) {
// The syntax descriptor is required. Use the universal one as a fallback.
// https://drafts.css-houdini.org/css-properties-values-api-1/#the-syntax-descriptor
at_property.syntax = '"*"';
}
if (!('inherits' in at_property)) {
// The inherits descriptor is required. Make it true as a fallback.
// https://drafts.css-houdini.org/css-properties-values-api-1/#inherits-descriptor
at_property.inherits = true;
}
if (!at_property.syntax.match(/^"\s*\*\s*"$/) &&
!('initialValue' in at_property)) {
// The initial-value is required for non-universal syntax.
// Pick a computationally independent value that follows specified syntax.
// https://drafts.css-houdini.org/css-properties-values-api-1/#the-syntax-descriptor
at_property.initialValue = (() => {
let first_syntax_component = specified_value
.replace(/^"(.*)"$/, '$1') // unquote
.replace(/[\s\uFEFF\xA0]+/g, ' ') // collapse whitespaces
.match(/^[^|\#\+]*/)[0] // pick first component
.trim();
switch (first_syntax_component) {
case '<color>': return 'blue';
case '<length>': return '42px';
default:
if (first_syntax_component.startsWith('<')) {
throw `Unsupported data type name '${first_syntax_component}'`;
}
return first_syntax_component; // <custom-ident>
}
})();
}
if (expected_value === null) {
test_with_at_property(at_property, (name, rule) => {
assert_true(!rule);
}, `Attribute '${descriptor}' makes the @property rule invalid for [${specified_value}]`);
} else {
if (typeof(expected_value) === 'undefined')
expected_value = specified_value;
test_with_at_property(at_property, (name, rule) => {
assert_equals(get_cssom_descriptor_value(rule, descriptor), expected_value);
}, `Attribute '${descriptor}' returns expected value for [${specified_value}]`);
}
}
// syntax
test_descriptor('syntax', '"<color>"', '<color>');
test_descriptor('syntax', '"<color> | none"', '<color> | none');
test_descriptor('syntax', '"<color># | <image> | none"', '<color># | <image> | none');
test_descriptor('syntax', '"foo | <length>#"', 'foo | <length>#');
test_descriptor('syntax', '"foo | bar | baz"', 'foo | bar | baz');
test_descriptor('syntax', '"notasyntax"', 'notasyntax');
// syntax: universal
for (const syntax of ["*", " * ", "* ", "\t*\t"]) {
test_descriptor('syntax', `"${syntax}"`, syntax);
}
// syntax: <color> value
test_descriptor('syntax', '"red"', "red"); // treated as <custom-ident>.
test_descriptor('syntax', '"rgb(255, 0, 0)"', null);
// syntax: missing quotes
test_descriptor('syntax', '<color>', null);
test_descriptor('syntax', 'foo | bar', null);
// syntax: invalid <custom-ident>
// https://drafts.csswg.org/css-values-4/#custom-idents
for (const syntax of
["default",
"initial",
"inherit",
"unset",
"revert",
"revert-layer",
]) {
test_descriptor('syntax', `"${syntax}"`, null);
test_descriptor('syntax', `"${uppercase_first(syntax)}"`, null);
}
// syntax: pipe between components
test_descriptor('syntax', '"foo bar"', null, {'initial-value': 'foo bar'});
test_descriptor('syntax', '"Foo <length>"', null, {'initial-value': 'Foo 42px'});
test_descriptor('syntax', '"foo, bar"', null, {'initial-value': 'foo, bar'});
test_descriptor('syntax', '"<length> <percentage>"', null, {'initial-value': '42px 100%'});
// syntax: leading bar
test_descriptor('syntax', '"|<length>"', null, {'initial-value': '42px'});
// initial-value
test_descriptor('initial-value', '10px');
test_descriptor('initial-value', 'rgb(1, 2, 3)');
test_descriptor('initial-value', 'red');
test_descriptor('initial-value', 'foo');
test_descriptor('initial-value', 'foo(){}');
// initial-value: not computationally independent
test_descriptor('initial-value', '3em', null, {'syntax': '"<length>"'});
test_descriptor('initial-value', 'var(--x)', null);
// inherits
test_descriptor('inherits', 'true', true);
test_descriptor('inherits', 'false', false);
test_descriptor('inherits', 'none', null);
test_descriptor('inherits', '0', null);
test_descriptor('inherits', '1', null);
test_descriptor('inherits', '"true"', null);
test_descriptor('inherits', '"false"', null);
test_descriptor('inherits', 'calc(0)', null);
test_with_style_node('@property foo { }', (node) => {
assert_equals(node.sheet.rules.length, 0);
}, 'Invalid property name does not parse [foo]');
test_with_style_node('@property -foo { }', (node) => {
assert_equals(node.sheet.rules.length, 0);
}, 'Invalid property name does not parse [-foo]');
// Applying @property rules
function test_applied(syntax, initial, inherits, expected) {
test_with_at_property({
syntax: `"${syntax}"`,
initialValue: initial,
inherits: inherits
}, (name, rule) => {
let actual = getComputedStyle(target).getPropertyValue(name);
assert_equals(actual, expected);
}, `Rule applied [${syntax}, ${initial}, ${inherits}]`);
}
function test_not_applied(syntax, initial, inherits) {
test_with_at_property({
syntax: `"${syntax}"`,
initialValue: initial,
inherits: inherits
}, (name, rule) => {
let actual = getComputedStyle(target).getPropertyValue(name);
assert_equals(actual, '');
}, `Rule not applied [${syntax}, ${initial}, ${inherits}]`);
}
// syntax, initialValue, inherits, expected
test_applied('*', 'foo(){}', false, 'foo(){}');
test_applied('<angle>', '42deg', false, '42deg');
test_applied('<angle>', '1turn', false, '360deg');
test_applied('<color>', 'green', false, 'rgb(0, 128, 0)');
test_applied('<color>', 'rgb(1, 2, 3)', false, 'rgb(1, 2, 3)');
test_applied('<image>', 'url("http://a/")', false, 'url("http://a/")');
test_applied('<integer>', '5', false, '5');
test_applied('<length-percentage>', '10px', false, '10px');
test_applied('<length-percentage>', '10%', false, '10%');
test_applied('<length-percentage>', 'calc(10% + 10px)', false, 'calc(10% + 10px)');
test_applied('<length>', '10px', false, '10px');
test_applied('<number>', '2.5', false, '2.5');
test_applied('<percentage>', '10%', false, '10%');
test_applied('<resolution>', '50dppx', false, '50dppx');
test_applied('<resolution>', '96dpi', false, '1dppx');
test_applied('<time>', '10s', false, '10s');
test_applied('<time>', '1000ms', false, '1s');
test_applied('<transform-function>', 'rotateX(0deg)', false, 'rotateX(0deg)');
test_applied('<transform-list>', 'rotateX(0deg)', false, 'rotateX(0deg)');
test_applied('<transform-list>', 'rotateX(0deg) translateX(10px)', false, 'rotateX(0deg) translateX(10px)');
test_applied('<url>', 'url("http://a/")', false, 'url("http://a/")');
test_applied("<string>", "'foo bar'", false, '"foo bar"');
test_applied("<string>", " 'foo bar' ", false, '"foo bar"');
test_applied("<string>", `'"foo" bar'`, false, '"\\"foo\\" bar"');
test_applied("<string>", '"bar baz"', false, '"bar baz"');
test_applied("<string>", `"bar 'baz'"`, false, `"bar 'baz'"`);
test_applied("<string>+", "'foo' 'bar'", false, '"foo" "bar"');
test_applied("<string>#", "'foo', 'bar'", false, '"foo", "bar"');
test_applied("<string>+ | <string>#", "'foo' 'bar'", false, '"foo" "bar"');
test_applied("<string>+ | <string>#", " 'foo' 'bar'", false, '"foo" "bar"');
test_applied("<string>+ | <string>#", `'foo' "bar"`, false, '"foo" "bar"');
test_applied("<string># | <string>+", "'foo', 'bar'", false, '"foo", "bar"');
test_applied("<string># | <string>+", "'foo', 'bar' ", false, '"foo", "bar"');
test_applied("<string># | <string>+", `"foo", 'bar'`, false, '"foo", "bar"');
test_not_applied("<string>", "1px", false);
test_not_applied("<string>", "foo", false);
test_not_applied("<string>", "calc(1 + 2)", false);
test_not_applied("<string>", "rgb(255, 99, 71)", false);
test_not_applied("<string>", "'foo' 2px", false);
// inherits: true/false
test_applied('<color>', 'tomato', false, 'rgb(255, 99, 71)');
test_applied('<color>', 'tomato', true, 'rgb(255, 99, 71)');
test_with_at_property({ syntax: '"*"', inherits: true }, (name, rule) => {
try {
outer.style.setProperty(name, 'foo');
let actual = getComputedStyle(target).getPropertyValue(name);
assert_equals(actual, 'foo');
} finally {
outer.style = '';
}
}, 'Rule applied for "*", even with no initial value');
test_not_applied(undefined, 'green', false);
test_not_applied('<color>', undefined, false);
test_not_applied('<color>', 'green', undefined);
test_not_applied('<gandalf>', 'grey', false);
test_not_applied('gandalf', 'grey', false);
test_not_applied('<color>', 'notacolor', false);
test_not_applied('<length>', '10em', false);
test_not_applied('<transform-function>', 'translateX(1em)', false);
test_not_applied('<transform-function>', 'translateY(1lh)', false);
test_not_applied('<transform-list>', 'rotate(10deg) translateX(1em)', false);
test_not_applied('<transform-list>', 'rotate(10deg) translateY(1lh)', false);
// Inheritance
test_with_at_property({
syntax: '"<length>"',
inherits: false,
initialValue: '0px'
}, (name, rule) => {
try {
outer.style = `${name}: 40px`;
assert_equals(getComputedStyle(outer).getPropertyValue(name), '40px');
assert_equals(getComputedStyle(target).getPropertyValue(name), '0px');
} finally {
outer.style = '';
}
}, 'Non-inherited properties do not inherit');
test_with_at_property({
syntax: '"<length>"',
inherits: true,
initialValue: '0px'
}, (name, rule) => {
try {
outer.style = `${name}: 40px`;
assert_equals(getComputedStyle(outer).getPropertyValue(name), '40px');
assert_equals(getComputedStyle(target).getPropertyValue(name), '40px');
} finally {
outer.style = '';
}
}, 'Inherited properties inherit');
// Initial values
test_with_at_property({
syntax: '"<color>"',
inherits: true,
initialValue: 'green'
}, (name, rule) => {
try {
target.style = `--x:var(${name})`;
assert_equals(getComputedStyle(target).getPropertyValue(name), 'rgb(0, 128, 0)');
} finally {
target.style = '';
}
}, 'Initial values substituted as computed value');
test_with_at_property({
syntax: '"<length>"',
inherits: false,
initialValue: undefined
}, (name, rule) => {
try {
target.style = `${name}: calc(1px + 1px);`;
assert_equals(getComputedStyle(target).getPropertyValue(name), 'calc(1px + 1px)');
} finally {
target.style = '';
}
}, 'Non-universal registration are invalid without an initial value');
test_with_at_property({
syntax: '"*"',
inherits: false,
initialValue: undefined
}, (name, rule) => {
try {
// If the registration suceeded, ${name} does *not* inherit, and hence
// the computed value on 'target' should be empty.
outer.style = `${name}: calc(1px + 1px);`;
assert_equals(getComputedStyle(target).getPropertyValue(name), '');
} finally {
outer.style = '';
}
}, 'Initial value may be omitted for universal registration');
</script>

View File

@ -0,0 +1,71 @@
<!DOCTYPE html>
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1/#dom-propertydescriptor-initialvalue" />
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1/#register-a-custom-property" />
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1/#substitution" />
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="./resources/utils.js"></script>
<div id=target></div>
<script>
function test_initial_value(reg, expected) {
let suffix = reg.inherits === true ? ', inherits' : '';
test(function(){
let name = generate_property(reg);
let actual = getComputedStyle(target).getPropertyValue(name);
assert_equals(actual, expected);
}, `Initial value for ${reg.syntax} correctly computed [${reg.initialValue}${suffix}]`);
}
test_initial_value({ syntax: '<length>', initialValue: 'calc(10px + 15px)' }, '25px');
test_initial_value({ syntax: '<length>', initialValue: '1in' }, '96px');
test_initial_value({ syntax: '<length>', initialValue: '2.54cm' }, '96px');
test_initial_value({ syntax: '<length>', initialValue: '25.4mm' }, '96px');
test_initial_value({ syntax: '<length>', initialValue: '6pc' }, '96px');
test_initial_value({ syntax: '<length>', initialValue: '72pt' }, '96px');
test_initial_value({ syntax: '<percentage>', initialValue: 'calc(10% + 20%)' }, '30%');
test_initial_value({ syntax: '<length-percentage>', initialValue: 'calc(1in + 10% + 4px)' }, 'calc(10% + 100px)');
test_initial_value({ syntax: '<color>', initialValue: 'pink', inherits: true }, 'rgb(255, 192, 203)');
test_initial_value({ syntax: '<color>', initialValue: 'purple' }, 'rgb(128, 0, 128)');
test_initial_value({ syntax: '<transform-function>', initialValue: 'rotate(42deg)' }, 'rotate(42deg)');
test_initial_value({ syntax: '<transform-list>', initialValue: 'scale(calc(2 + 2))' }, 'scale(4)');
test_initial_value({ syntax: '<transform-list>', initialValue: 'scale(calc(2 + 1)) translateX(calc(3px + 1px))' }, 'scale(3) translateX(4px)');
test_initial_value({ syntax: '<url>', initialValue: 'url(a)' },
`url("${new URL('a', document.baseURI)}")`);
test_initial_value({ syntax: '<url>+', initialValue: 'url(a) url(a)' },
`url("${new URL('a', document.baseURI)}") url("${new URL('a', document.baseURI)}")`);
// Test that the initial value of the custom property 'reg' is successfully
// substituted into 'property'.
function test_substituted_value(reg, property, expected) {
let inherits_text = reg.inherits === true ? 'inherited' : 'non-inherited';
test(function(){
try {
let name = generate_property(reg);
target.style = `${property}:var(${name});`;
assert_equals(getComputedStyle(target).getPropertyValue(property), expected);
} finally {
target.style = '';
}
}, `Initial ${inherits_text} value can be substituted [${reg.initialValue}, ${property}]`);
}
test_substituted_value({ syntax: '<color>', initialValue: 'purple', inherits: true }, 'color', 'rgb(128, 0, 128)');
test_substituted_value({ syntax: '<color>', initialValue: 'pink' }, 'background-color', 'rgb(255, 192, 203)');
// Registered properties shall substitute as a token sequence equivalent to
// their computed value.
test_substituted_value({ syntax: 'foo', initialValue: '\tfoo\t' }, '--x', 'foo');
test_substituted_value({ syntax: '<angle>', initialValue: '\t1turn' }, '--x', '360deg');
test_substituted_value({ syntax: '<color>', initialValue: ' pink ' }, '--x', 'rgb(255, 192, 203)');
test_substituted_value({ syntax: '<custom-ident>', initialValue: '\ttest' }, '--x', 'test');
test_substituted_value({ syntax: '<integer>', initialValue: 'calc(20 + 20 + 10)' }, '--x', '50');
test_substituted_value({ syntax: '<length-percentage>', initialValue: '\tcalc(13% + 37px)' }, '--x', 'calc(13% + 37px)');
test_substituted_value({ syntax: '<length>', initialValue: 'calc(10px + 15px)' }, '--x', '25px');
test_substituted_value({ syntax: '<number>', initialValue: 'calc(13 + 37)' }, '--x', '50');
test_substituted_value({ syntax: '<percentage>', initialValue: 'calc(13% + 37%)' }, '--x', '50%');
test_substituted_value({ syntax: '<time>', initialValue: '2000ms' }, '--x', '2s');
test_substituted_value({ syntax: '<transform-function>', initialValue: 'scale(calc(2 + 2))' }, '--x', 'scale(4)');
test_substituted_value({ syntax: '<transform-list>', initialValue: 'scale(calc(2 + 2)) translateX(calc(3px + 1px))' }, '--x', 'scale(4) translateX(4px)');
</script>