test_parsePseudoClassesAndAttributes.js (5013B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 const { 7 parsePseudoClassesAndAttributes, 8 SELECTOR_ATTRIBUTE, 9 SELECTOR_ELEMENT, 10 SELECTOR_PSEUDO_CLASS, 11 } = require("resource://devtools/shared/css/parsing-utils.js"); 12 13 const TEST_DATA = [ 14 // Test that a null input throws an exception 15 { 16 input: null, 17 throws: true, 18 }, 19 // Test that a undefined input throws an exception 20 { 21 input: undefined, 22 throws: true, 23 }, 24 { 25 input: ":root", 26 expected: [{ value: ":root", type: SELECTOR_PSEUDO_CLASS }], 27 }, 28 { 29 input: ".testclass", 30 expected: [{ value: ".testclass", type: SELECTOR_ELEMENT }], 31 }, 32 { 33 input: "div p", 34 expected: [{ value: "div p", type: SELECTOR_ELEMENT }], 35 }, 36 { 37 input: "div > p", 38 expected: [{ value: "div > p", type: SELECTOR_ELEMENT }], 39 }, 40 { 41 input: "a[hidden]", 42 expected: [ 43 { value: "a", type: SELECTOR_ELEMENT }, 44 { value: "[hidden]", type: SELECTOR_ATTRIBUTE }, 45 ], 46 }, 47 { 48 input: "a[hidden=true]", 49 expected: [ 50 { value: "a", type: SELECTOR_ELEMENT }, 51 { value: "[hidden=true]", type: SELECTOR_ATTRIBUTE }, 52 ], 53 }, 54 { 55 input: "a[hidden=true] p:hover", 56 expected: [ 57 { value: "a", type: SELECTOR_ELEMENT }, 58 { value: "[hidden=true]", type: SELECTOR_ATTRIBUTE }, 59 { value: " p", type: SELECTOR_ELEMENT }, 60 { value: ":hover", type: SELECTOR_PSEUDO_CLASS }, 61 ], 62 }, 63 { 64 input: 'a[checked="true"]', 65 expected: [ 66 { value: "a", type: SELECTOR_ELEMENT }, 67 { value: '[checked="true"]', type: SELECTOR_ATTRIBUTE }, 68 ], 69 }, 70 { 71 input: "a[title~=test]", 72 expected: [ 73 { value: "a", type: SELECTOR_ELEMENT }, 74 { value: "[title~=test]", type: SELECTOR_ATTRIBUTE }, 75 ], 76 }, 77 { 78 input: 'h1[hidden="true"][title^="Important"]', 79 expected: [ 80 { value: "h1", type: SELECTOR_ELEMENT }, 81 { value: '[hidden="true"]', type: SELECTOR_ATTRIBUTE }, 82 { value: '[title^="Important"]', type: SELECTOR_ATTRIBUTE }, 83 ], 84 }, 85 { 86 input: "p:hover", 87 expected: [ 88 { value: "p", type: SELECTOR_ELEMENT }, 89 { value: ":hover", type: SELECTOR_PSEUDO_CLASS }, 90 ], 91 }, 92 { 93 input: "p + .testclass:hover", 94 expected: [ 95 { value: "p + .testclass", type: SELECTOR_ELEMENT }, 96 { value: ":hover", type: SELECTOR_PSEUDO_CLASS }, 97 ], 98 }, 99 { 100 input: "p::before", 101 expected: [ 102 { value: "p", type: SELECTOR_ELEMENT }, 103 { value: "::before", type: SELECTOR_PSEUDO_CLASS }, 104 ], 105 }, 106 { 107 input: "p:nth-child(2)", 108 expected: [ 109 { value: "p", type: SELECTOR_ELEMENT }, 110 { value: ":nth-child(2)", type: SELECTOR_PSEUDO_CLASS }, 111 ], 112 }, 113 { 114 input: 'p:not([title="test"]) .testclass', 115 expected: [ 116 { value: "p", type: SELECTOR_ELEMENT }, 117 { value: ':not([title="test"])', type: SELECTOR_PSEUDO_CLASS }, 118 { value: " .testclass", type: SELECTOR_ELEMENT }, 119 ], 120 }, 121 { 122 input: "a\\:hover", 123 expected: [{ value: "a\\:hover", type: SELECTOR_ELEMENT }], 124 }, 125 { 126 input: ":not(:lang(it))", 127 expected: [{ value: ":not(:lang(it))", type: SELECTOR_PSEUDO_CLASS }], 128 }, 129 { 130 input: "p:not(:lang(it))", 131 expected: [ 132 { value: "p", type: SELECTOR_ELEMENT }, 133 { value: ":not(:lang(it))", type: SELECTOR_PSEUDO_CLASS }, 134 ], 135 }, 136 { 137 input: "p:not(p:lang(it))", 138 expected: [ 139 { value: "p", type: SELECTOR_ELEMENT }, 140 { value: ":not(p:lang(it))", type: SELECTOR_PSEUDO_CLASS }, 141 ], 142 }, 143 { 144 input: ":not(:lang(it)", 145 expected: [{ value: ":not(:lang(it)", type: SELECTOR_ELEMENT }], 146 }, 147 { 148 input: ":not(:lang(it)))", 149 expected: [ 150 { value: ":not(:lang(it))", type: SELECTOR_PSEUDO_CLASS }, 151 { value: ")", type: SELECTOR_ELEMENT }, 152 ], 153 }, 154 ]; 155 156 function run_test() { 157 for (const test of TEST_DATA) { 158 dump("Test input string " + test.input + "\n"); 159 let output; 160 161 try { 162 output = parsePseudoClassesAndAttributes(test.input); 163 } catch (e) { 164 dump( 165 "parsePseudoClassesAndAttributes threw an exception with the " + 166 "given input string\n" 167 ); 168 if (test.throws) { 169 ok(true, "Exception expected"); 170 } else { 171 dump(); 172 ok(false, "Exception unexpected\n" + e); 173 } 174 } 175 176 if (output) { 177 assertOutput(output, test.expected); 178 } 179 } 180 } 181 182 function assertOutput(actual, expected) { 183 if (actual.length === expected.length) { 184 for (let i = 0; i < expected.length; i++) { 185 dump("Check that the output item has the expected value and type\n"); 186 ok(!!actual[i]); 187 equal(expected[i].value, actual[i].value); 188 equal(expected[i].type, actual[i].type); 189 } 190 } else { 191 for (const prop of actual) { 192 dump( 193 "Actual output contained: {value: " + 194 prop.value + 195 ", type: " + 196 prop.type + 197 "}\n" 198 ); 199 } 200 equal(actual.length, expected.length); 201 } 202 }