Tests: Import some @function parsing tests

This commit is contained in:
Callum Law 2026-03-06 22:00:02 +13:00 committed by Sam Atkins
parent 450c15c63b
commit fc3dc8ac8c
5 changed files with 651 additions and 0 deletions

View file

@ -0,0 +1,39 @@
Harness status: OK
Found 34 tests
34 Fail
Fail Empty CSSFunctionRule
Fail Single CSSFunctionDeclarations
Fail CSSFunctionDescriptors (result)
Fail CSSFunctionDescriptors (result, repeated)
Fail CSSFunctionDescriptors (local variables)
Fail CSSFunctionDescriptors (local variables, repeated)
Fail CSSFunctionDescriptors (local variables and result)
Fail CSSFunctionDescriptors serialization
Fail Unknown descriptors
Fail Unknown descriptors (mutation)
Fail item()
Fail Indexed property getter
Fail @supports in body
Fail CSSFunctionRule.name
Fail CSSFunctionRule.getParameters()
Fail CSSFunctionRule.returnType
Fail CSSFunctionRule escapes
Fail CSSFunctionRule.cssText (--empty)
Fail CSSFunctionRule.cssText (--ret-length)
Fail CSSFunctionRule.cssText (--ret-length-auto)
Fail CSSFunctionRule.cssText (--param-single)
Fail CSSFunctionRule.cssText (--param-typed)
Fail CSSFunctionRule.cssText (--param-typed-default)
Fail CSSFunctionRule.cssText (--param-default)
Fail CSSFunctionRule.cssText (--param-multi)
Fail CSSFunctionRule.cssText (--param-multi-mixed)
Fail CSSFunctionRule.cssText (--body-result)
Fail CSSFunctionRule.cssText (--body-locals)
Fail CSSFunctionRule.cssText (--param-type-fn)
Fail CSSFunctionRule.cssText (--param-type-fn-uni)
Fail CSSFunctionRule.cssText (--ret-type-fn)
Fail CSSFunctionRule.cssText (--ret-type-fn-uni)
Fail CSSFunctionRule.cssText (--body-result-multi)
Fail CSSFunctionRule.cssText (--escaped-)

View file

