mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
Update web-platform-tests to revision 84f93271efe15a4e37fed477a2ad364f8659a0f8
This commit is contained in:
parent
5504d9259d
commit
77e26e71da
374 changed files with 25426 additions and 892 deletions
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue