summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/css/support/parsing-testcommon.js
blob: 93fd0090770b548c5116b59b037114616f541b14 (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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
'use strict';

/**
 * Create test that a CSS property computes to the expected value.
 * The document element #target is used to perform the test.
 *
 * @param {string} property  The name of the CSS property being tested.
 * @param {string} value     A specified value for the property.
 * @param {string|array} serializedValue  The expected serialized value,
 *                                 or an array of permitted serializations.
 *                                 If omitted, defaults to the specified value.
 * @param {object} options  Additional test information, such as a custom
 *                          comparison function required for color tests.
 *                          comparisonFunction is a function that takes two
 *                          arguments, actual and expected and contains asserts.
 */
function test_valid_value(property, value, serializedValue, options = {}) {
    if (arguments.length < 3)
        serializedValue = value;

    var stringifiedValue = JSON.stringify(value);

    test(function(){
        var div = document.getElementById('target') || document.createElement('div');
        div.style[property] = "";
        div.style[property] = value;
        var readValue = div.style.getPropertyValue(property);
        assert_not_equals(readValue, "", "property should be set");
        if (options.comparisonFunction)
            options.comparisonFunction(readValue, serializedValue);
        else if (Array.isArray(serializedValue))
            assert_in_array(readValue, serializedValue, "serialization should be sound");
        else
            assert_equals(readValue, serializedValue, "serialization should be canonical");

        div.style[property] = readValue;
        assert_equals(div.style.getPropertyValue(property), readValue, "serialization should round-trip");

    }, "e.style['" + property + "'] = " + stringifiedValue + " should set the property value");
}

function test_invalid_value(property, value) {
    var stringifiedValue = JSON.stringify(value);

    test(function(){
        var div = document.getElementById('target') || document.createElement('div');
        div.style[property] = "";
        div.style[property] = value;
        assert_equals(div.style.getPropertyValue(property), "");
    }, "e.style['" + property + "'] = " + stringifiedValue + " should not set the property value");
}

function test_valid_forgiving_selector(selector) {
  test_valid_selector(selector, selector, { onlyWhenForgiving: true });
}

// serializedSelector can be the expected serialization of selector,
// or an array of permitted serializations,
// or omitted if value should serialize as selector.
function test_valid_selector(selector, serializedSelector, options) {
    if (arguments.length < 2)
        serializedSelector = selector;

    const stringifiedSelector = JSON.stringify(selector);

    test(function(){
        document.querySelector(selector);
        assert_true(true, stringifiedSelector + " should not throw in querySelector");

        const style = document.createElement("style");
        document.head.append(style);
        const {sheet} = style;
        document.head.removeChild(style);
        const {cssRules} = sheet;

        assert_equals(cssRules.length, 0, "Sheet should have no rule");
        sheet.insertRule(selector + "{}");
        assert_equals(cssRules.length, 1, "Sheet should have 1 rule");

        const readSelector = cssRules[0].selectorText;
        if (Array.isArray(serializedSelector))
            assert_in_array(readSelector, serializedSelector, "serialization should be sound");
        else
            assert_equals(readSelector, serializedSelector, "serialization should be canonical");

        sheet.deleteRule(0);
        assert_equals(cssRules.length, 0, "Sheet should have no rule");
        sheet.insertRule(readSelector + "{}");
        assert_equals(cssRules.length, 1, "Sheet should have 1 rule");

        assert_equals(cssRules[0].selectorText, readSelector, "serialization should round-trip");

        let supports = !options?.onlyWhenForgiving;
        assert_equals(CSS.supports(`selector(${selector})`), supports, "CSS.supports() reports the expected value");
    }, stringifiedSelector + " should be a valid selector");
}

function test_invalid_selector(selector) {
    const stringifiedSelector = JSON.stringify(selector);

    test(function(){
        assert_throws_dom(
          DOMException.SYNTAX_ERR,
          () => document.querySelector(selector),
          stringifiedSelector + " should throw in querySelector");

        const style = document.createElement("style");
        document.head.append(style);
        const {sheet} = style;
        document.head.removeChild(style);

        assert_throws_dom(
          DOMException.SYNTAX_ERR,
          () => sheet.insertRule(selector + "{}"),
          stringifiedSelector + " should throw in insertRule");
    }, stringifiedSelector + " should be an invalid selector");
}

// serialized can be the expected serialization of rule, or an array of
// permitted serializations, or omitted if value should serialize as rule.
function test_valid_rule(rule, serialized) {
    if (serialized === undefined)
        serialized = rule;

    test(function(){
        const style = document.createElement("style");
        document.head.append(style);
        const {sheet} = style;
        document.head.removeChild(style);
        const {cssRules} = sheet;

        assert_equals(cssRules.length, 0, "Sheet should have no rules");
        sheet.insertRule(rule);
        assert_equals(cssRules.length, 1, "Sheet should have 1 rule");

        const serialization = cssRules[0].cssText;
        if (Array.isArray(serialized))
            assert_in_array(serialization, serialized, "serialization should be sound");
        else
            assert_equals(serialization, serialized, "serialization should be canonical");

        sheet.deleteRule(0);
        assert_equals(cssRules.length, 0, "Sheet should have no rule");
        sheet.insertRule(serialization);
        assert_equals(cssRules.length, 1, "Sheet should have 1 rule");

        assert_equals(cssRules[0].cssText, serialization, "serialization should round-trip");
    }, rule + " should be a valid rule");
}

function test_invalid_rule(rule) {
    test(function(){
        const style = document.createElement("style");
        document.head.append(style);
        const {sheet} = style;
        document.head.removeChild(style);

        assert_throws_dom(
          DOMException.SYNTAX_ERR,
          () => sheet.insertRule(rule),
          rule + " should throw in insertRule");
    }, rule + " should be an invalid rule");
}

function _set_style(rule) {
    const style = document.createElement('style');
    style.innerText = rule;
    document.head.append(style);
    const { sheet } = style;
    document.head.removeChild(style);
    return sheet;
}

function test_keyframes_name_valid(keyframes_name) {
    test(t => {
        const sheet = _set_style(`@keyframes ${keyframes_name} {}`);
        assert_equals(sheet.cssRules.length, 1);
    }, `valid: @keyframes ${keyframes_name} { }`);
}

function test_keyframes_name_invalid(keyframes_name) {
    test(t => {
        const sheet = _set_style(`@keyframes ${keyframes_name} {}`);
        assert_equals(sheet.cssRules.length, 0);
    }, `invalid: @keyframes ${keyframes_name} { }`);
}