Update web-platform-tests to revision 84f93271efe15a4e37fed477a2ad364f8659a0f8

This commit is contained in:
WPT Sync Bot 2020-04-23 08:19:14 +00:00
parent 5504d9259d
commit 77e26e71da
374 changed files with 25426 additions and 892 deletions

View file

@ -0,0 +1,190 @@
<!DOCTYPE html>
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="./resources/utils.js"></script>
<div id=outer>
<div id=div></div>
</div>
<script>
test_with_at_property({
syntax: '"<length>"',
inherits: false,
initialValue: '0px'
}, (name) => {
with_style_node(`
@keyframes test {
from { ${name}: 100px; }
to { ${name}: 200px; }
}
#div { animation: test 100s -50s linear; }
`, () => {
assert_equals(getComputedStyle(div).getPropertyValue(name), '150px');
});
}, '@keyframes works with @property');
test_with_at_property({
syntax: '"<length>"',
inherits: false,
initialValue: '0px'
}, (name) => {
with_style_node(`
@property ${name} {
syntax: "<color>";
inherits: false;
initial-value: black;
}
@keyframes test {
from { ${name}: rgb(100, 100, 100); }
to { ${name}: rgb(200, 200, 200); }
}
#div { animation: test 100s -50s linear; }
`, () => {
assert_equals(getComputedStyle(div).getPropertyValue(name), 'rgb(150, 150, 150)');
});
}, '@keyframes picks up the latest @property in the document');
test_with_at_property({
syntax: '"<length>"',
inherits: false,
initialValue: '0px'
}, (name) => {
// These keyframes are initially invalid for the declared custom property.
let animation = div.animate([
{ [name]: 'rgb(100, 100, 100)'},
{ [name]: 'rgb(200, 200, 200)'},
], { duration: 10000, delay: -5000, easing: 'linear' });
let cs = getComputedStyle(div);
assert_equals(cs.getPropertyValue(name), '0px');
// Redeclare the property as a <color>, effectively making the existing
// keyframes valid.
with_at_property({
name: name,
syntax: '"<color>"',
inherits: false,
initialValue: 'black'
}, (name) => {
assert_equals(cs.getPropertyValue(name), 'rgb(150, 150, 150)');
});
animation.finish();
}, 'Ongoing animation picks up redeclared custom property');
test_with_at_property({
syntax: '"<length>"',
inherits: false,
initialValue: '0px'
}, (name) => {
// These keyframes are initially invalid for the declared custom property.
let animation = div.animate([
{ [name]: 'rgb(100, 100, 100)'},
{ [name]: 'rgb(200, 200, 200)'},
], { duration: 10000, delay: -5000, easing: 'linear' });
let cs = getComputedStyle(div);
assert_equals(cs.getPropertyValue(name), '0px');
// Setting the keyframes to something that matches <length> makes the
// interpolation valid.
animation.effect.setKeyframes([
{[name]: '100px'},
{[name]: '200px'}
]);
assert_equals(cs.getPropertyValue(name), '150px');
animation.finish();
}, 'Ongoing animation matches new keyframes against the current registration');
test_with_at_property({
syntax: '"<length>"',
inherits: false,
initialValue: '0px'
}, (name) => {
let animation = div.animate([
{ [name]: 'initial'},
{ [name]: '400px'},
], { duration: 10000, delay: -5000, easing: 'linear' });
let cs = getComputedStyle(div);
assert_equals(cs.getPropertyValue(name), '200px');
// Change initial value.
with_at_property({
name: name,
syntax: '"<length>"',
inherits: false,
initialValue: '100px'
}, (name) => {
assert_equals(cs.getPropertyValue(name), '250px');
});
animation.finish();
}, 'Ongoing animation picks up redeclared intial value');
test_with_at_property({
syntax: '"<length>"',
inherits: false,
initialValue: '0px'
}, (name) => {
try {
document.body.style = `${name}: 100px`;
// Note that 'inherit' here refers to #outer, which has the initial
// value. (#outer did not inherit from body, since the property is not
// yet declared as inherited).
let animation = div.animate([
{ [name]: 'inherit'},
{ [name]: '400px'},
], { duration: 10000, delay: -5000, easing: 'linear' });
let cs = getComputedStyle(div);
assert_equals(cs.getPropertyValue(name), '200px');
// Change inherits to 'true'. The value should now propagate from body
// to #outer.
with_at_property({
name: name,
syntax: '"<length>"',
inherits: true,
initialValue: '0px'
}, (name) => {
assert_equals(cs.getPropertyValue(name), '250px');
});
animation.finish();
} finally {
document.body.style = '';
}
}, 'Ongoing animation picks up redeclared inherits flag');
test_with_at_property({
syntax: '"<length>"',
inherits: false,
initialValue: '0px'
}, (name) => {
try {
outer.style = `${name}: 100px`;
// 'unset' should take the initial value (not the value from #outer), since
// the property is not declared as inherited.
let animation = div.animate([
{ [name]: 'unset'},
{ [name]: '400px'},
], { duration: 10000, delay: -5000, easing: 'linear' });
let cs = getComputedStyle(div);
assert_equals(cs.getPropertyValue(name), '200px');
// Change inherits to 'true'. 'unset' now refers to #outer's value.
with_at_property({
name: name,
syntax: '"<length>"',
inherits: true,
initialValue: '0px'
}, (name) => {
assert_equals(cs.getPropertyValue(name), '250px');
});
animation.finish();
} finally {
outer.style = '';
}
}, 'Ongoing animation picks up redeclared meaning of \'unset\'');
</script>

