author | Anders Hartvoll Ruud <andruud@chromium.org> |
Tue, 28 Apr 2020 11:35:45 +0000 | |
changeset 527552 | 1fb5e8dca04615104c2c4084d4522b9542b71b28 |
parent 527551 | 85717ca941fff6abca6893202f0fd26bc0aad518 |
child 527553 | 880e5158d0f65527e1b61be6e5850316128ba906 |
push id | 37368 |
push user | btara@mozilla.com |
push date | Fri, 01 May 2020 21:45:51 +0000 |
treeherder | mozilla-central@0f9c5a59e45d [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | testonly |
bugs | 1631731, 23134, 973830, 2157528, 761157 |
milestone | 77.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
new file mode 100644 --- /dev/null +++ b/testing/web-platform/tests/css/css-properties-values-api/at-property-cssom.html @@ -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>
new file mode 100644 --- /dev/null +++ b/testing/web-platform/tests/css/css-properties-values-api/at-property.html @@ -0,0 +1,232 @@ +<!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> +<div id="outer"> + <div id="target"></div> +</div> +<script> + +let g_id = 0; + +function generate_name() { + g_id++; + return `--property-${g_id}`; +} + +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_rule(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_rule(desc, fn, description) { + test(() => with_at_rule(desc, fn), description); +} + +function test_with_style_node(text, fn, description) { + test(() => with_style_node(text, fn), description); +} + +// 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_rule({ [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_rule({ + 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_rule({ + 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_rule({ 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_rule({ + 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_rule({ + 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'); + +test_with_at_rule({ + 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'); + +</script>