mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-11 02:29:21 +00:00
Tests: Import some css/css-properties-values-api
WPT tests
Casual import of 4 WPT tests related to `CSS.registerProperty`
This commit is contained in:
parent
90c0decd95
commit
ab574deb93
Notes:
github-actions[bot]
2025-07-22 09:59:12 +00:00
Author: https://github.com/Norbiros
Commit: ab574deb93
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5507
Reviewed-by: https://github.com/AtkinsSJ ✅
9 changed files with 881 additions and 0 deletions
|
@ -0,0 +1,12 @@
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Found 6 tests
|
||||||
|
|
||||||
|
5 Pass
|
||||||
|
1 Fail
|
||||||
|
Pass registerProperty requires a Dictionary type
|
||||||
|
Pass registerProperty requires a name matching <custom-property-name>
|
||||||
|
Pass registerProperty only allows omitting initialValue if syntax is '*'
|
||||||
|
Pass registerProperty fails for an already registered property
|
||||||
|
Pass registerProperty requires inherits
|
||||||
|
Fail Registering a property should not cause a transition
|
|
@ -0,0 +1,14 @@
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Found 8 tests
|
||||||
|
|
||||||
|
2 Pass
|
||||||
|
6 Fail
|
||||||
|
Fail Registered properties are correctly inherited (or not) depending on the inherits flag.
|
||||||
|
Fail Explicitly inheriting from a parent with an invalid value results in initial value.
|
||||||
|
Pass Explicitly inheriting from a parent with no value results in initial value.
|
||||||
|
Pass Explicitly inheriting from a parent with a value results in that value.
|
||||||
|
Fail Reference to undefined variable results in inherited value
|
||||||
|
Fail Reference to syntax-incompatible variable results in inherited value
|
||||||
|
Fail Font-relative units are absolutized before before inheritance
|
||||||
|
Fail Calc expressions are resolved before inheritance
|
|
@ -0,0 +1,11 @@
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Found 5 tests
|
||||||
|
|
||||||
|
2 Pass
|
||||||
|
3 Fail
|
||||||
|
Fail A var() cycle between two registered properties is handled correctly.
|
||||||
|
Fail A var() cycle between a registered properties and an unregistered property is handled correctly.
|
||||||
|
Fail A var() cycle between a two unregistered properties is handled correctly.
|
||||||
|
Pass A var() cycle between a syntax:'*' property and an unregistered property is handled correctly.
|
||||||
|
Pass Custom properties with universal syntax become guaranteed-invalid when invalid at computed-value time
|
|
@ -0,0 +1,22 @@
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Found 16 tests
|
||||||
|
|
||||||
|
7 Pass
|
||||||
|
9 Fail
|
||||||
|
Fail var() references work with registered properties
|
||||||
|
Fail References to registered var()-properties work in registered lists
|
||||||
|
Fail References to mixed registered and unregistered var()-properties work in registered lists
|
||||||
|
Fail Registered lists may be concatenated
|
||||||
|
Fail Font-relative units are absolutized when substituting
|
||||||
|
Fail Calc expressions are resolved when substituting
|
||||||
|
Fail Lists with relative units are absolutized when substituting
|
||||||
|
Fail Values are absolutized when substituting into properties with universal syntax
|
||||||
|
Fail Invalid values for registered properties are serialized as the empty string
|
||||||
|
Pass Valid fallback does not invalidate var()-reference [<length>, 10px]
|
||||||
|
Pass Valid fallback does not invalidate var()-reference [<length> | <color>, red]
|
||||||
|
Pass Valid fallback does not invalidate var()-reference [<length> | none, none]
|
||||||
|
Pass Invalid fallback doesn't invalidate var()-reference [<length>, red]
|
||||||
|
Pass Invalid fallback doesn't invalidate var()-reference [<length> | none, nolength]
|
||||||
|
Pass Invalid fallback doesn't invalidate var()-reference [<length>, var(--novar)]
|
||||||
|
Pass Empty universal custom property can be substituted with var()
|
|
@ -0,0 +1,75 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api/#register-a-custom-property" />
|
||||||
|
<script src="../../resources/testharness.js"></script>
|
||||||
|
<script src="../../resources/testharnessreport.js"></script>
|
||||||
|
<script src="./resources/utils.js"></script>
|
||||||
|
<div id=target></div>
|
||||||
|
<script>
|
||||||
|
// Tests for error checking during property registration
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
assert_throws_js(TypeError, () => CSS.registerProperty());
|
||||||
|
assert_throws_js(TypeError, () => CSS.registerProperty(undefined));
|
||||||
|
assert_throws_js(TypeError, () => CSS.registerProperty(true));
|
||||||
|
assert_throws_js(TypeError, () => CSS.registerProperty(2));
|
||||||
|
assert_throws_js(TypeError, () => CSS.registerProperty("css"));
|
||||||
|
assert_throws_js(TypeError, () => CSS.registerProperty(null));
|
||||||
|
}, "registerProperty requires a Dictionary type");
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
// Valid property names, shouldn't throw
|
||||||
|
CSS.registerProperty({name: '--name1', inherits: false});
|
||||||
|
CSS.registerProperty({name: '--name2, no need for escapes', inherits: false});
|
||||||
|
CSS.registerProperty({name: ['--name', 3], inherits: false});
|
||||||
|
|
||||||
|
// Invalid property names
|
||||||
|
assert_throws_js(TypeError, () => CSS.registerProperty({}));
|
||||||
|
assert_throws_dom("SyntaxError", () => CSS.registerProperty({name: 'no-leading-dash', inherits: false}));
|
||||||
|
assert_throws_dom("SyntaxError", () => CSS.registerProperty({name: '', inherits: false}));
|
||||||
|
assert_throws_dom("SyntaxError", () => CSS.registerProperty({name: '\\--name', inherits: false}));
|
||||||
|
}, "registerProperty requires a name matching <custom-property-name>");
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
CSS.registerProperty({name: '--syntax-test-1', syntax: '*', inherits: false});
|
||||||
|
CSS.registerProperty({name: '--syntax-test-2', syntax: ' * ', inherits: false});
|
||||||
|
assert_throws_dom("SyntaxError",
|
||||||
|
() => CSS.registerProperty({name: '--syntax-test-3', syntax: 'length', inherits: false}));
|
||||||
|
}, "registerProperty only allows omitting initialValue if syntax is '*'");
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
CSS.registerProperty({name: '--re-register', syntax: '<length>', initialValue: '0px', inherits: false});
|
||||||
|
assert_throws_dom('InvalidModificationError',
|
||||||
|
() => CSS.registerProperty({name: '--re-register', syntax: '<percentage>', initialValue: '0%', inherits: false}));
|
||||||
|
}, "registerProperty fails for an already registered property");
|
||||||
|
|
||||||
|
test(function(){
|
||||||
|
CSS.registerProperty({name: '--inherit-test-1', syntax: '<length>', initialValue: '0px', inherits: true});
|
||||||
|
CSS.registerProperty({name: '--inherit-test-2', syntax: '<length>', initialValue: '0px', inherits: false});
|
||||||
|
assert_throws_js(TypeError, () => CSS.registerProperty({name: '--inherit-test-3', syntax: '<length>', initialValue: '0px'}));
|
||||||
|
}, "registerProperty requires inherits");
|
||||||
|
|
||||||
|
test(function(){
|
||||||
|
try {
|
||||||
|
let name = generate_name();
|
||||||
|
|
||||||
|
target.style.setProperty(name, 'green');
|
||||||
|
target.style.transitionProperty = name;
|
||||||
|
target.style.transitionDuration = '1s';
|
||||||
|
target.style.transitionTimingFunction = 'steps(1, end)';
|
||||||
|
|
||||||
|
assert_equals(getComputedStyle(target).getPropertyValue(name), 'green');
|
||||||
|
|
||||||
|
CSS.registerProperty({
|
||||||
|
name: name,
|
||||||
|
syntax: '<color>',
|
||||||
|
initialValue: 'red',
|
||||||
|
inherits: false
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_equals(getComputedStyle(target).getPropertyValue(name), 'rgb(0, 128, 0)');
|
||||||
|
} finally {
|
||||||
|
target.style = '';
|
||||||
|
}
|
||||||
|
}, 'Registering a property should not cause a transition');
|
||||||
|
|
||||||
|
</script>
|
|
@ -0,0 +1,96 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api/#dom-propertydescriptor-inherits" />
|
||||||
|
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api/#register-a-custom-property" />
|
||||||
|
<script src="../../resources/testharness.js"></script>
|
||||||
|
<script src="../../resources/testharnessreport.js"></script>
|
||||||
|
<style>
|
||||||
|
#outer {
|
||||||
|
--inherited-length-1: 10px;
|
||||||
|
--inherited-length-2: var(--non-inherited-length-1);
|
||||||
|
--inherited-length-3: 30px;
|
||||||
|
--non-inherited-length-1: 22px;
|
||||||
|
--non-inherited-length-3: calc(var(--non-inherited-length-2) * 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
#inner {
|
||||||
|
--inherited-length-3: 15px;
|
||||||
|
--non-inherited-length-1: 40px;
|
||||||
|
--non-inherited-length-2: 90px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div id=outer><div id=inner></div></div>
|
||||||
|
<script>
|
||||||
|
test(function() {
|
||||||
|
CSS.registerProperty({name: '--inherited-length-1', syntax: '<length>', initialValue: '1px', inherits: true});
|
||||||
|
CSS.registerProperty({name: '--inherited-length-2', syntax: '<length>', initialValue: '2px', inherits: true});
|
||||||
|
CSS.registerProperty({name: '--inherited-length-3', syntax: '<length>', initialValue: '3px', inherits: true});
|
||||||
|
CSS.registerProperty({name: '--non-inherited-length-1', syntax: '<length>', initialValue: '4px', inherits: false});
|
||||||
|
CSS.registerProperty({name: '--non-inherited-length-2', syntax: '<length>', initialValue: '5px', inherits: false});
|
||||||
|
CSS.registerProperty({name: '--non-inherited-length-3', syntax: '<length>', initialValue: '6px', inherits: false});
|
||||||
|
|
||||||
|
outerComputedStyle = getComputedStyle(outer);
|
||||||
|
assert_equals(outerComputedStyle.getPropertyValue('--inherited-length-1'), '10px');
|
||||||
|
assert_equals(outerComputedStyle.getPropertyValue('--inherited-length-2'), '22px');
|
||||||
|
assert_equals(outerComputedStyle.getPropertyValue('--inherited-length-3'), '30px');
|
||||||
|
assert_equals(outerComputedStyle.getPropertyValue('--non-inherited-length-1'), '22px');
|
||||||
|
assert_equals(outerComputedStyle.getPropertyValue('--non-inherited-length-2'), '5px');
|
||||||
|
assert_equals(outerComputedStyle.getPropertyValue('--non-inherited-length-3'), '50px');
|
||||||
|
|
||||||
|
innerComputedStyle = getComputedStyle(inner);
|
||||||
|
assert_equals(innerComputedStyle.getPropertyValue('--inherited-length-1'), '10px');
|
||||||
|
assert_equals(innerComputedStyle.getPropertyValue('--inherited-length-2'), '22px');
|
||||||
|
assert_equals(innerComputedStyle.getPropertyValue('--inherited-length-3'), '15px');
|
||||||
|
assert_equals(innerComputedStyle.getPropertyValue('--non-inherited-length-1'), '40px');
|
||||||
|
assert_equals(innerComputedStyle.getPropertyValue('--non-inherited-length-2'), '90px');
|
||||||
|
assert_equals(innerComputedStyle.getPropertyValue('--non-inherited-length-3'), '6px');
|
||||||
|
}, "Registered properties are correctly inherited (or not) depending on the inherits flag.");
|
||||||
|
|
||||||
|
test(function(){
|
||||||
|
CSS.registerProperty({name: '--initial-length-1', syntax: '<length>', initialValue: '0px', inherits: false});
|
||||||
|
outer.style = '--initial-length-1: notalength';
|
||||||
|
inner.style = '--initial-length-1: inherit';
|
||||||
|
assert_equals(getComputedStyle(inner).getPropertyValue('--initial-length-1'), '0px');
|
||||||
|
}, "Explicitly inheriting from a parent with an invalid value results in initial value.");
|
||||||
|
|
||||||
|
test(function(){
|
||||||
|
CSS.registerProperty({name: '--initial-length-2', syntax: '<length>', initialValue: '0px', inherits: false});
|
||||||
|
inner.style = '--initial-length-2: inherit';
|
||||||
|
assert_equals(getComputedStyle(inner).getPropertyValue('--initial-length-2'), '0px');
|
||||||
|
}, "Explicitly inheriting from a parent with no value results in initial value.");
|
||||||
|
|
||||||
|
test(function(){
|
||||||
|
CSS.registerProperty({name: '--initial-length-3', syntax: '<length>', initialValue: '0px', inherits: false});
|
||||||
|
outer.style = '--initial-length-3: 100px';
|
||||||
|
inner.style = '--initial-length-3: inherit';
|
||||||
|
assert_equals(getComputedStyle(inner).getPropertyValue('--initial-length-3'), '100px');
|
||||||
|
}, "Explicitly inheriting from a parent with a value results in that value.");
|
||||||
|
|
||||||
|
test(function(){
|
||||||
|
CSS.registerProperty({name: '--inherited-length-4', syntax: '<length>', initialValue: '0px', inherits: true});
|
||||||
|
outer.style = '--inherited-length-4: 42px';
|
||||||
|
inner.style = '--inherited-length-4: var(--undefined)';
|
||||||
|
assert_equals(getComputedStyle(inner).getPropertyValue('--inherited-length-4'), '42px');
|
||||||
|
}, "Reference to undefined variable results in inherited value");
|
||||||
|
|
||||||
|
test(function(){
|
||||||
|
CSS.registerProperty({name: '--inherited-length-5', syntax: '<length>', initialValue: '0px', inherits: true});
|
||||||
|
outer.style = '--inherited-length-5: 42px';
|
||||||
|
inner.style = '--incompatible: nolength; --inherited-length-5: var(--incompatible)';
|
||||||
|
assert_equals(getComputedStyle(inner).getPropertyValue('--inherited-length-5'), '42px');
|
||||||
|
}, "Reference to syntax-incompatible variable results in inherited value");
|
||||||
|
|
||||||
|
test(function(){
|
||||||
|
CSS.registerProperty({name: '--inherited-em', syntax: '<length>', initialValue: '0px', inherits: true});
|
||||||
|
outer.style = 'font-size: 11px; --inherited-em: 10em;';
|
||||||
|
inner.style = 'font-size: 22px; --unregistered:var(--inherited-em);';
|
||||||
|
assert_equals(getComputedStyle(inner).getPropertyValue('--unregistered'), '110px');
|
||||||
|
}, "Font-relative units are absolutized before before inheritance");
|
||||||
|
|
||||||
|
test(function(){
|
||||||
|
CSS.registerProperty({name: '--calc-length', syntax: '<length>', initialValue: '0px', inherits: true});
|
||||||
|
outer.style = '--calc-length: calc(10px + 10px);';
|
||||||
|
inner.style = '--unregistered:var(--calc-length);';
|
||||||
|
assert_equals(getComputedStyle(inner).getPropertyValue('--unregistered'), '20px');
|
||||||
|
}, "Calc expressions are resolved before inheritance");
|
||||||
|
|
||||||
|
</script>
|
|
@ -0,0 +1,261 @@
|
||||||
|
let next_property_id = 1;
|
||||||
|
|
||||||
|
// Generate a unique property name on the form --prop-N.
|
||||||
|
function generate_name() {
|
||||||
|
return `--prop-${next_property_id++}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Produce a compatible initial value for the specified syntax.
|
||||||
|
function any_initial_value(syntax) {
|
||||||
|
let components = syntax.split('|').map(x => x.trim())
|
||||||
|
let first_component = components[0];
|
||||||
|
|
||||||
|
if (first_component.endsWith('+') || first_component.endsWith('#'))
|
||||||
|
first_component = first_component.slice(0, -1);
|
||||||
|
|
||||||
|
switch (first_component) {
|
||||||
|
case '*':
|
||||||
|
case '<custom-ident>':
|
||||||
|
return 'NULL';
|
||||||
|
case '<angle>':
|
||||||
|
return '0deg';
|
||||||
|
case '<color>':
|
||||||
|
return 'rgb(0, 0, 0)';
|
||||||
|
case '<image>':
|
||||||
|
case '<url>':
|
||||||
|
return 'url(0)';
|
||||||
|
case '<integer>':
|
||||||
|
case '<length-percentage>':
|
||||||
|
case '<length>':
|
||||||
|
case '<number>':
|
||||||
|
return '0';
|
||||||
|
case '<percentage>':
|
||||||
|
return '0%';
|
||||||
|
case '<resolution>':
|
||||||
|
return '0dpi';
|
||||||
|
case '<time>':
|
||||||
|
return '0s';
|
||||||
|
case '<transform-function>':
|
||||||
|
case '<transform-list>':
|
||||||
|
return 'matrix(0, 0, 0, 0, 0, 0)';
|
||||||
|
default:
|
||||||
|
// We assume syntax is a specific custom ident.
|
||||||
|
return first_component;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Registers a unique property on the form '--prop-N' and returns the name.
|
||||||
|
// Any value except 'syntax' may be omitted, in which case the property will
|
||||||
|
// not inherit, and some undefined (but compatible) initial value will be
|
||||||
|
// generated. If a single string is used as the argument, it is assumed to be
|
||||||
|
// the syntax.
|
||||||
|
function generate_property(reg) {
|
||||||
|
// Verify that only valid keys are specified. This prevents the caller from
|
||||||
|
// accidentally supplying 'inherited' instead of 'inherits', for example.
|
||||||
|
if (typeof(reg) === 'object') {
|
||||||
|
const permitted = new Set(['name', 'syntax', 'initialValue', 'inherits']);
|
||||||
|
if (!Object.keys(reg).every(k => permitted.has(k)))
|
||||||
|
throw new Error('generate_property: invalid parameter');
|
||||||
|
}
|
||||||
|
|
||||||
|
let syntax = typeof(reg) === 'string' ? reg : reg.syntax;
|
||||||
|
let initial = typeof(reg.initialValue) === 'undefined' ? any_initial_value(syntax)
|
||||||
|
: reg.initialValue;
|
||||||
|
let inherits = typeof(reg.inherits) === 'undefined' ? false : reg.inherits;
|
||||||
|
|
||||||
|
let name = generate_name();
|
||||||
|
CSS.registerProperty({
|
||||||
|
name: name,
|
||||||
|
syntax: syntax,
|
||||||
|
initialValue: initial,
|
||||||
|
inherits: inherits
|
||||||
|
});
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
function all_syntaxes() {
|
||||||
|
return [
|
||||||
|
'*',
|
||||||
|
'<angle>',
|
||||||
|
'<color>',
|
||||||
|
'<custom-ident>',
|
||||||
|
'<image>',
|
||||||
|
'<integer>',
|
||||||
|
'<length-percentage>',
|
||||||
|
'<length>',
|
||||||
|
'<number>',
|
||||||
|
'<percentage>',
|
||||||
|
'<resolution>',
|
||||||
|
'<time>',
|
||||||
|
'<transform-function>',
|
||||||
|
'<transform-list>',
|
||||||
|
'<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);
|
||||||
|
}
|
||||||
|
|
||||||
|
function animation_test(property, values, description) {
|
||||||
|
const name = generate_name();
|
||||||
|
property.name = name;
|
||||||
|
CSS.registerProperty(property);
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
const duration = 1000;
|
||||||
|
const keyframes = {};
|
||||||
|
keyframes[name] = values.keyframes;
|
||||||
|
|
||||||
|
const iterations = 3;
|
||||||
|
const composite = values.composite || "replace";
|
||||||
|
const iterationComposite = values.iterationComposite || "replace";
|
||||||
|
const animation = target.animate(keyframes, { composite, iterationComposite, iterations, duration });
|
||||||
|
animation.pause();
|
||||||
|
// We seek to the middle of the third iteration which will allow to test cases where
|
||||||
|
// iterationComposite is set to something other than "replace".
|
||||||
|
animation.currentTime = duration * 2.5;
|
||||||
|
|
||||||
|
const assert_equals_function = values.assert_function || assert_equals;
|
||||||
|
assert_equals_function(getComputedStyle(target).getPropertyValue(name), values.expected);
|
||||||
|
}, description);
|
||||||
|
};
|
||||||
|
|
||||||
|
function discrete_animation_test(syntax, fromValue, toValue, description) {
|
||||||
|
test(() => {
|
||||||
|
const name = generate_name();
|
||||||
|
|
||||||
|
CSS.registerProperty({
|
||||||
|
name,
|
||||||
|
syntax,
|
||||||
|
inherits: false,
|
||||||
|
initialValue: fromValue
|
||||||
|
});
|
||||||
|
|
||||||
|
const duration = 1000;
|
||||||
|
const keyframes = [];
|
||||||
|
keyframes[name] = toValue;
|
||||||
|
const animation = target.animate(keyframes, duration);
|
||||||
|
animation.pause();
|
||||||
|
|
||||||
|
const checkAtProgress = (progress, expected) => {
|
||||||
|
animation.currentTime = duration * 0.25;
|
||||||
|
assert_equals(getComputedStyle(target).getPropertyValue(name), fromValue, `The correct value is used at progress = ${progress}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
checkAtProgress(0, fromValue);
|
||||||
|
checkAtProgress(0.25, fromValue);
|
||||||
|
checkAtProgress(0.49, fromValue);
|
||||||
|
checkAtProgress(0.5, toValue);
|
||||||
|
checkAtProgress(0.75, toValue);
|
||||||
|
checkAtProgress(1, toValue);
|
||||||
|
}, description || `Animating a custom property of type ${syntax} is discrete`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function transition_test(options, description) {
|
||||||
|
promise_test(async () => {
|
||||||
|
const customProperty = generate_name();
|
||||||
|
|
||||||
|
options.transitionProperty ??= customProperty;
|
||||||
|
|
||||||
|
CSS.registerProperty({
|
||||||
|
name: customProperty,
|
||||||
|
syntax: options.syntax,
|
||||||
|
inherits: false,
|
||||||
|
initialValue: options.from
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_equals(getComputedStyle(target).getPropertyValue(customProperty), options.from, "Element has the expected initial value");
|
||||||
|
|
||||||
|
const transitionEventPromise = new Promise(resolve => {
|
||||||
|
let listener = event => {
|
||||||
|
target.removeEventListener("transitionrun", listener);
|
||||||
|
assert_equals(event.propertyName, customProperty, "TransitionEvent has the expected property name");
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
target.addEventListener("transitionrun", listener);
|
||||||
|
});
|
||||||
|
|
||||||
|
target.style.transition = `${options.transitionProperty} 1s -500ms linear`;
|
||||||
|
if (options.behavior) {
|
||||||
|
target.style.transitionBehavior = options.behavior;
|
||||||
|
}
|
||||||
|
target.style.setProperty(customProperty, options.to);
|
||||||
|
|
||||||
|
const animations = target.getAnimations();
|
||||||
|
assert_equals(animations.length, 1, "A single animation is running");
|
||||||
|
|
||||||
|
const transition = animations[0];
|
||||||
|
assert_class_string(transition, "CSSTransition", "A CSSTransition is running");
|
||||||
|
|
||||||
|
transition.pause();
|
||||||
|
assert_equals(getComputedStyle(target).getPropertyValue(customProperty), options.expected, "Element has the expected animated value");
|
||||||
|
|
||||||
|
await transitionEventPromise;
|
||||||
|
}, description);
|
||||||
|
}
|
||||||
|
|
||||||
|
function no_transition_test(options, description) {
|
||||||
|
test(() => {
|
||||||
|
const customProperty = generate_name();
|
||||||
|
|
||||||
|
CSS.registerProperty({
|
||||||
|
name: customProperty,
|
||||||
|
syntax: options.syntax,
|
||||||
|
inherits: false,
|
||||||
|
initialValue: options.from
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_equals(getComputedStyle(target).getPropertyValue(customProperty), options.from, "Element has the expected initial value");
|
||||||
|
|
||||||
|
target.style.transition = `${customProperty} 1s -500ms linear`;
|
||||||
|
target.style.setProperty(customProperty, options.to);
|
||||||
|
|
||||||
|
assert_equals(target.getAnimations().length, 0, "No animation was created");
|
||||||
|
assert_equals(getComputedStyle(target).getPropertyValue(customProperty), options.to, "Element has the expected final value");
|
||||||
|
}, description);
|
||||||
|
};
|
||||||
|
|
||||||
|
function test_initial_value_valid(syntax, initialValue) {
|
||||||
|
// No actual assertions, this just shouldn't throw
|
||||||
|
test(() => {
|
||||||
|
var name = generate_name();
|
||||||
|
CSS.registerProperty({name: name, syntax: syntax, initialValue: initialValue, inherits: false});
|
||||||
|
}, "syntax:'" + syntax + "', initialValue:'" + initialValue + "' is valid");
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_initial_value_invalid(syntax, initialValue) {
|
||||||
|
test(() =>{
|
||||||
|
var name = generate_name();
|
||||||
|
assert_throws_dom("SyntaxError",
|
||||||
|
() => CSS.registerProperty({name: name, syntax: syntax, initialValue: initialValue, inherits: false}));
|
||||||
|
}, "syntax:'" + syntax + "', initialValue:'" + initialValue + "' is invalid");
|
||||||
|
}
|
|
@ -0,0 +1,183 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api/#dom-css-registerproperty" />
|
||||||
|
<script src="../../resources/testharness.js"></script>
|
||||||
|
<script src="../../resources/testharnessreport.js"></script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#test1 {
|
||||||
|
--registered-1-a: var(--registered-1-b, 10px);
|
||||||
|
--registered-1-b: var(--registered-1-a, 20px);
|
||||||
|
|
||||||
|
--registered-1-c: var(--registered-1-b, 30px);
|
||||||
|
--registered-1-d: var(--registered-1-b);
|
||||||
|
--unregistered-1-a:var(--registered-1-a,40px);
|
||||||
|
--unregistered-1-a:var(--registered-1-a);
|
||||||
|
left: var(--registered-1-a, 50px);
|
||||||
|
top: var(--registered-1-b, 60px);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div id=test1></div>
|
||||||
|
<script>
|
||||||
|
test(function() {
|
||||||
|
CSS.registerProperty({name: '--registered-1-a', syntax: '<length>', initialValue: '1px', inherits: false});
|
||||||
|
CSS.registerProperty({name: '--registered-1-b', syntax: '<length>', initialValue: '2px', inherits: false});
|
||||||
|
CSS.registerProperty({name: '--registered-1-c', syntax: '<length>', initialValue: '3px', inherits: false});
|
||||||
|
CSS.registerProperty({name: '--registered-1-d', syntax: '<length>', initialValue: '4px', inherits: false});
|
||||||
|
|
||||||
|
computedStyle = getComputedStyle(test1);
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-1-a'), '1px');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-1-b'), '2px');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-1-c'), '2px');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-1-d'), '2px');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--unregistered-1-a'), '1px');
|
||||||
|
assert_equals(computedStyle.left, '1px');
|
||||||
|
assert_equals(computedStyle.top, '2px');
|
||||||
|
}, "A var() cycle between two registered properties is handled correctly.");
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#test2 {
|
||||||
|
--registered-2-a: var(--unregistered-2-a, 10px);
|
||||||
|
--unregistered-2-a:var(--registered-2-a,20px);
|
||||||
|
|
||||||
|
--registered-2-b: var(--registered-2-a, 30px);
|
||||||
|
--registered-2-c: var(--registered-2-a);
|
||||||
|
--registered-2-d: var(--unregistered-2-a, 40px);
|
||||||
|
--registered-2-e: var(--unregistered-2-a);
|
||||||
|
--unregistered-2-b:var(--registered-2-a,50px);
|
||||||
|
--unregistered-2-c:var(--registered-2-a);
|
||||||
|
--unregistered-2-d:var(--unregistered-2-a,60px);
|
||||||
|
--unregistered-2-e:var(--unregistered-2-a);
|
||||||
|
left: var(--registered-2-a, 70px);
|
||||||
|
top: var(--unregistered-2-a, 80px);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div id=test2></div>
|
||||||
|
<script>
|
||||||
|
test(function() {
|
||||||
|
CSS.registerProperty({name: '--registered-2-a', syntax: '<length>', initialValue: '1px', inherits: false});
|
||||||
|
CSS.registerProperty({name: '--registered-2-b', syntax: '<length>', initialValue: '2px', inherits: false});
|
||||||
|
CSS.registerProperty({name: '--registered-2-c', syntax: '<length>', initialValue: '3px', inherits: false});
|
||||||
|
CSS.registerProperty({name: '--registered-2-d', syntax: '<length>', initialValue: '4px', inherits: false});
|
||||||
|
CSS.registerProperty({name: '--registered-2-e', syntax: '<length>', initialValue: '5px', inherits: false});
|
||||||
|
|
||||||
|
computedStyle = getComputedStyle(test2);
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-2-a'), '1px');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--unregistered-2-a'), '');
|
||||||
|
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-2-b'), '1px');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-2-c'), '1px');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-2-d'), '40px');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-2-e'), '5px');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--unregistered-2-b'), '1px');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--unregistered-2-c'), '1px');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--unregistered-2-d'), '60px');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--unregistered-2-e'), '');
|
||||||
|
assert_equals(computedStyle.left, '1px');
|
||||||
|
assert_equals(computedStyle.top, '80px');
|
||||||
|
}, "A var() cycle between a registered properties and an unregistered property is handled correctly.");
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#test3 {
|
||||||
|
--unregistered-3-a:var(--unregistered-3-b,10px);
|
||||||
|
--unregistered-3-b:var(--unregistered-3-a,20px);
|
||||||
|
|
||||||
|
--registered-3-a: var(--unregistered-3-a, 30px);
|
||||||
|
--registered-3-b: var(--unregistered-3-a);
|
||||||
|
--registered-3-c: var(--unregistered-3-b, 40px);
|
||||||
|
--registered-3-d: var(--registered-3-c, 50px);
|
||||||
|
left: var(--registered-3-d, 60px);
|
||||||
|
top: var(--registered-3-b, 70px);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div id=test3></div>
|
||||||
|
<script>
|
||||||
|
test(function() {
|
||||||
|
CSS.registerProperty({name: '--registered-3-a', syntax: '<length>', initialValue: '1px', inherits: false});
|
||||||
|
CSS.registerProperty({name: '--registered-3-b', syntax: '<length>', initialValue: '2px', inherits: false});
|
||||||
|
CSS.registerProperty({name: '--registered-3-c', syntax: '<length>', initialValue: '3px', inherits: false});
|
||||||
|
CSS.registerProperty({name: '--registered-3-d', syntax: '<length>', initialValue: '4px', inherits: false});
|
||||||
|
|
||||||
|
computedStyle = getComputedStyle(test3);
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--unregistered-3-a'), '');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--unregistered-3-b'), '');
|
||||||
|
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-3-a'), '30px');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-3-b'), '2px');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-3-c'), '40px');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-3-d'), '40px');
|
||||||
|
assert_equals(computedStyle.left, '40px');
|
||||||
|
assert_equals(computedStyle.top, '2px');
|
||||||
|
}, "A var() cycle between a two unregistered properties is handled correctly.");
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#test4 {
|
||||||
|
--registered-4-a:var(--unregistered-4-a,hello);
|
||||||
|
--unregistered-4-a:var(--registered-4-a,world);
|
||||||
|
|
||||||
|
--registered-4-b:var(--unregistered-4-a,meow);
|
||||||
|
--registered-4-c:var(--unregistered-4-a);
|
||||||
|
--unregistered-4-b:var(--unregistered-4-a,woof);
|
||||||
|
--unregistered-4-c:var(--unregistered-4-a);
|
||||||
|
transition-property: var(--registered-4-a, water);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div id=test4></div>
|
||||||
|
<script>
|
||||||
|
test(function() {
|
||||||
|
CSS.registerProperty({name: '--registered-4-a', syntax: '*', inherits: false});
|
||||||
|
CSS.registerProperty({name: '--registered-4-b', syntax: '*', initialValue: 'moo', inherits: false});
|
||||||
|
CSS.registerProperty({name: '--registered-4-c', syntax: '*', initialValue: 'circle', inherits: false});
|
||||||
|
|
||||||
|
computedStyle = getComputedStyle(test4);
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-4-a'), '');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--unregistered-4-a'), '');
|
||||||
|
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-4-b'), 'meow');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-4-c'), '');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--unregistered-4-b'), 'woof');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--unregistered-4-c'), '');
|
||||||
|
assert_equals(computedStyle.transitionProperty, 'water');
|
||||||
|
}, "A var() cycle between a syntax:'*' property and an unregistered property is handled correctly.");
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#test5_parent {
|
||||||
|
--registered-5-c:foo;
|
||||||
|
--registered-5-d:bar;
|
||||||
|
--registered-5-e:baz;
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
#test5 {
|
||||||
|
--registered-5-a:var(--registered-5-b,hello);
|
||||||
|
--registered-5-b:var(--registered-5-a,world);
|
||||||
|
|
||||||
|
--registered-5-c:var(--registered-5-a);
|
||||||
|
--registered-5-d:var(--registered-5-b);
|
||||||
|
--registered-5-e:var(--unknown);
|
||||||
|
color: var(--registered-5-e);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div id=test5_parent>
|
||||||
|
<div id=test5></div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
test(function() {
|
||||||
|
CSS.registerProperty({name: '--registered-5-a', syntax: '*', inherits: true});
|
||||||
|
CSS.registerProperty({name: '--registered-5-b', syntax: '*', inherits: true});
|
||||||
|
CSS.registerProperty({name: '--registered-5-c', syntax: '*', inherits: true});
|
||||||
|
CSS.registerProperty({name: '--registered-5-d', syntax: '*', inherits: true});
|
||||||
|
CSS.registerProperty({name: '--registered-5-e', syntax: '*', inherits: true});
|
||||||
|
|
||||||
|
let computedStyle = getComputedStyle(test5);
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-5-a'), '');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-5-b'), '');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-5-c'), '');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-5-d'), '');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-5-e'), '');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('color'), 'rgb(0, 128, 0)');
|
||||||
|
}, "Custom properties with universal syntax become guaranteed-invalid when " +
|
||||||
|
"invalid at computed-value time");
|
||||||
|
</script>
|
|
@ -0,0 +1,207 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api/#dom-css-registerproperty" />
|
||||||
|
<script src="../../resources/testharness.js"></script>
|
||||||
|
<script src="../../resources/testharnessreport.js"></script>
|
||||||
|
<script src="./resources/utils.js"></script>
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
--registered-length-1: 10px;
|
||||||
|
--registered-length-2: var(--registered-length-1);
|
||||||
|
--registered-length-3: var(--length-1);
|
||||||
|
--registered-length-4: calc(var(--length-1) + 40px);
|
||||||
|
--registered-length-5: var(--invalid, 70px);
|
||||||
|
--registered-length-6: calc(var(--registered-length-3)*4);
|
||||||
|
--registered-length-7: var(--123px, 6px);
|
||||||
|
|
||||||
|
--length-1: 20px;
|
||||||
|
--length-2: var(--registered-length-1);
|
||||||
|
--length-3: calc(var(--123px, 6px) + var(--123px));
|
||||||
|
|
||||||
|
--percentage: 10%;
|
||||||
|
--registered-length-invalid: var(--percentage);
|
||||||
|
|
||||||
|
--registered-token-stream-1:var(--invalid);
|
||||||
|
--registered-token-stream-2:var(--invalid,fallback);
|
||||||
|
--token-stream-1:var(--registered-token-stream-1,moo);
|
||||||
|
|
||||||
|
--registered-length-list-1: 1px, var(--registered-length-1), 2px;
|
||||||
|
--registered-length-list-2: 1px, var(--length-1), var(--registered-length-1), 2px;
|
||||||
|
--registered-length-list-3: var(--registered-length-list-1), var(--registered-length-list-2);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div id=element></div>
|
||||||
|
<script>
|
||||||
|
test(function() {
|
||||||
|
CSS.registerProperty({name: '--123px', syntax: '<length>', initialValue: '123px', inherits: false});
|
||||||
|
|
||||||
|
CSS.registerProperty({name: '--registered-length-1', syntax: '<length>', initialValue: '0px', inherits: false});
|
||||||
|
CSS.registerProperty({name: '--registered-length-2', syntax: '<length>', initialValue: '0px', inherits: false});
|
||||||
|
CSS.registerProperty({name: '--registered-length-3', syntax: '<length>', initialValue: '0px', inherits: false});
|
||||||
|
CSS.registerProperty({name: '--registered-length-4', syntax: '<length>', initialValue: '0px', inherits: false});
|
||||||
|
CSS.registerProperty({name: '--registered-length-5', syntax: '<length>', initialValue: '0px', inherits: false});
|
||||||
|
CSS.registerProperty({name: '--registered-length-6', syntax: '<length>', initialValue: '0px', inherits: false});
|
||||||
|
CSS.registerProperty({name: '--registered-length-7', syntax: '<length>', initialValue: '0px', inherits: false});
|
||||||
|
CSS.registerProperty({name: '--registered-length-invalid', syntax: '<length>', initialValue: '15px', inherits: false});
|
||||||
|
|
||||||
|
CSS.registerProperty({name: '--registered-token-stream-1', syntax: '*', inherits: false});
|
||||||
|
CSS.registerProperty({name: '--registered-token-stream-2', syntax: '*', inherits: false});
|
||||||
|
|
||||||
|
computedStyle = getComputedStyle(element);
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-length-1'), '10px');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-length-2'), '10px');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-length-3'), '20px');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-length-4'), '60px');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-length-5'), '70px');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-length-6'), '80px');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-length-7'), '123px');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--length-1'), '20px');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--length-2'), '10px');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--length-3'), 'calc(123px + 123px)');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-length-invalid'), '15px');
|
||||||
|
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-token-stream-1'), '');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-token-stream-2'), 'fallback');
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--token-stream-1'), 'moo');
|
||||||
|
}, "var() references work with registered properties");
|
||||||
|
|
||||||
|
test(function(){
|
||||||
|
CSS.registerProperty({
|
||||||
|
name: '--registered-length-list-1',
|
||||||
|
syntax: '<length>#',
|
||||||
|
initialValue: '0px',
|
||||||
|
inherits: false
|
||||||
|
});
|
||||||
|
let computedStyle = getComputedStyle(element);
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-length-list-1'), '1px, 10px, 2px');
|
||||||
|
}, 'References to registered var()-properties work in registered lists');
|
||||||
|
|
||||||
|
test(function(){
|
||||||
|
CSS.registerProperty({
|
||||||
|
name: '--registered-length-list-2',
|
||||||
|
syntax: '<length>#',
|
||||||
|
initialValue: '0px',
|
||||||
|
inherits: false
|
||||||
|
});
|
||||||
|
let computedStyle = getComputedStyle(element);
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-length-list-2'), '1px, 20px, 10px, 2px');
|
||||||
|
}, 'References to mixed registered and unregistered var()-properties work in registered lists');
|
||||||
|
|
||||||
|
test(function(){
|
||||||
|
CSS.registerProperty({
|
||||||
|
name: '--registered-length-list-3',
|
||||||
|
syntax: '<length>#',
|
||||||
|
initialValue: '0px',
|
||||||
|
inherits: false
|
||||||
|
});
|
||||||
|
let computedStyle = getComputedStyle(element);
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--registered-length-list-3'), '1px, 10px, 2px, 1px, 20px, 10px, 2px');
|
||||||
|
}, 'Registered lists may be concatenated');
|
||||||
|
|
||||||
|
test(function(){
|
||||||
|
CSS.registerProperty({
|
||||||
|
name: '--length-em',
|
||||||
|
syntax: '<length>',
|
||||||
|
initialValue: '0px',
|
||||||
|
inherits: false
|
||||||
|
});
|
||||||
|
element.style = 'font-size: 11px; --length-em: 10em; --unregistered:var(--length-em);';
|
||||||
|
let computedStyle = getComputedStyle(element);
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--unregistered'), '110px');
|
||||||
|
element.style = '';
|
||||||
|
}, 'Font-relative units are absolutized when substituting');
|
||||||
|
|
||||||
|
test(function(){
|
||||||
|
CSS.registerProperty({
|
||||||
|
name: '--length-calc',
|
||||||
|
syntax: '<length>',
|
||||||
|
initialValue: '0px',
|
||||||
|
inherits: false
|
||||||
|
});
|
||||||
|
element.style = 'font-size: 11px; --length-calc: calc(10em + 10px); --unregistered:var(--length-calc);';
|
||||||
|
let computedStyle = getComputedStyle(element);
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--unregistered'), '120px');
|
||||||
|
element.style = '';
|
||||||
|
}, 'Calc expressions are resolved when substituting');
|
||||||
|
|
||||||
|
test(function(){
|
||||||
|
CSS.registerProperty({
|
||||||
|
name: '--length-calc-list',
|
||||||
|
syntax: '<length>#',
|
||||||
|
initialValue: '0px',
|
||||||
|
inherits: false
|
||||||
|
});
|
||||||
|
element.style = 'font-size: 11px; --length-calc-list: 10em, calc(10em + 10px); --unregistered:var(--length-calc-list);';
|
||||||
|
let computedStyle = getComputedStyle(element);
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--unregistered'), '110px, 120px');
|
||||||
|
element.style = '';
|
||||||
|
}, 'Lists with relative units are absolutized when substituting');
|
||||||
|
|
||||||
|
test(function(){
|
||||||
|
let length = generate_property('none | <length>');
|
||||||
|
let universal = generate_property('*');
|
||||||
|
element.style = `font-size: 10px; ${length}: 10em; ${universal}: var(${length})`;
|
||||||
|
let computedStyle = getComputedStyle(element);
|
||||||
|
assert_equals(computedStyle.getPropertyValue(universal), '100px');
|
||||||
|
element.style = '';
|
||||||
|
}, 'Values are absolutized when substituting into properties with universal syntax');
|
||||||
|
|
||||||
|
test(function(){
|
||||||
|
let name = generate_property('<length>');
|
||||||
|
let unregistered = '--unregistered'
|
||||||
|
element.style = `${name}: red; ${unregistered}: var(${name})`
|
||||||
|
let computedStyle = getComputedStyle(element);
|
||||||
|
assert_equals(computedStyle.getPropertyValue(unregistered), '');
|
||||||
|
}, 'Invalid values for registered properties are serialized as the empty string')
|
||||||
|
|
||||||
|
function test_valid_fallback(syntax, value, fallback) {
|
||||||
|
test(function(){
|
||||||
|
let name = generate_property(syntax);
|
||||||
|
try {
|
||||||
|
element.style = `${name}: ${value}; --x:var(${name},${fallback})`;
|
||||||
|
let computedStyle = getComputedStyle(element);
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--x'), value);
|
||||||
|
} finally {
|
||||||
|
element.style = '';
|
||||||
|
}
|
||||||
|
}, `Valid fallback does not invalidate var()-reference [${syntax}, ${fallback}]`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_invalid_fallback(syntax, value, fallback) {
|
||||||
|
test(function(){
|
||||||
|
let name = generate_property(syntax);
|
||||||
|
try {
|
||||||
|
element.style = `${name}: ${value}; --x:var(${name},${fallback})`;
|
||||||
|
let computedStyle = getComputedStyle(element);
|
||||||
|
assert_equals(computedStyle.getPropertyValue('--x'), value);
|
||||||
|
} finally {
|
||||||
|
element.style = '';
|
||||||
|
}
|
||||||
|
}, `Invalid fallback doesn't invalidate var()-reference [${syntax}, ${fallback}]`);
|
||||||
|
}
|
||||||
|
|
||||||
|
test_valid_fallback('<length>', '40px', '10px');
|
||||||
|
test_valid_fallback('<length> | <color>', '40px', 'red');
|
||||||
|
test_valid_fallback('<length> | none', '40px', 'none');
|
||||||
|
|
||||||
|
test_invalid_fallback('<length>', '40px', 'red');
|
||||||
|
test_invalid_fallback('<length> | none', '40px', 'nolength');
|
||||||
|
test_invalid_fallback('<length>', '40px', 'var(--novar)');
|
||||||
|
|
||||||
|
test(function(t){
|
||||||
|
CSS.registerProperty({
|
||||||
|
name: '--registered-universal-no-initial',
|
||||||
|
syntax: '*',
|
||||||
|
inherits: false
|
||||||
|
});
|
||||||
|
t.add_cleanup(() => {
|
||||||
|
element.style = '';
|
||||||
|
});
|
||||||
|
element.style = [
|
||||||
|
'--registered-universal-no-initial:;',
|
||||||
|
'background-color: var(--registered-universal-no-initial) green',
|
||||||
|
].join(';');
|
||||||
|
let computedStyle = getComputedStyle(element);
|
||||||
|
assert_equals(computedStyle.getPropertyValue('background-color'), 'rgb(0, 128, 0)');
|
||||||
|
}, 'Empty universal custom property can be substituted with var()');
|
||||||
|
|
||||||
|
</script>
|
Loading…
Add table
Add a link
Reference in a new issue