View file

@ -0,0 +1,187 @@
<!DOCTYPE html>
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1/#cssom">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
@property --valid {
syntax: "<color> | none";
inherits: false;
initial-value: red;
}
@property --valid-reverse {
initial-value: 0px;
inherits: true;
syntax: "<length>";
}
@property --valid-universal {
syntax: "*";
inherits: false;
}
@property --valid-whitespace {
syntax: " <color>+ ";
inherits: false;
initial-value: red, blue;
}
@property --vALId {
syntax: "<color> | none";
inherits: false;
initial-value: red;
}
@property --no-descriptors {
}
@property --no-syntax {
inherits: false;
initial-value: red;
}
@property --no-inherits {
syntax: "<color> | none";
initial-value: red;
}
@property --no-initial-value {
syntax: "<color> | none";
inherits: false;
}
@property --syntax-only {
syntax: "<color> | none";
}
@property --inherits-only {
inherits: true;
}
@property --initial-value-only {
initial-value: red;
}
</style>
<script>
function find_at_property_rule(name) {
for (let rule of document.styleSheets[0].cssRules) {
if (rule.type != CSSRule.PROPERTY_RULE)
continue;
if (rule.name == name)
return rule;
}
return null;
}
function test_css_text(name, expected) {
test(() => {
let rule = find_at_property_rule(name);
assert_true(!!rule);
assert_equals(rule.cssText, expected);
}, `Rule for ${name} has expected cssText`);
}
function test_name(name) {
test(() => {
let rule = find_at_property_rule(name);
assert_true(!!rule);
assert_equals(rule.name, name);
}, `Rule for ${name} returns expected value for CSSPropertyRule.name`);
}
function test_syntax(name, expected) {
test(() => {
let rule = find_at_property_rule(name);
assert_true(!!rule);
assert_equals(rule.syntax, expected);
}, `Rule for ${name} returns expected value for CSSPropertyRule.syntax`);
}
function test_inherits(name, expected) {
test(() => {
let rule = find_at_property_rule(name);
assert_true(!!rule);
assert_equals(rule.inherits, expected);
}, `Rule for ${name} returns expected value for CSSPropertyRule.inherits`);
}
function test_initial_value(name, expected) {
test(() => {
let rule = find_at_property_rule(name);
assert_true(!!rule);
assert_equals(rule.initialValue, expected);
}, `Rule for ${name} returns expected value for CSSPropertyRule.initialValue`);
}
// CSSPropertyRule.cssText
test_css_text('--valid', '@property --valid { syntax: "<color> | none"; inherits: false; initial-value: red; }');
test_css_text('--valid-reverse', '@property --valid-reverse { syntax: "<length>"; inherits: true; initial-value: 0px; }');
test_css_text('--valid-universal', '@property --valid-universal { syntax: "*"; inherits: false; }');
test_css_text('--valid-whitespace', '@property --valid-whitespace { syntax: " <color>+ "; inherits: false; initial-value: red, blue; }');
test_css_text('--vALId', '@property --vALId { syntax: "<color> | none"; inherits: false; initial-value: red; }');
test_css_text('--no-descriptors', '@property --no-descriptors { }');
test_css_text('--no-syntax', '@property --no-syntax { inherits: false; initial-value: red; }');
test_css_text('--no-inherits', '@property --no-inherits { syntax: "<color> | none"; initial-value: red; }');
test_css_text('--no-initial-value', '@property --no-initial-value { syntax: "<color> | none"; inherits: false; }');
test_css_text('--syntax-only', '@property --syntax-only { syntax: "<color> | none"; }');
test_css_text('--inherits-only', '@property --inherits-only { inherits: true; }');
test_css_text('--initial-value-only', '@property --initial-value-only { initial-value: red; }');
// CSSPropertyRule.name
test_name('--valid');
test_name('--valid-reverse');
test_name('--valid-universal');
test_name('--valid-whitespace');
test_name('--vALId');
test_name('--no-descriptors');
test_name('--no-syntax');
test_name('--no-inherits');
test_name('--no-initial-value');
test_name('--syntax-only');
test_name('--inherits-only');
test_name('--initial-value-only');
// CSSPropertyRule.syntax
test_syntax('--valid', '<color> | none');
test_syntax('--valid-reverse', '<length>');
test_syntax('--valid-universal', '*');
test_syntax('--valid-whitespace', ' <color>+ ');
test_syntax('--vALId', '<color> | none');
test_syntax('--no-descriptors', '');
test_syntax('--no-syntax', '');
test_syntax('--no-inherits', '<color> | none');
test_syntax('--no-initial-value', '<color> | none');
test_syntax('--syntax-only', '<color> | none');
test_syntax('--inherits-only', '');
test_syntax('--initial-value-only', '');
// CSSPropertyRule.inherits
test_inherits('--valid', false);
test_inherits('--valid-reverse', true);
test_inherits('--valid-universal', false);
test_inherits('--valid-whitespace', false);
test_inherits('--vALId', false);
test_inherits('--no-descriptors', false);
test_inherits('--no-syntax', false);
test_inherits('--no-inherits', false);
test_inherits('--no-initial-value', false);
test_inherits('--syntax-only', false);
test_inherits('--inherits-only', true);
test_inherits('--initial-value-only', false);
// CSSPropertyRule.initialValue
test_initial_value('--valid', ' red');
test_initial_value('--valid-reverse', ' 0px');
test_initial_value('--valid-universal', null);
test_initial_value('--valid-whitespace', ' red, blue');
test_initial_value('--vALId', ' red');
test_initial_value('--no-descriptors', null);
test_initial_value('--no-syntax', ' red');
test_initial_value('--no-inherits', ' red');
test_initial_value('--no-initial-value', null);
test_initial_value('--syntax-only', null);
test_initial_value('--inherits-only', null);
test_initial_value('--initial-value-only', ' red');
</script>

