Bug 1631731 [wpt PR 23134] - [@property] Set status to 'test' and move tests to WPT, a=testonly
authorAnders Hartvoll Ruud <andruud@chromium.org>
Tue, 28 Apr 2020 11:35:45 +0000
changeset 527552 1fb5e8dca04615104c2c4084d4522b9542b71b28
parent 527551 85717ca941fff6abca6893202f0fd26bc0aad518
child 527553 880e5158d0f65527e1b61be6e5850316128ba906
push id37368
push userbtara@mozilla.com
push dateFri, 01 May 2020 21:45:51 +0000
treeherdermozilla-central@0f9c5a59e45d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstestonly
bugs1631731, 23134, 973830, 2157528, 761157
milestone77.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
Bug 1631731 [wpt PR 23134] - [@property] Set status to 'test' and move tests to WPT, a=testonly Automatic update from web-platform-tests [@property] Set status to 'test' and move tests to WPT Bug: 973830 Change-Id: I5d950496834ab17dc8615335c9c4ae25f2a4179b Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2157528 Commit-Queue: Anders Hartvoll Ruud <andruud@chromium.org> Reviewed-by: Ian Kilpatrick <ikilpatrick@chromium.org> Cr-Commit-Position: refs/heads/master@{#761157} -- wpt-commits: 8ab9b393636f35a1ddeb0526483b9c03013a4f98 wpt-pr: 23134
testing/web-platform/tests/css/css-properties-values-api/at-property-cssom.html
testing/web-platform/tests/css/css-properties-values-api/at-property.html
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>