@ -0,0 +1,92 @@
Harness status: OK
Found 86 tests
38 Pass
48 Fail
Fail @function --foo() is valid
Fail @function --foo( ) is valid
Fail @function --foo(--x) is valid
Fail @function --foo( --x ) is valid
Pass @function --foo () is invalid
Pass @function --foo (--x) is invalid
Fail @function --foo(--x auto) is valid
Fail @function --foo(--x <angle>) is valid
Fail @function --foo(--x <color>) is valid
Fail @function --foo(--x <custom-ident>) is valid
Fail @function --foo(--x <image>) is valid
Fail @function --foo(--x <integer>) is valid
Fail @function --foo(--x <length>) is valid
Fail @function --foo(--x <length-percentage>) is valid
Fail @function --foo(--x <number>) is valid
Fail @function --foo(--x <percentage>) is valid
Fail @function --foo(--x <resolution>) is valid
Fail @function --foo(--x <string>) is valid
Fail @function --foo(--x <time>) is valid
Fail @function --foo(--x <url>) is valid
Fail @function --foo(--x <transform-function>) is valid
Fail @function --foo(--x <transform-list>) is valid
Fail @function --foo(--x type(auto)) is valid
Fail @function --foo(--x type(<length>)) is valid
Fail @function --foo(--x type(<length> | auto)) is valid
Fail @function --foo(--x type(none | auto)) is valid
Fail @function --foo(--x type(*)) is valid
Fail @function --foo(--x, --y) is valid
Fail @function --foo(--x, --y, --z) is valid
Fail @function --foo(--x <length>, --y, --z) is valid
Fail @function --foo(--x, --y <number>, --z <angle>) is valid
Fail @function --foo(--x : 10px) is valid
Fail @function --foo(--x type(*): 10px) is valid
Fail @function --foo(--x <length>: 10px) is valid
Fail @function --foo(--x <length>: 10px, --y) is valid
Fail @function --foo(--x, --y <length>: 10px) is valid
Fail @function --foo(--x type(<length> | auto): auto) is valid
Fail @function --foo(--x type(<length> | auto) : auto) is valid
Fail @function --foo(--x:1px, --y, --z:2px) is valid
Pass @function --foo(--x: 10px !important) is invalid
Pass @function --foo(--x <length>: 10deg) is invalid
Pass @function --foo(--x <angle>: 10px) is invalid
Pass @function --foo(--x <color>: 10px) is invalid
Pass @function --foo(--x type(<color>+): red 5) is invalid
Pass @function --foo(--x type(auto | none): thing) is invalid
Fail @function --foo(--x <length>#) is valid
Fail @function --foo(--x <length>+) is valid
Fail @function --foo(--x type(<length>+)) is valid
Fail @function --foo(--x <transform-function>#) is valid
Fail @function --foo(--x <transform-function>+) is valid
Pass @function --foo(--x <transform-list>#) is invalid
Pass @function --foo(--x <transform-list>+) is invalid
Pass @function --foo(--x *) is invalid
Pass @function --foo(--x !) is invalid
Pass @function --foo(--x 50px) is invalid
Pass @function --foo(--x <length> | auto) is invalid
Pass @function --foo(--x none | auto) is invalid
Pass @function --foo(--x <dino>) is invalid
Pass @function --foo(!) is invalid
Pass @function --foo(--x: !) is invalid
Pass @function --foo(--x type(!)) is invalid
Pass @function --foo(,) is invalid
Pass @function --foo(,,,) is invalid
Pass @function --foo(--x, ;) is invalid
Pass @function --foo(;) is invalid
Pass @function --foo(]) is invalid
Pass @function --foo(, --x]) is invalid
Fail @function --foo(--x) returns type(*) is valid
Fail @function --foo(--x) returns <length> is valid
Fail @function --foo(--x) returns <length>+ is valid
Fail @function --foo(--x) returns type(<length>) is valid
Fail @function --foo(--x) returns type(<length> | auto) is valid
Fail @function --foo(--x) returns type(foo | bar) is valid
Pass @function --foo(--x) ! is invalid
Pass @function --foo(--x) ! <length> is invalid
Pass @function --foo(--x) returns <length>! is invalid
Pass @function --foo(--x) length is invalid
Pass @function --foo(--x) returns is invalid
Pass @function --foo(--x) returns is invalid
Pass @function --foo(--x) returns * is invalid
Pass @function --foo(--x) returns <transform-list># is invalid
Pass @function --foo(--x) returns <transform-list>+ is invalid
Pass @function --foo(--x) returns auto | none is invalid
Pass @function --foo(--x): <length> is invalid
Pass @function --foo(--x): length is invalid
Pass @function --foo(--x) returneth <length> is invalid

View file

@ -0,0 +1,329 @@
<!DOCTYPE html>
<title>CSS Custom Functions: CSSOM</title>
<link rel="help" href="https://drafts.csswg.org/css-mixins-1/#cssom">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script>
test(t => {
let sheet = new CSSStyleSheet();
sheet.replaceSync(`
@function --foo() {}
`);
assert_equals(sheet.cssRules.length, 1);
let functionRule = sheet.cssRules[0];
assert_true(functionRule instanceof CSSFunctionRule);
assert_equals(functionRule.cssRules.length, 0);
}, 'Empty CSSFunctionRule');
test(t => {
let sheet = new CSSStyleSheet();
sheet.replaceSync(`
@function --foo() {
result: 100px;
}
`);
assert_equals(sheet.cssRules.length, 1);
let functionRule = sheet.cssRules[0];
assert_true(functionRule instanceof CSSFunctionRule);
assert_equals(functionRule.cssRules.length, 1);
let declarationsRule = functionRule.cssRules[0];
assert_true(declarationsRule instanceof CSSFunctionDeclarations);
let descriptors = declarationsRule.style;
assert_true(descriptors instanceof CSSFunctionDescriptors);
}, 'Single CSSFunctionDeclarations');
test(t => {
let sheet = new CSSStyleSheet();
sheet.replaceSync(`
@function --foo() {
result: 100px;
}
`);
let descriptors = sheet.cssRules[0]?.cssRules[0]?.style;
assert_true(descriptors instanceof CSSFunctionDescriptors);
assert_equals(descriptors.result, '100px');
}, 'CSSFunctionDescriptors (result)');
test(t => {
let sheet = new CSSStyleSheet();
sheet.replaceSync(`
@function --foo() {
result: 100px;
result: 101px;
}
`);
let descriptors = sheet.cssRules[0]?.cssRules[0]?.style;
assert_true(descriptors instanceof CSSFunctionDescriptors);
assert_equals(descriptors.result, '101px');
}, 'CSSFunctionDescriptors (result, repeated)');
test(t => {
let sheet = new CSSStyleSheet();
sheet.replaceSync(`
@function --foo() {
--x: 1px;
--y: 2px;
}
`);
let descriptors = sheet.cssRules[0]?.cssRules[0]?.style;
assert_true(descriptors instanceof CSSFunctionDescriptors);
assert_equals(descriptors.getPropertyValue('--x'), '1px');
assert_equals(descriptors.getPropertyValue('--y'), '2px');
assert_equals(descriptors.getPropertyValue('--unknown'), '');
assert_equals(descriptors.result, '');
}, 'CSSFunctionDescriptors (local variables)');
test(t => {
let sheet = new CSSStyleSheet();
sheet.replaceSync(`
@function --foo() {
--x: 1px;
--y: 2px;
--x: 3px;
}
`);
let descriptors = sheet.cssRules[0]?.cssRules[0]?.style;
assert_true(descriptors instanceof CSSFunctionDescriptors);
assert_equals(descriptors.getPropertyValue('--x'), '3px');
assert_equals(descriptors.getPropertyValue('--y'), '2px');
assert_equals(descriptors.getPropertyValue('--unknown'), '');
assert_equals(descriptors.result, '');
}, 'CSSFunctionDescriptors (local variables, repeated)');
test(t => {
let sheet = new CSSStyleSheet();
sheet.replaceSync(`
@function --foo() {
--x: 1px;
--y: 2px;
result: 3px;
}
`);
let descriptors = sheet.cssRules[0]?.cssRules[0]?.style;
assert_true(descriptors instanceof CSSFunctionDescriptors);
assert_equals(descriptors.getPropertyValue('--x'), '1px');
assert_equals(descriptors.getPropertyValue('--y'), '2px');
assert_equals(descriptors.getPropertyValue('--unknown'), '');
assert_equals(descriptors.result, '3px');
}, 'CSSFunctionDescriptors (local variables and result)');
test(t => {
let sheet = new CSSStyleSheet();
sheet.replaceSync(`
@function --foo() {
--x: 1px;
--y: 2px;
result: 3px;
}
`);
let descriptors = sheet.cssRules[0]?.cssRules[0]?.style;
assert_true(descriptors instanceof CSSFunctionDescriptors);
assert_equals(descriptors.cssText, '--x: 1px; --y: 2px; result: 3px;');
}, 'CSSFunctionDescriptors serialization');
test(t => {
let sheet = new CSSStyleSheet();
sheet.replaceSync(`
@function --foo() {
--x: 1px;
syntax: "<length>";
--y: 2px;
color: red;
unknown: unknown;
result: 3px;
}
`);
let descriptors = sheet.cssRules[0]?.cssRules[0]?.style;
assert_true(descriptors instanceof CSSFunctionDescriptors);
assert_equals(descriptors.length, 3);
assert_equals(descriptors.cssText, '--x: 1px; --y: 2px; result: 3px;');
}, 'Unknown descriptors');
test(t => {
let sheet = new CSSStyleSheet();
sheet.replaceSync(`
@function --foo() {
--x: 1px;
}
`);
let descriptors = sheet.cssRules[0]?.cssRules[0]?.style;
assert_true(descriptors instanceof CSSFunctionDescriptors);
assert_equals(descriptors.length, 1);
descriptors.cssText = '--x: 1px; color: red; result: 3px; --y: 2px;';
assert_equals(descriptors.length, 3);
assert_equals(descriptors.cssText, '--x: 1px; result: 3px; --y: 2px;');
}, 'Unknown descriptors (mutation)');
test(t => {
let sheet = new CSSStyleSheet();
sheet.replaceSync(`
@function --foo() {
--x: 1px;
result: 2px;
}
`);
let descriptors = sheet.cssRules[0]?.cssRules[0]?.style;
assert_true(descriptors instanceof CSSFunctionDescriptors);
assert_equals(descriptors.length, 2);
assert_equals(descriptors.item(0), '--x');
assert_equals(descriptors.item(1), 'result');
}, 'item()');
// https://webidl.spec.whatwg.org/#dfn-indexed-property-getter
test(t => {
let sheet = new CSSStyleSheet();
sheet.replaceSync(`
@function --foo() {
--x: 1px;
result: 2px;
}
`);
let descriptors = sheet.cssRules[0]?.cssRules[0]?.style;
assert_true(descriptors instanceof CSSFunctionDescriptors);
assert_array_equals(Array.from(descriptors), ['--x', 'result']);;
}, 'Indexed property getter');
// Conditional rules
test(t => {
let sheet = new CSSStyleSheet();
sheet.replaceSync(`
@function --foo() {
@supports (width: 100px) {
result: 100px;
}
result: 200px;
}
`);
assert_equals(sheet.cssRules.length, 1);
let functionRule = sheet.cssRules[0];
assert_true(functionRule instanceof CSSFunctionRule);
assert_equals(functionRule.cssRules.length, 2);
let supportsRule = functionRule.cssRules[0];
assert_true(supportsRule instanceof CSSSupportsRule);
assert_true(supportsRule.cssRules[0] instanceof CSSFunctionDeclarations);
assert_equals(supportsRule.cssRules[0].style?.result, '100px');
let declarationsRule = functionRule.cssRules[1];
assert_true(declarationsRule instanceof CSSFunctionDeclarations);
let descriptors = declarationsRule.style;
assert_true(descriptors instanceof CSSFunctionDescriptors);
assert_equals(descriptors.result, '200px');
}, '@supports in body');
// CSSFunctionRule
test(t => {
let sheet = new CSSStyleSheet();
sheet.replaceSync(`
@function --foo() {}
`);
assert_equals(sheet.cssRules.length, 1);
let functionRule = sheet.cssRules[0];
assert_true(functionRule instanceof CSSFunctionRule);
assert_equals(functionRule.name, '--foo');
}, 'CSSFunctionRule.name');
test(t => {
let sheet = new CSSStyleSheet();
sheet.replaceSync(`
@function --f0() {}
@function --f1(--x) {}
@function --f2(--x <length>) {}
@function --f3(--x: 10px) {}
@function --f4(--x <length>: 10px) {}
@function --f5(--x type(<length> | auto): 10px, --y, --z: red) {}
`);
assert_equals(sheet.cssRules.length, 6);
assert_object_equals(sheet.cssRules[0].getParameters(), []);
assert_object_equals(sheet.cssRules[1].getParameters(), [
{name: '--x', type: '*'},
]);
assert_object_equals(sheet.cssRules[2].getParameters(), [
{name: '--x', type: '<length>'},
]);
assert_object_equals(sheet.cssRules[3].getParameters(), [
{name: '--x', type: '*', defaultValue: '10px'},
]);
assert_object_equals(sheet.cssRules[4].getParameters(), [
{name: '--x', type: '<length>', defaultValue: '10px'},
]);
assert_object_equals(sheet.cssRules[5].getParameters(), [
{name: '--x', type: '<length> | auto', defaultValue: '10px'},
{name: '--y', type: '*'},
{name: '--z', type: '*', defaultValue: 'red'},
], '--f5');
}, 'CSSFunctionRule.getParameters()');
test(t => {
let sheet = new CSSStyleSheet();
sheet.replaceSync(`
@function --f0() {}
@function --f1() returns <length> {}
@function --f2() returns <length>+ {}
@function --f3() returns type(*) {}
@function --f4() returns type(<length> | auto) {}
`);
assert_equals(sheet.cssRules.length, 5);
assert_equals(sheet.cssRules[0]?.returnType, '*');
assert_equals(sheet.cssRules[1]?.returnType, '<length>');
assert_equals(sheet.cssRules[2]?.returnType, '<length>+');
assert_equals(sheet.cssRules[3]?.returnType, '*');
assert_equals(sheet.cssRules[4]?.returnType, '<length> | auto');
}, 'CSSFunctionRule.returnType');
test(t => {
let sheet = new CSSStyleSheet();
// U+0009 CHARACTER TABULATION
sheet.replaceSync(`@function --escaped-\\9 -tab(--param-\\9 -tab) { --local-\\9 -tab: 1px; }`);
assert_equals(sheet.cssRules.length, 1);
let rule = sheet.cssRules[0];
assert_equals(rule.name, '--escaped-\t-tab');
assert_equals(rule.getParameters()[0]?.name, '--param-\t-tab');
assert_equals(rule.cssRules[0].style.getPropertyValue('--local-\t-tab'), '1px');
}, 'CSSFunctionRule escapes');
function test_cssText(actual, expected) {
expected ??= actual;
let name = actual.match(/@function (--[-\w]+)/)[1];
test(t => {
let sheet = new CSSStyleSheet();
sheet.replaceSync(actual);
assert_equals(sheet.cssRules[0]?.cssText, expected);
}, `CSSFunctionRule.cssText (${name})`);
}
// The function name is used by the test description; please make sure it's
// unique among all test_cssText cases.
test_cssText(`@function --empty() { }`);
test_cssText(`@function --ret-length() returns <length> { }`);
test_cssText(`@function --ret-length-auto() returns type(<length> | auto) { }`);
test_cssText(`@function --param-single(--x) { }`);
test_cssText(`@function --param-typed(--x <length>) { }`);
test_cssText(`@function --param-typed-default(--x <length>: 10px) { }`);
test_cssText(`@function --param-default(--x: 10px) { }`);
test_cssText(`@function --param-multi(--x, --y) { }`);
test_cssText(`@function --param-multi-mixed(--x: 10px, --y, --z <length>) { }`);
test_cssText(`@function --body-result() { result: 10px; }`);
test_cssText(`@function --body-locals() { --x: 1px; --y: 2px; result: 10px; }`);
// Cases that don't round-trip as-is:
test_cssText(`@function --param-type-fn(--x type(<length>)) { }`,
`@function --param-type-fn(--x <length>) { }`);
test_cssText(`@function --param-type-fn-uni(--x type(*)) { }`,
`@function --param-type-fn-uni(--x) { }`);
test_cssText(`@function --ret-type-fn() returns type(*) { }`,
`@function --ret-type-fn() { }`);
test_cssText(`@function --ret-type-fn-uni() returns type(*) { }`,
`@function --ret-type-fn-uni() { }`);
test_cssText(`@function --body-result-multi() { result: 10px; result: 20px; }`,
`@function --body-result-multi() { result: 20px; }`);
// Escapes (U+0009 CHARACTER TABULATION):
test_cssText(`@function --escaped-\\9 -tab(--param-\\9 -tab) { --local-\\9 -tab: 1px; }`);
</script>

View file

@ -0,0 +1,130 @@
<!DOCTYPE html>
<title>Custom Functions: Prelude Parsing</title>
<link rel="help" href="https://drafts.csswg.org/css-mixins-1/#function-rule">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script>
function test_valid_prelude(rule_without_block) {
test(() => {
let s = new CSSStyleSheet();
s.replaceSync(`${rule_without_block} {}`);
assert_equals(s.cssRules.length, 1);
}, `${rule_without_block} is valid`);
}
function test_invalid_prelude(rule_without_block) {
test(() => {
let s = new CSSStyleSheet();
s.replaceSync(`${rule_without_block} {}`);
assert_equals(s.cssRules.length, 0);
}, `${rule_without_block} is invalid`);
}
test_valid_prelude('@function --foo()');
test_valid_prelude('@function --foo( )');
test_valid_prelude('@function --foo(--x)');
test_valid_prelude('@function --foo( --x )');
test_invalid_prelude('@function --foo ()');
test_invalid_prelude('@function --foo (--x)');
// All single <syntax-component> types.
test_valid_prelude('@function --foo(--x auto)');
test_valid_prelude('@function --foo(--x <angle>)');
test_valid_prelude('@function --foo(--x <color>)');
test_valid_prelude('@function --foo(--x <custom-ident>)');
test_valid_prelude('@function --foo(--x <image>)');
test_valid_prelude('@function --foo(--x <integer>)');
test_valid_prelude('@function --foo(--x <length>)');
test_valid_prelude('@function --foo(--x <length-percentage>)');
test_valid_prelude('@function --foo(--x <number>)');
test_valid_prelude('@function --foo(--x <percentage>)');
test_valid_prelude('@function --foo(--x <resolution>)');
test_valid_prelude('@function --foo(--x <string>)');
test_valid_prelude('@function --foo(--x <time>)');
test_valid_prelude('@function --foo(--x <url>)');
test_valid_prelude('@function --foo(--x <transform-function>)');
test_valid_prelude('@function --foo(--x <transform-list>)');
test_valid_prelude('@function --foo(--x type(auto))');
test_valid_prelude('@function --foo(--x type(<length>))');
test_valid_prelude('@function --foo(--x type(<length> | auto))');
test_valid_prelude('@function --foo(--x type(none | auto))');
test_valid_prelude('@function --foo(--x type(*))');
// Multiple parameters.
test_valid_prelude('@function --foo(--x, --y)');
test_valid_prelude('@function --foo(--x, --y, --z)');
test_valid_prelude('@function --foo(--x <length>, --y, --z)');
test_valid_prelude('@function --foo(--x, --y <number>, --z <angle>)');
// Defaults.
test_valid_prelude('@function --foo(--x : 10px)');
test_valid_prelude('@function --foo(--x type(*): 10px)');
test_valid_prelude('@function --foo(--x <length>: 10px)');
test_valid_prelude('@function --foo(--x <length>: 10px, --y)');
test_valid_prelude('@function --foo(--x, --y <length>: 10px)');
test_valid_prelude('@function --foo(--x type(<length> | auto): auto)');
test_valid_prelude('@function --foo(--x type(<length> | auto) : auto)');
// A parameter without a default may appear after a parameter with
// a default, even though there's no way to actually call --foo()
// with just --y:
test_valid_prelude('@function --foo(--x:1px, --y, --z:2px)');
test_invalid_prelude('@function --foo(--x: 10px !important)');
// Default type mismatch.
test_invalid_prelude('@function --foo(--x <length>: 10deg)');
test_invalid_prelude('@function --foo(--x <angle>: 10px)');
test_invalid_prelude('@function --foo(--x <color>: 10px)');
test_invalid_prelude('@function --foo(--x type(<color>+): red 5)');
test_invalid_prelude('@function --foo(--x type(auto | none): thing)');
// Lists.
test_valid_prelude('@function --foo(--x <length>#)');
test_valid_prelude('@function --foo(--x <length>+)');
test_valid_prelude('@function --foo(--x type(<length>+))');
test_valid_prelude('@function --foo(--x <transform-function>#)');
test_valid_prelude('@function --foo(--x <transform-function>+)');
// <transform-list> is special: a multiplier cannot follow it.
test_invalid_prelude('@function --foo(--x <transform-list>#)');
test_invalid_prelude('@function --foo(--x <transform-list>+)');
test_invalid_prelude('@function --foo(--x *)');
test_invalid_prelude('@function --foo(--x !)');
test_invalid_prelude('@function --foo(--x 50px)');
test_invalid_prelude('@function --foo(--x <length> | auto)');
test_invalid_prelude('@function --foo(--x none | auto)');
test_invalid_prelude('@function --foo(--x <dino>)');
test_invalid_prelude('@function --foo(!)');
test_invalid_prelude('@function --foo(--x: !)');
test_invalid_prelude('@function --foo(--x type(!))');
test_invalid_prelude('@function --foo(,)');
test_invalid_prelude('@function --foo(,,,)');
test_invalid_prelude('@function --foo(--x, ;)');
test_invalid_prelude('@function --foo(;)');
test_invalid_prelude('@function --foo(])');
test_invalid_prelude('@function --foo(, --x])');
// Return value types.
test_valid_prelude('@function --foo(--x) returns type(*)');
test_valid_prelude('@function --foo(--x) returns <length>');
test_valid_prelude('@function --foo(--x) returns <length>+');
test_valid_prelude('@function --foo(--x) returns type(<length>)');
test_valid_prelude('@function --foo(--x) returns type(<length> | auto)');
test_valid_prelude('@function --foo(--x) returns type(foo | bar)');
test_invalid_prelude('@function --foo(--x) !');
test_invalid_prelude('@function --foo(--x) ! <length>');
test_invalid_prelude('@function --foo(--x) returns <length>!');
test_invalid_prelude('@function --foo(--x) length');
test_invalid_prelude('@function --foo(--x) returns');
test_invalid_prelude('@function --foo(--x) returns ');
test_invalid_prelude('@function --foo(--x) returns *');
test_invalid_prelude('@function --foo(--x) returns <transform-list>#');
test_invalid_prelude('@function --foo(--x) returns <transform-list>+');
test_invalid_prelude('@function --foo(--x) returns auto | none');
test_invalid_prelude('@function --foo(--x): <length>');
test_invalid_prelude('@function --foo(--x): length');
test_invalid_prelude('@function --foo(--x) returneth <length>');
</script>

View file

@ -0,0 +1,61 @@
// Looks for <template> elements, and runs each test in turn, for example:
//
// <template data-name="Example test">
// <style>
// @function --f() returns <length> {
// result: calc(1px + 1px);
// }
// #target {
// --actual: --f();
// --expected: 2px;
// }
// </style>
// </template>
//
// The test passes if the computed value of --actual matches
// the computed value of --expected on #target.
//
// Elements <div id=target> and <div=main> are assumed to exist.
function test_all_templates() {
let templates = document.querySelectorAll('template');
for (let template of templates) {
test((t) => {
t.add_cleanup(() => main.replaceChildren());
main.append(template.content.cloneNode(true));
let cs = getComputedStyle(target);
let actual = cs.getPropertyValue('--actual');
let expected = cs.getPropertyValue('--expected');
assert_equals(actual, expected);
}, template.getAttribute('data-name'));
}
}
// Within an array of elements, find an element with id=target (recursively,
// including shadows).
function find_target(elements) {
for (let e of (elements ?? [])) {
let t = e.id == 'target' ? e : null;
t ??= find_target(e.children);
t ??= find_target(e.shadowRoot?.children);
if (t) {
return t;
}
}
return null;
}
// Similar to test_all_templates(), but treats each <div data-name="...">
// as a test, and lets ShadowDOM do the "inflation".
function test_all_shadows() {
let hosts = document.querySelectorAll('div[data-name]');
for (let host of hosts) {
test((t) => {
let target = find_target([host]);
assert_true(target != null);
let cs = getComputedStyle(target);
let actual = cs.getPropertyValue('--actual');
let expected = cs.getPropertyValue('--expected');
assert_equals(actual, expected);
}, host.getAttribute('data-name'));
}
}