View file

@ -0,0 +1,46 @@
<!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>
<style>
@property --x {
syntax: "<length>";
inherits: false;
initial-value: 0px;
}
#outside {
--x: calc(1px + 1px);
--y: calc(1px + 1px);
}
</style>
<template id=template>
<style>
/* This rule should have no effect */
@property --y {
syntax: "<length>";
inherits: false;
initial-value: 0px;
}
#inside {
--x: calc(1px + 1px);
--y: calc(1px + 1px);
}
</style>
<div id=inside></div>
</template>
<div id=host></div>
<div id=outside></div>
<script>
test(() => {
let root = host.attachShadow({ mode: 'open' });
root.append(template.content.cloneNode(true));
let inside = root.querySelector('#inside');
assert_equals(getComputedStyle(outside).getPropertyValue('--x'), '2px');
assert_equals(getComputedStyle(outside).getPropertyValue('--y'), ' calc(1px + 1px)');
assert_equals(getComputedStyle(inside).getPropertyValue('--x'), '2px');
assert_equals(getComputedStyle(inside).getPropertyValue('--y'), ' calc(1px + 1px)');
}, '@property rules in shadow trees should have no effect');
</script>

View file

@ -0,0 +1,106 @@
<!DOCTYPE html>
<title>Verify that the correct registration is selected for mutated stylesheets</title>
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1/#determining-registration">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="./resources/utils.js"></script>
<div id=div></div>
<script>
test(() => {
with_at_property({
syntax: '"<length>"',
inherits: false,
initialValue: '1px'
}, (name) => {
assert_equals(getComputedStyle(div).getPropertyValue(name), '1px');
});
}, '@property detected when stylesheet appears');
test(() => {
let name = generate_name();
with_at_property({
name: name,
syntax: '"<length>"',
inherits: false,
initialValue: '1px'
}, (name) => {
assert_equals(getComputedStyle(div).getPropertyValue(name), '1px');
});
assert_equals(getComputedStyle(div).getPropertyValue(name), '');
}, '@property removal detected when last @property rule disappears');
test(() => {
with_at_property({
syntax: '"<length>"',
inherits: false,
initialValue: '1px'
}, (name1) => {
with_at_property({
syntax: '"<length>"',
inherits: false,
initialValue: '2px'
}, (name2) => {
assert_equals(getComputedStyle(div).getPropertyValue(name2), '2px');
});
});
}, '@property detected in second stylesheet');
test(() => {
let name2 = generate_name();
with_at_property({
syntax: '"<length>"',
inherits: false,
initialValue: '1px'
}, (name1) => {
with_at_property({
name2: name2,
syntax: '"<length>"',
inherits: false,
initialValue: '2px'
}, (name2) => {
assert_equals(getComputedStyle(div).getPropertyValue(name2), '2px');
});
assert_equals(getComputedStyle(div).getPropertyValue(name2), '');
});
}, '@property removal detected with removal of second stylesheet');
test(() => {
let name1 = generate_name();
let name2 = generate_name();
let sheet1 = `
@property ${name1} {
inherits: false;
syntax: "<length>";
initial-value: 1px;
}
`;
let sheet2 = `
@property ${name2} {
inherits: false;
syntax: "<length>";
initial-value: 2px;
}
`;
let node1 = document.createElement('style');
let node2 = document.createElement('style');
node1.textContent = sheet1;
node2.textContent = sheet2;
try {
document.body.append(node1, node2);
assert_equals(getComputedStyle(div).getPropertyValue(name1), '1px');
assert_equals(getComputedStyle(div).getPropertyValue(name2), '2px');
node1.remove();
assert_equals(getComputedStyle(div).getPropertyValue(name1), '');
assert_equals(getComputedStyle(div).getPropertyValue(name2), '2px');
} finally {
node1.remove();
node2.remove();
}
}, '@property removal detected with removal of first stylesheet');
</script>

