summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/css/cssom/css-style-attr-decl-block.html
blob: 744b3a744cb2fda98c2ceea251a8c02c6e4bae3b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
<!DOCTYPE html>
<meta charset="UTF-8">
<link rel="author" title="Xidorn Quan" href="mailto:me@upsuper.org">
<link rel="help" href="https://drafts.csswg.org/cssom-1/#css-declaration-blocks">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
<script>
function createTestElement(style) {
  let wrapper = document.createElement("div");
  wrapper.innerHTML = `<div id="test" style="${style}"></div>`;
  return wrapper.querySelector("#test");
}

test(function() {
  let elem = createTestElement("z-index: 10;");
  assert_equals(elem.style.cssText, "z-index: 10;");
}, "Style attribute should create CSS declaration block based on its content");

test(function() {
  let elem = createTestElement("z-index: 20;");
  let style = elem.style;
  assert_equals(style.cssText, "z-index: 20;");
  function assert_css_text(value, action) {
    assert_equals(style.cssText, value, "CSS declaration block after " + action);
  }
  elem.setAttribute("style", "z-index: 21;");
  assert_css_text("z-index: 21;", "changing the style attribute");
  elem.removeAttribute("style");
  assert_css_text("", "removing the style attribute");
  elem.setAttribute("style", "position: absolute;");
  assert_css_text("position: absolute;", "adding style attribute again");
}, "Changes to style attribute should reflect on CSS declaration block");

test(function() {
  let elem = createTestElement("z-index: 30;");
  let style = elem.style;
  assert_equals(style.cssText, "z-index: 30;");
  function assert_attr(value, action) {
    assert_equals(elem.getAttribute("style"), value, "style attribute after " + action);
  }
  style.setProperty("z-index", "31");
  assert_attr("z-index: 31;", "changing property in CSS declaration block");
  style.removeProperty("z-index");
  assert_attr("", "removing property from CSS declaration block");
  style.setProperty("position", "absolute");
  assert_attr("position: absolute;", "adding property to CSS declaration block");
  style.cssText = "z-index: 32;";
  assert_attr("z-index: 32;", "changing cssText");
  style.cssText = "z-index: 33; invalid";
  assert_attr("z-index: 33;", "changing cssText to a partial invalid value");
}, "Changes to CSS declaration block should reflect on style attribute");

test(function() {
  let elem = createTestElement("z-index: 40;");
  let style = elem.style;
  assert_equals(style.cssText, "z-index: 40;");
  // Create an observer for the element.
  let observer = new MutationObserver(function() {});
  observer.observe(elem, {attributes: true, attributeOldValue: true});
  function assert_record_with_old_value(oldValue, action) {
    let records = observer.takeRecords();
    assert_equals(records.length, 1, "number of mutation records after " + action);
    let record = records[0];
    assert_equals(record.type, "attributes", "mutation type after " + action);
    assert_equals(record.attributeName, "style", "mutated attribute after " + action);
    assert_equals(record.oldValue, oldValue, "old value after " + action);
  }
  style.setProperty("z-index", "41");
  assert_record_with_old_value("z-index: 40;", "changing property in CSS declaration block");
  style.cssText = "z-index: 42;";
  assert_record_with_old_value("z-index: 41;", "changing cssText");
  style.cssText = "z-index: 42;";
  assert_record_with_old_value("z-index: 42;", "changing cssText with the same content");
  style.removeProperty("z-index");
  assert_record_with_old_value("z-index: 42;", "removing property from CSS declaration block");
  // Mutation to shorthand properties should also trigger only one mutation record.
  style.setProperty("margin", "1px");
  assert_record_with_old_value("", "adding shorthand property to CSS declaration block");
  style.removeProperty("margin");
  assert_record_with_old_value("margin: 1px;", "removing shorthand property from CSS declaration block");
  // Final sanity check.
  assert_equals(elem.getAttribute("style"), "");
}, "Changes to CSS declaration block should queue mutation record for style attribute");

test(function() {
  let elem = createTestElement("z-index: 50; invalid");
  let style = elem.style;
  assert_equals(style.cssText, "z-index: 50;");
  // Create an observer for the element.
  let observer = new MutationObserver(function() {});
  observer.observe(elem, {attributes: true});
  function assert_no_record(action) {
    let records = observer.takeRecords();
    assert_equals(records.length, 0, "expect no record after " + action);
  }
  style.setProperty("z-index", "invalid");
  assert_no_record("setting invalid value to property");
  // Longhand property.
  style.removeProperty("position");
  assert_no_record("removing non-existing longhand property");
  style.setProperty("position", "");
  assert_no_record("setting empty string to non-existing longhand property");
  // Shorthand property.
  style.removeProperty("margin");
  assert_no_record("removing non-existing shorthand property");
  style.setProperty("margin", "");
  assert_no_record("setting empty string to non-existing shorthand property");
  // Check that the value really isn't changed.
  assert_equals(elem.getAttribute("style"), "z-index: 50; invalid",
                "style attribute after removing non-existing properties");
}, "Removing non-existing property or setting invalid value on CSS declaration block shouldn't queue mutation record");

test(function() {
  let elem = createTestElement("background-image: url(./);");
  let style = elem.style;
  let base = document.createElement("base");
  base.href = "/";
  document.body.appendChild(elem);
  let originalComputedValue = getComputedStyle(elem).backgroundImage;
  document.head.appendChild(base);
  this.add_cleanup(() => {
    document.head.removeChild(base);
    document.body.removeChild(elem);
  });
  style.setProperty("background-color", "green");
  assert_equals(getComputedStyle(elem).backgroundImage, originalComputedValue,
                "getComputedStyle(elem).backgroundImage after setting background-color");
  style.setProperty("background-image", "url(./)");
  assert_not_equals(getComputedStyle(elem).backgroundImage, originalComputedValue,
                    "getComputedStyle(elem).backgroundImage after setting background-image");
}, "Changes to CSS declaration block after a base URL change");

test(function() {
  let e1 = document.createElement('div');
  let e2 = document.createElement('div');
  document.body.append(e1, e2);
  this.add_cleanup(() => {
    e1.remove();
    e2.remove();
  });
  e1.style.cssText = "all:revert;border-bottom-left-radius:1px;";
  e2.style.cssText = "all:unset;border-bottom-left-radius:1px;";
  let processed = e1.style.cssText.split(';')
    .map(x => x.replace(/revert$/, 'unset')).join(';');
  assert_equals(processed, e2.style.cssText);
}, "Expansion of all:unset and all:revert treated identically");
</script>