summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/css/css-properties-values-api/at-property.html
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/css/css-properties-values-api/at-property.html')
-rw-r--r--testing/web-platform/tests/css/css-properties-values-api/at-property.html243
1 files changed, 243 insertions, 0 deletions
diff --git a/testing/web-platform/tests/css/css-properties-values-api/at-property.html b/testing/web-platform/tests/css/css-properties-values-api/at-property.html
new file mode 100644
index 0000000000..95d30af15a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-properties-values-api/at-property.html
@@ -0,0 +1,243 @@
+<!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 | <length>#"', 'foo | <length>#');
+test_descriptor('syntax', '"foo | bar | baz"', 'foo | bar | baz');
+test_descriptor('syntax', '"notasyntax"', 'notasyntax');
+
+// syntax: universal
+for (const syntax of ["*", " * ", "* ", "\t*\t"]) {
+ test_descriptor('syntax', `"${syntax}"`, syntax);
+}
+
+test_descriptor('syntax', 'red', '');
+test_descriptor('syntax', 'rgb(255, 0, 0)', '');
+test_descriptor('syntax', '<color>', '');
+test_descriptor('syntax', 'foo | bar', '');
+
+// syntax: pipe between components
+test_descriptor('syntax', 'foo bar', '');
+test_descriptor('syntax', 'Foo <length>', '');
+test_descriptor('syntax', 'foo, bar', '');
+test_descriptor('syntax', '<length> <percentage>', '');
+
+// syntax: leaading bar
+test_descriptor('syntax', '|<length>', '');
+
+// 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);
+
+test_not_applied('<transform-function>', 'translateX(1em)', false);
+test_not_applied('<transform-function>', 'translateY(1lh)', false);
+test_not_applied('<transform-list>', 'rotate(10deg) translateX(1em)', false);
+test_not_applied('<transform-list>', 'rotate(10deg) translateY(1lh)', false);
+
+// Inheritance
+
+test_with_at_property({
+ syntax: '"<length>"',
+ inherits: false,
+ initialValue: '0px'
+}, (name, rule) => {
+ try {
+ outer.style = `${name}: 40px`;
+ assert_equals(getComputedStyle(outer).getPropertyValue(name), '40px');
+ assert_equals(getComputedStyle(target).getPropertyValue(name), '0px');
+ } finally {
+ outer.style = '';
+ }
+}, 'Non-inherited properties do not inherit');
+
+test_with_at_property({
+ syntax: '"<length>"',
+ inherits: true,
+ initialValue: '0px'
+}, (name, rule) => {
+ try {
+ outer.style = `${name}: 40px`;
+ assert_equals(getComputedStyle(outer).getPropertyValue(name), '40px');
+ assert_equals(getComputedStyle(target).getPropertyValue(name), '40px');
+ } finally {
+ outer.style = '';
+ }
+}, 'Inherited properties inherit');
+
+// Initial values
+
+test_with_at_property({
+ syntax: '"<color>"',
+ inherits: true,
+ initialValue: 'green'
+}, (name, rule) => {
+ try {
+ target.style = `--x:var(${name})`;
+ assert_equals(getComputedStyle(target).getPropertyValue(name), 'rgb(0, 128, 0)');
+ } finally {
+ target.style = '';
+ }
+}, 'Initial values substituted as computed value');
+
+test_with_at_property({
+ syntax: '"<length>"',
+ inherits: false,
+ initialValue: undefined
+}, (name, rule) => {
+ try {
+ target.style = `${name}: calc(1px + 1px);`;
+ assert_equals(getComputedStyle(target).getPropertyValue(name), 'calc(1px + 1px)');
+ } finally {
+ target.style = '';
+ }
+}, 'Non-universal registration are invalid without an initial value');
+
+test_with_at_property({
+ syntax: '"*"',
+ inherits: false,
+ initialValue: undefined
+}, (name, rule) => {
+ try {
+ // If the registration suceeded, ${name} does *not* inherit, and hence
+ // the computed value on 'target' should be empty.
+ outer.style = `${name}: calc(1px + 1px);`;
+ assert_equals(getComputedStyle(target).getPropertyValue(name), '');
+ } finally {
+ outer.style = '';
+ }
+}, 'Initial value may be omitted for universal registration');
+
+</script>