View file

@ -0,0 +1,224 @@
<!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) {
let camel = to_camel_case(descriptor);
if (typeof(expected_value) === 'undefined')
expected_value = specified_value;
test_with_at_property({ [camel]: specified_value }, (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 | bar | baz"', 'foo | bar | baz');
test_descriptor('syntax', '"*"', '*');
test_descriptor('syntax', '"notasyntax"', 'notasyntax');
test_descriptor('syntax', 'red', '');
test_descriptor('syntax', 'rgb(255, 0, 0)', '');
test_descriptor('syntax', '<color>', '');
test_descriptor('syntax', 'foo | bar', '');
// 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', 'if(){}');
test_descriptor('initial-value', 'var(--x)');
// inherits
test_descriptor('inherits', 'true', true);
test_descriptor('inherits', 'false', false);
test_descriptor('inherits', 'none', false);
test_descriptor('inherits', '0', false);
test_descriptor('inherits', '1', false);
test_descriptor('inherits', '"true"', false);
test_descriptor('inherits', '"false"', false);
test_descriptor('inherits', 'calc(0)', false);
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('*', 'if(){}', false, 'if(){}');
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/")');
// 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);
// 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,134 @@
<!DOCTYPE html>
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1/#determining-registration">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="./resources/utils.js"></script>
<style>
@property --a {
syntax: "<length>";
inherits: false;
initial-value: 1px;
}
@property --b {
syntax: "<length>";
inherits: false;
initial-value: 2px;
}
@property --c {
syntax: "<length>";
inherits: false;
initial-value: 3px;
}
@property --d {
syntax: "<length>";
inherits: false;
initial-value: 4px;
}
@property --d {
syntax: "<color>";
inherits: false;
initial-value: red;
}
</style>
<style>
@property --c {
syntax: "<integer>";
inherits: false;
initial-value: 6;
}
</style>
<div id=outer>
<div id=div></div>
</div>
<script>
CSS.registerProperty({
name: '--b',
syntax: '<color>',
inherits: false,
initialValue: 'green'
});
CSS.registerProperty({
name: '--e',
syntax: '<color>',
inherits: false,
initialValue: 'blue'
});
test(() => {
assert_equals(getComputedStyle(div).getPropertyValue('--a'), '1px');
}, '@property determines the registration when uncontested');
test(() => {
assert_equals(getComputedStyle(div).getPropertyValue('--b'), 'rgb(0, 128, 0)');
}, 'CSS.registerProperty wins over @property');
test(() => {
assert_equals(getComputedStyle(div).getPropertyValue('--c'), '6');
}, '@property later in document order wins');
test(() => {
assert_equals(getComputedStyle(div).getPropertyValue('--d'), 'rgb(255, 0, 0)');
}, '@property later in stylesheet wins');
test(() => {
assert_equals(getComputedStyle(div).getPropertyValue('--e'), 'rgb(0, 0, 255)');
}, 'CSS.registerProperty determines the registration when uncontested');
test(() => {
// --f is initially not registered, hence has no initial value.
assert_equals(getComputedStyle(div).getPropertyValue('--f'), '');
with_at_property({
name: '--f',
syntax: '"<length>"',
inherits: false,
initialValue: '10px'
}, () => {
assert_equals(getComputedStyle(div).getPropertyValue('--f'), '10px');
});
// When the style node is removed, --f should be unregistered again.
assert_equals(getComputedStyle(div).getPropertyValue('--f'), '');
}, '@property registrations are cleared when rule removed');
test_with_style_node('div { --g: calc(1px + 1px); }', () => {
// --g should be a token sequence at this point.
assert_equals(getComputedStyle(div).getPropertyValue('--g'), ' calc(1px + 1px)');
with_at_property({
name: '--g',
syntax: '"<length>"',
inherits: false,
initialValue: '0px'
}, () => {
// --g is now a <length>, hence the calc() should be simplified.
assert_equals(getComputedStyle(div).getPropertyValue('--g'), '2px');
});
// --g should be a token sequence again.
assert_equals(getComputedStyle(div).getPropertyValue('--g'), ' calc(1px + 1px)');
}, 'Computed value becomes token sequence when @property is removed');
test_with_style_node('#outer { --h: 10px; }', () => {
assert_equals(getComputedStyle(div).getPropertyValue('--h'), ' 10px');
with_at_property({
name: '--h',
syntax: '"<length>"',
inherits: false,
initialValue: '0px'
}, () => {
// --h is no longer inherited
assert_equals(getComputedStyle(div).getPropertyValue('--h'), '0px');
});
assert_equals(getComputedStyle(div).getPropertyValue('--h'), ' 10px');
}, 'Inherited status is reflected in computed styles when @property is removed');
</script>

View file

@ -92,3 +92,35 @@ function all_syntaxes() {
'<url>'
]
}
function with_style_node(text, fn) {
let node = document.createElement('style');
node.textContent = text;
try {
document.body.append(node);
fn(node);
} finally {
node.remove();
}
}
function with_at_property(desc, fn) {
let name = typeof(desc.name) === 'undefined' ? generate_name() : desc.name;
let text = `@property ${name} {`;
if (typeof(desc.syntax) !== 'undefined')
text += `syntax:${desc.syntax};`;
if (typeof(desc.initialValue) !== 'undefined')
text += `initial-value:${desc.initialValue};`;
if (typeof(desc.inherits) !== 'undefined')
text += `inherits:${desc.inherits};`;
text += '}';
with_style_node(text, (node) => fn(name, node.sheet.rules[0]));
}
function test_with_at_property(desc, fn, description) {
test(() => with_at_property(desc, fn), description);
}
function test_with_style_node(text, fn, description) {
test(() => with_style_node(text, fn), description);
}