OLD | NEW |
1 /* | 1 /* |
2 * This file is part of Adblock Plus <https://adblockplus.org/>, | 2 * This file is part of Adblock Plus <https://adblockplus.org/>, |
3 * Copyright (C) 2006-present eyeo GmbH | 3 * Copyright (C) 2006-present eyeo GmbH |
4 * | 4 * |
5 * Adblock Plus is free software: you can redistribute it and/or modify | 5 * Adblock Plus is free software: you can redistribute it and/or modify |
6 * it under the terms of the GNU General Public License version 3 as | 6 * it under the terms of the GNU General Public License version 3 as |
7 * published by the Free Software Foundation. | 7 * published by the Free Software Foundation. |
8 * | 8 * |
9 * Adblock Plus is distributed in the hope that it will be useful, | 9 * Adblock Plus is distributed in the hope that it will be useful, |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 * GNU General Public License for more details. | 12 * GNU General Public License for more details. |
13 * | 13 * |
14 * You should have received a copy of the GNU General Public License | 14 * You should have received a copy of the GNU General Public License |
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. | 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
16 */ | 16 */ |
17 | 17 |
| 18 /* global assert */ |
| 19 |
18 "use strict"; | 20 "use strict"; |
19 | 21 |
20 const {ElemHideEmulation, setTestMode, | 22 const {ElemHideEmulation, setTestMode, |
21 getTestInfo} = require("../../lib/content/elemHideEmulation"); | 23 getTestInfo} = require("../../lib/content/elemHideEmulation"); |
22 const {timeout} = require("./_utils"); | 24 const {timeout} = require("./_utils"); |
23 | 25 |
24 const REFRESH_INTERVAL = 200; | 26 describe("Element Hiding Emulation", () => |
25 | |
26 let testDocument = null; | |
27 | |
28 exports.setUp = function(callback) | |
29 { | 27 { |
30 setTestMode(); | 28 const REFRESH_INTERVAL = 200; |
31 | 29 |
32 let iframe = document.createElement("iframe"); | 30 let testDocument = null; |
33 document.body.appendChild(iframe); | 31 |
34 testDocument = iframe.contentDocument; | 32 beforeEach(() => |
35 | 33 { |
36 callback(); | 34 setTestMode(); |
37 }; | 35 |
38 | 36 let iframe = document.createElement("iframe"); |
39 exports.tearDown = function(callback) | 37 document.body.appendChild(iframe); |
40 { | 38 testDocument = iframe.contentDocument; |
41 let iframe = testDocument.defaultView.frameElement; | 39 }); |
42 iframe.parentNode.removeChild(iframe); | 40 |
43 testDocument = null; | 41 afterEach(() => |
44 | 42 { |
45 callback(); | 43 let iframe = testDocument.defaultView.frameElement; |
46 }; | 44 iframe.parentNode.removeChild(iframe); |
47 | 45 testDocument = null; |
48 function unexpectedError(test, error) | 46 }); |
49 { | 47 |
50 console.error(error); | 48 function unexpectedError(error) |
51 test.ok(false, "Unexpected error: " + error); | 49 { |
52 } | 50 console.error(error); |
53 | 51 assert.ok(false, "Unexpected error: " + error); |
54 function expectHidden(test, element, id) | |
55 { | |
56 let withId = ""; | |
57 if (typeof id != "undefined") | |
58 withId = ` with ID '${id}'`; | |
59 | |
60 test.equal( | |
61 window.getComputedStyle(element).display, "none", | |
62 `The element${withId}'s display property should be set to 'none'`); | |
63 } | |
64 | |
65 function expectVisible(test, element, id) | |
66 { | |
67 let withId = ""; | |
68 if (typeof id != "undefined") | |
69 withId = ` with ID '${id}'`; | |
70 | |
71 test.notEqual( | |
72 window.getComputedStyle(element).display, "none", | |
73 `The element${withId}'s display property should not be set to 'none'`); | |
74 } | |
75 | |
76 function expectProcessed(test, element, id = null) | |
77 { | |
78 let withId = ""; | |
79 if (id) | |
80 withId = ` with ID '${id}'`; | |
81 | |
82 test.ok( | |
83 getTestInfo().lastProcessedElements.has(element), | |
84 `The element${withId} should have been processed`); | |
85 } | |
86 | |
87 function expectNotProcessed(test, element, id = null) | |
88 { | |
89 let withId = ""; | |
90 if (id) | |
91 withId = ` with ID '${id}'`; | |
92 | |
93 test.ok( | |
94 !getTestInfo().lastProcessedElements.has(element), | |
95 `The element${withId} should not have been processed`); | |
96 } | |
97 | |
98 function findUniqueId() | |
99 { | |
100 let id = "elemHideEmulationTest-" + Math.floor(Math.random() * 10000); | |
101 if (!testDocument.getElementById(id)) | |
102 return id; | |
103 return findUniqueId(); | |
104 } | |
105 | |
106 function insertStyleRule(rule) | |
107 { | |
108 let styleElement; | |
109 let styleElements = testDocument.head.getElementsByTagName("style"); | |
110 if (styleElements.length) | |
111 styleElement = styleElements[0]; | |
112 else | |
113 { | |
114 styleElement = testDocument.createElement("style"); | |
115 testDocument.head.appendChild(styleElement); | |
116 } | 52 } |
117 styleElement.sheet.insertRule(rule, styleElement.sheet.cssRules.length); | 53 |
118 } | 54 function expectHidden(element, id) |
119 | 55 { |
120 function createElement(parent, type = "div", id = findUniqueId(), | 56 let withId = ""; |
121 innerText = null) | 57 if (typeof id != "undefined") |
122 { | 58 withId = ` with ID '${id}'`; |
123 let element = testDocument.createElement(type); | 59 |
124 element.id = id; | 60 assert.equal( |
125 if (!parent) | 61 window.getComputedStyle(element).display, "none", |
126 testDocument.body.appendChild(element); | 62 `The element${withId}'s display property should be set to 'none'`); |
127 else | |
128 parent.appendChild(element); | |
129 if (innerText) | |
130 element.innerText = innerText; | |
131 return element; | |
132 } | |
133 | |
134 // Insert a <div> with a unique id and a CSS rule | |
135 // for the the selector matching the id. | |
136 function createElementWithStyle(styleBlock, parent) | |
137 { | |
138 let element = createElement(parent); | |
139 insertStyleRule("#" + element.id + " " + styleBlock); | |
140 return element; | |
141 } | |
142 | |
143 // Create a new ElemHideEmulation instance with @selectors. | |
144 async function applyElemHideEmulation(test, selectors) | |
145 { | |
146 await Promise.resolve(); | |
147 | |
148 try | |
149 { | |
150 let elemHideEmulation = new ElemHideEmulation( | |
151 elems => | |
152 { | |
153 for (let elem of elems) | |
154 elem.style.display = "none"; | |
155 } | |
156 ); | |
157 | |
158 elemHideEmulation.document = testDocument; | |
159 elemHideEmulation.MIN_INVOCATION_INTERVAL = REFRESH_INTERVAL / 2; | |
160 elemHideEmulation.apply(selectors.map( | |
161 selector => ({selector, text: selector}) | |
162 )); | |
163 | |
164 return elemHideEmulation; | |
165 } | 63 } |
166 catch (error) | 64 |
167 { | 65 function expectVisible(element, id) |
168 unexpectedError(test, error); | 66 { |
| 67 let withId = ""; |
| 68 if (typeof id != "undefined") |
| 69 withId = ` with ID '${id}'`; |
| 70 |
| 71 assert.notEqual( |
| 72 window.getComputedStyle(element).display, "none", |
| 73 `The element${withId}'s display property should not be set to 'none'`); |
169 } | 74 } |
170 } | 75 |
171 | 76 function expectProcessed(element, id = null) |
172 exports.testVerbatimPropertySelector = async function(test) | 77 { |
173 { | 78 let withId = ""; |
174 let toHide = createElementWithStyle("{background-color: #000}"); | 79 if (id) |
175 let selectors = [":-abp-properties(background-color: rgb(0, 0, 0))"]; | 80 withId = ` with ID '${id}'`; |
176 | 81 |
177 if (await applyElemHideEmulation(test, selectors)) | 82 assert.ok( |
178 expectHidden(test, toHide); | 83 getTestInfo().lastProcessedElements.has(element), |
179 | 84 `The element${withId} should have been processed`); |
180 test.done(); | |
181 }; | |
182 | |
183 exports.testVerbatimPropertySelectorWithPrefix = async function(test) | |
184 { | |
185 let parent = createElementWithStyle("{background-color: #000}"); | |
186 let toHide = createElementWithStyle("{background-color: #000}", parent); | |
187 | |
188 let selectors = ["div > :-abp-properties(background-color: rgb(0, 0, 0))"]; | |
189 | |
190 if (await applyElemHideEmulation(test, selectors)) | |
191 { | |
192 expectVisible(test, parent); | |
193 expectHidden(test, toHide); | |
194 } | 85 } |
195 | 86 |
196 test.done(); | 87 function expectNotProcessed(element, id = null) |
197 }; | 88 { |
198 | 89 let withId = ""; |
199 exports.testVerbatimPropertySelectorWithPrefixNoMatch = async function(test) | 90 if (id) |
200 { | 91 withId = ` with ID '${id}'`; |
201 let parent = createElementWithStyle("{background-color: #000}"); | 92 |
202 let toHide = createElementWithStyle("{background-color: #fff}", parent); | 93 assert.ok( |
203 | 94 !getTestInfo().lastProcessedElements.has(element), |
204 let selectors = ["div > :-abp-properties(background-color: rgb(0, 0, 0))"]; | 95 `The element${withId} should not have been processed`); |
205 | |
206 if (await applyElemHideEmulation(test, selectors)) | |
207 { | |
208 expectVisible(test, parent); | |
209 expectVisible(test, toHide); | |
210 } | 96 } |
211 | 97 |
212 test.done(); | 98 function findUniqueId() |
213 }; | 99 { |
214 | 100 let id = "elemHideEmulationTest-" + Math.floor(Math.random() * 10000); |
215 exports.testVerbatimPropertySelectorWithSuffix = async function(test) | 101 if (!testDocument.getElementById(id)) |
216 { | 102 return id; |
217 let parent = createElementWithStyle("{background-color: #000}"); | 103 return findUniqueId(); |
218 let toHide = createElementWithStyle("{background-color: #000}", parent); | |
219 | |
220 let selectors = [":-abp-properties(background-color: rgb(0, 0, 0)) > div"]; | |
221 | |
222 if (await applyElemHideEmulation(test, selectors)) | |
223 { | |
224 expectVisible(test, parent); | |
225 expectHidden(test, toHide); | |
226 } | 104 } |
227 | 105 |
228 test.done(); | 106 function insertStyleRule(rule) |
229 }; | 107 { |
230 | 108 let styleElement; |
231 exports.testVerbatimPropertyPseudoSelectorWithPrefixAndSuffix = async function(t
est) | 109 let styleElements = testDocument.head.getElementsByTagName("style"); |
232 { | 110 if (styleElements.length) |
233 let parent = createElementWithStyle("{background-color: #000}"); | 111 styleElement = styleElements[0]; |
234 let middle = createElementWithStyle("{background-color: #000}", parent); | 112 else |
235 let toHide = createElementWithStyle("{background-color: #000}", middle); | 113 { |
236 | 114 styleElement = testDocument.createElement("style"); |
237 let selectors = ["div > :-abp-properties(background-color: rgb(0, 0, 0)) > div
"]; | 115 testDocument.head.appendChild(styleElement); |
238 | 116 } |
239 if (await applyElemHideEmulation(test, selectors)) | 117 styleElement.sheet.insertRule(rule, styleElement.sheet.cssRules.length); |
240 { | |
241 expectVisible(test, parent); | |
242 expectVisible(test, middle); | |
243 expectHidden(test, toHide); | |
244 } | 118 } |
245 | 119 |
246 test.done(); | 120 function createElement(parent, type = "div", id = findUniqueId(), |
247 }; | 121 innerText = null) |
248 | 122 { |
249 // Add the style. Then add the element for that style. | 123 let element = testDocument.createElement(type); |
250 // This should retrigger the filtering and hide it. | 124 element.id = id; |
251 exports.testPropertyPseudoSelectorAddStyleAndElement = async function(test) | 125 if (!parent) |
252 { | 126 testDocument.body.appendChild(element); |
253 let styleElement; | 127 else |
254 let toHide; | 128 parent.appendChild(element); |
255 | 129 if (innerText) |
256 let selectors = [":-abp-properties(background-color: rgb(0, 0, 0))"]; | 130 element.innerText = innerText; |
257 | 131 return element; |
258 if (await applyElemHideEmulation(test, selectors)) | |
259 { | |
260 styleElement = testDocument.createElement("style"); | |
261 testDocument.head.appendChild(styleElement); | |
262 styleElement.sheet.insertRule("#toHide {background-color: #000}"); | |
263 await timeout(REFRESH_INTERVAL); | |
264 | |
265 toHide = createElement(); | |
266 toHide.id = "toHide"; | |
267 expectVisible(test, toHide); | |
268 await timeout(REFRESH_INTERVAL); | |
269 | |
270 expectHidden(test, toHide); | |
271 } | 132 } |
272 | 133 |
273 test.done(); | 134 // Insert a <div> with a unique id and a CSS rule |
274 }; | 135 // for the the selector matching the id. |
275 | 136 function createElementWithStyle(styleBlock, parent) |
276 exports.testPropertySelectorWithWildcard = async function(test) | 137 { |
277 { | 138 let element = createElement(parent); |
278 let toHide = createElementWithStyle("{background-color: #000}"); | 139 insertStyleRule("#" + element.id + " " + styleBlock); |
279 let selectors = [":-abp-properties(*color: rgb(0, 0, 0))"]; | 140 return element; |
280 | |
281 if (await applyElemHideEmulation(test, selectors)) | |
282 expectHidden(test, toHide); | |
283 | |
284 test.done(); | |
285 }; | |
286 | |
287 exports.testPropertySelectorWithRegularExpression = async function(test) | |
288 { | |
289 let toHide = createElementWithStyle("{background-color: #000}"); | |
290 let selectors = [":-abp-properties(/.*color: rgb\\(0, 0, 0\\)/)"]; | |
291 | |
292 if (await applyElemHideEmulation(test, selectors)) | |
293 expectHidden(test, toHide); | |
294 | |
295 test.done(); | |
296 }; | |
297 | |
298 exports.testDynamicallyChangedProperty = async function(test) | |
299 { | |
300 let toHide = createElementWithStyle("{}"); | |
301 let selectors = [":-abp-properties(background-color: rgb(0, 0, 0))"]; | |
302 | |
303 if (await applyElemHideEmulation(test, selectors)) | |
304 { | |
305 expectVisible(test, toHide); | |
306 insertStyleRule("#" + toHide.id + " {background-color: #000}"); | |
307 | |
308 await timeout(0); | |
309 | |
310 // Re-evaluation will only happen after a delay | |
311 expectVisible(test, toHide); | |
312 await timeout(REFRESH_INTERVAL); | |
313 | |
314 expectHidden(test, toHide); | |
315 } | 141 } |
316 | 142 |
317 test.done(); | 143 // Create a new ElemHideEmulation instance with @selectors. |
318 }; | 144 async function applyElemHideEmulation(selectors) |
319 | 145 { |
320 exports.testPseudoClassWithPropBeforeSelector = async function(test) | 146 await Promise.resolve(); |
321 { | 147 |
322 let parent = createElementWithStyle("{}"); | 148 try |
323 let child = createElementWithStyle("{background-color: #000}", parent); | 149 { |
324 | 150 let elemHideEmulation = new ElemHideEmulation( |
325 let selectors = ["div:-abp-properties(content: \"publicite\")"]; | 151 elems => |
326 | 152 { |
327 insertStyleRule(`#${child.id}::before {content: "publicite"}`); | 153 for (let elem of elems) |
328 | 154 elem.style.display = "none"; |
329 if (await applyElemHideEmulation(test, selectors)) | 155 } |
330 { | 156 ); |
331 expectHidden(test, child); | 157 |
332 expectVisible(test, parent); | 158 elemHideEmulation.document = testDocument; |
333 } | 159 elemHideEmulation.MIN_INVOCATION_INTERVAL = REFRESH_INTERVAL / 2; |
334 | 160 elemHideEmulation.apply(selectors.map( |
335 test.done(); | 161 selector => ({selector, text: selector}) |
336 }; | 162 )); |
337 | 163 |
338 exports.testPseudoClassHasSelector = async function(test) | 164 return elemHideEmulation; |
339 { | 165 } |
340 let toHide = createElementWithStyle("{}"); | 166 catch (error) |
341 | 167 { |
342 if (await applyElemHideEmulation(test, ["div:-abp-has(div)"])) | 168 unexpectedError(error); |
343 expectVisible(test, toHide); | |
344 | |
345 test.done(); | |
346 }; | |
347 | |
348 exports.testPseudoClassHasSelectorWithPrefix = async function(test) | |
349 { | |
350 let parent = createElementWithStyle("{}"); | |
351 let child = createElementWithStyle("{}", parent); | |
352 | |
353 if (await applyElemHideEmulation(test, ["div:-abp-has(div)"])) | |
354 { | |
355 expectHidden(test, parent); | |
356 expectVisible(test, child); | |
357 } | |
358 | |
359 test.done(); | |
360 }; | |
361 | |
362 exports.testPseudoClassHasSelectorWithSuffix = async function(test) | |
363 { | |
364 let parent = createElementWithStyle("{}"); | |
365 let middle = createElementWithStyle("{}", parent); | |
366 let child = createElementWithStyle("{}", middle); | |
367 | |
368 if (await applyElemHideEmulation(test, ["div:-abp-has(div) > div"])) | |
369 { | |
370 expectVisible(test, parent); | |
371 expectHidden(test, middle); | |
372 expectHidden(test, child); | |
373 } | |
374 | |
375 test.done(); | |
376 }; | |
377 | |
378 exports.testPseudoClassHasSelectorWithSuffixSibling = async function(test) | |
379 { | |
380 let parent = createElementWithStyle("{}"); | |
381 let middle = createElementWithStyle("{}", parent); | |
382 let toHide = createElementWithStyle("{}"); | |
383 | |
384 if (await applyElemHideEmulation(test, ["div:-abp-has(div) + div"])) | |
385 { | |
386 expectVisible(test, parent); | |
387 expectVisible(test, middle); | |
388 expectHidden(test, toHide); | |
389 } | |
390 | |
391 test.done(); | |
392 }; | |
393 | |
394 exports.testPseudoClassHasSelectorWithSuffixSiblingChild = async function(test) | |
395 { | |
396 // <div> | |
397 // <div></div> | |
398 // <div> | |
399 // <div>to hide</div> | |
400 // </div> | |
401 // </div> | |
402 let parent = createElementWithStyle("{}"); | |
403 let middle = createElementWithStyle("{}", parent); | |
404 let sibling = createElementWithStyle("{}"); | |
405 let toHide = createElementWithStyle("{}", sibling); | |
406 | |
407 if (await applyElemHideEmulation(test, ["div:-abp-has(div) + div > div"])) | |
408 { | |
409 expectVisible(test, parent); | |
410 expectVisible(test, middle); | |
411 expectVisible(test, sibling); | |
412 expectHidden(test, toHide); | |
413 } | |
414 | |
415 test.done(); | |
416 }; | |
417 | |
418 function compareExpectations(test, elems, expectations) | |
419 { | |
420 for (let elem in expectations) | |
421 { | |
422 if (elems[elem]) | |
423 { | |
424 if (expectations[elem]) | |
425 expectVisible(test, elems[elem], elem); | |
426 else | |
427 expectHidden(test, elems[elem], elem); | |
428 } | 169 } |
429 } | 170 } |
430 } | 171 |
431 | 172 describe("Verbatim Property Selector", () => |
432 async function runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling(test, se
lector, expectations) | 173 { |
433 { | 174 it("Regular", async() => |
434 testDocument.body.innerHTML = `<div id="parent"> | 175 { |
435 <div id="middle"> | 176 let toHide = createElementWithStyle("{background-color: #000}"); |
436 <div id="middle1"><div id="inside" class="inside"></div></div> | 177 let selectors = [":-abp-properties(background-color: rgb(0, 0, 0))"]; |
437 </div> | 178 |
438 <div id="sibling"> | 179 if (await applyElemHideEmulation(selectors)) |
439 <div id="tohide"><span>to hide</span></div> | 180 expectHidden(toHide); |
440 </div> | 181 }); |
441 <div id="sibling2"> | 182 |
442 <div id="sibling21"><div id="sibling211" class="inside"></div></div> | 183 it("With Prefix", async() => |
443 </div> | 184 { |
444 </div>`; | 185 let parent = createElementWithStyle("{background-color: #000}"); |
445 let elems = { | 186 let toHide = createElementWithStyle("{background-color: #000}", parent); |
446 parent: testDocument.getElementById("parent"), | 187 |
447 middle: testDocument.getElementById("middle"), | 188 let selectors = ["div > :-abp-properties(background-color: rgb(0, 0, 0))"]
; |
448 inside: testDocument.getElementById("inside"), | 189 |
449 sibling: testDocument.getElementById("sibling"), | 190 if (await applyElemHideEmulation(selectors)) |
450 sibling2: testDocument.getElementById("sibling2"), | 191 { |
451 toHide: testDocument.getElementById("tohide") | 192 expectVisible(parent); |
452 }; | 193 expectHidden(toHide); |
453 | 194 } |
454 insertStyleRule(".inside {}"); | 195 }); |
455 | 196 |
456 if (await applyElemHideEmulation(test, [selector])) | 197 it("With Prefix No Match", async() => |
457 compareExpectations(test, elems, expectations); | 198 { |
458 | 199 let parent = createElementWithStyle("{background-color: #000}"); |
459 test.done(); | 200 let toHide = createElementWithStyle("{background-color: #fff}", parent); |
460 } | 201 |
461 | 202 let selectors = ["div > :-abp-properties(background-color: rgb(0, 0, 0))"]
; |
462 exports.testPseudoClassHasSelectorWithHasAndWithSuffixSibling = function(test) | 203 |
463 { | 204 if (await applyElemHideEmulation(selectors)) |
464 let expectations = { | 205 { |
465 parent: true, | 206 expectVisible(parent); |
466 middile: true, | 207 expectVisible(toHide); |
467 inside: true, | 208 } |
468 sibling: true, | 209 }); |
469 sibling2: true, | 210 |
470 toHide: false | 211 it("With Suffix", async() => |
471 }; | 212 { |
472 runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling( | 213 let parent = createElementWithStyle("{background-color: #000}"); |
473 test, "div:-abp-has(:-abp-has(div.inside)) + div > div", expectations); | 214 let toHide = createElementWithStyle("{background-color: #000}", parent); |
474 }; | 215 |
475 | 216 let selectors = [":-abp-properties(background-color: rgb(0, 0, 0)) > div"]
; |
476 exports.testPseudoClassHasSelectorWithHasAndWithSuffixSibling2 = function(test) | 217 |
477 { | 218 if (await applyElemHideEmulation(selectors)) |
478 let expectations = { | 219 { |
479 parent: true, | 220 expectVisible(parent); |
480 middile: true, | 221 expectHidden(toHide); |
481 inside: true, | 222 } |
482 sibling: true, | 223 }); |
483 sibling2: true, | 224 |
484 toHide: false | 225 |
485 }; | 226 it("With prefix and suffix", async() => |
486 runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling( | 227 { |
487 test, "div:-abp-has(:-abp-has(> div.inside)) + div > div", expectations); | 228 let parent = createElementWithStyle("{background-color: #000}"); |
488 }; | 229 let middle = createElementWithStyle("{background-color: #000}", parent); |
489 | 230 let toHide = createElementWithStyle("{background-color: #000}", middle); |
490 exports.testPseudoClassHasSelectorWithHasAndWithSuffixSibling3 = function(test) | 231 |
491 { | 232 let selectors = ["div > :-abp-properties(background-color: rgb(0, 0, 0)) >
div"]; |
492 let expectations = { | 233 |
493 parent: true, | 234 if (await applyElemHideEmulation(selectors)) |
494 middile: true, | 235 { |
495 inside: true, | 236 expectVisible(parent); |
496 sibling: true, | 237 expectVisible(middle); |
497 sibling2: true, | 238 expectHidden(toHide); |
498 toHide: false | 239 } |
499 }; | 240 }); |
500 runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling( | 241 }); |
501 test, "div:-abp-has(> div:-abp-has(div.inside)) + div > div", expectations); | 242 |
502 }; | 243 // Add the style. Then add the element for that style. |
503 | 244 // This should retrigger the filtering and hide it. |
504 exports.testPseudoClassHasSelectorWithSuffixSiblingNoop = function(test) | 245 it("Property Pseudo Selector Add Style and elemment", async() => |
505 { | 246 { |
506 let expectations = { | 247 let styleElement; |
507 parent: true, | 248 let toHide; |
508 middile: true, | 249 |
509 inside: true, | 250 let selectors = [":-abp-properties(background-color: rgb(0, 0, 0))"]; |
510 sibling: true, | 251 |
511 sibling2: true, | 252 if (await applyElemHideEmulation(selectors)) |
512 toHide: true | 253 { |
513 }; | 254 styleElement = testDocument.createElement("style"); |
514 runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling( | 255 testDocument.head.appendChild(styleElement); |
515 test, "div:-abp-has(> body div.inside) + div > div", expectations); | 256 styleElement.sheet.insertRule("#toHide {background-color: #000}"); |
516 }; | 257 await timeout(REFRESH_INTERVAL); |
517 | 258 |
518 exports.testPseudoClassHasSelectorWithSuffixSiblingContains = function(test) | 259 toHide = createElement(); |
519 { | 260 toHide.id = "toHide"; |
520 let expectations = { | 261 expectVisible(toHide); |
521 parent: true, | 262 await timeout(REFRESH_INTERVAL); |
522 middile: true, | 263 |
523 inside: true, | 264 expectHidden(toHide); |
524 sibling: true, | |
525 sibling2: true, | |
526 toHide: true | |
527 }; | |
528 runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling( | |
529 test, "div:-abp-has(> span:-abp-contains(Advertisment))", expectations); | |
530 }; | |
531 | |
532 async function runTestQualifier(test, selector) | |
533 { | |
534 testDocument.body.innerHTML = ` | |
535 <style> | |
536 span::before { | |
537 content: "any"; | |
538 } | 265 } |
539 </style> | 266 }); |
540 <div id="toHide"> | 267 |
541 <a> | 268 describe("Property Selector", () => |
542 <p> | 269 { |
543 <span></span> | 270 it("With Wildcard", async() => |
544 </p> | 271 { |
545 </a> | 272 let toHide = createElementWithStyle("{background-color: #000}"); |
546 </div>`; | 273 let selectors = [":-abp-properties(*color: rgb(0, 0, 0))"]; |
547 | 274 |
548 if (await applyElemHideEmulation(test, [selector])) | 275 if (await applyElemHideEmulation(selectors)) |
549 expectHidden(test, testDocument.getElementById("toHide")); | 276 expectHidden(toHide); |
550 | 277 }); |
551 test.done(); | 278 |
552 } | 279 it("With regular expression", async() => |
553 | 280 { |
554 // See issue https://issues.adblockplus.org/ticket/7428 | 281 let toHide = createElementWithStyle("{background-color: #000}"); |
555 exports.testPropertySelectorCombinatorQualifier = function(test) | 282 let selectors = [":-abp-properties(/.*color: rgb\\(0, 0, 0\\)/)"]; |
556 { | 283 |
557 runTestQualifier( | 284 if (await applyElemHideEmulation(selectors)) |
558 test, | 285 expectHidden(toHide); |
559 "div:-abp-has(> a p > :-abp-properties(content: \"any\"))" | 286 }); |
560 ); | 287 }); |
561 }; | 288 |
562 | 289 it("Dynamically Changed Property", async() => |
563 // See issue https://issues.adblockplus.org/ticket/7359 | 290 { |
564 exports.testPropertySelectorCombinatorQualifierNested = function(test) | 291 let toHide = createElementWithStyle("{}"); |
565 { | 292 let selectors = [":-abp-properties(background-color: rgb(0, 0, 0))"]; |
566 runTestQualifier( | 293 |
567 test, | 294 if (await applyElemHideEmulation(selectors)) |
568 "div:-abp-has(> a p:-abp-has(> :-abp-properties(content: \"any\")))" | 295 { |
569 ); | 296 expectVisible(toHide); |
570 }; | 297 insertStyleRule("#" + toHide.id + " {background-color: #000}"); |
571 | 298 |
572 // See issue https://issues.adblockplus.org/ticket/7400 | 299 await timeout(0); |
573 exports.testPropertySelectorIdenticalTypeQualifier = function(test) | 300 |
574 { | 301 // Re-evaluation will only happen after a delay |
575 runTestQualifier( | 302 expectVisible(toHide); |
576 test, | 303 await timeout(REFRESH_INTERVAL); |
577 "div:-abp-has(span:-abp-properties(content: \"any\"))" | 304 |
578 ); | 305 expectHidden(toHide); |
579 }; | 306 } |
580 | 307 }); |
581 // See issue https://issues.adblockplus.org/ticket/7400 | 308 |
582 exports.testPropertySelectorIdenticalTypeQualifierNested = function(test) | 309 describe("Pseudo Class", () => |
583 { | 310 { |
584 runTestQualifier( | 311 it("With prop before selector", async() => |
585 test, | 312 { |
586 "div:-abp-has(p:-abp-has(span:-abp-properties(content: \"any\")))" | 313 let parent = createElementWithStyle("{}"); |
587 ); | 314 let child = createElementWithStyle("{background-color: #000}", parent); |
588 }; | 315 |
589 | 316 let selectors = ["div:-abp-properties(content: \"publicite\")"]; |
590 async function runTestPseudoClassContains(test, selector, expectations) | 317 |
591 { | 318 insertStyleRule(`#${child.id}::before {content: "publicite"}`); |
592 testDocument.body.innerHTML = `<div id="parent"> | 319 |
593 <div id="middle"> | 320 if (await applyElemHideEmulation(selectors)) |
594 <div id="middle1"><div id="inside" class="inside"></div></div> | 321 { |
595 </div> | 322 expectHidden(child); |
596 <div id="sibling"> | 323 expectVisible(parent); |
597 <div id="tohide">to hide \ud83d\ude42!</div> | 324 } |
598 </div> | 325 }); |
599 <div id="sibling2"> | 326 |
600 <div id="sibling21"><div id="sibling211" class="inside">Ad*</div></div> | 327 function compareExpectations(elems, expectations) |
601 </div> | 328 { |
602 </div>`; | 329 for (let elem in expectations) |
603 let elems = { | 330 { |
604 parent: testDocument.getElementById("parent"), | 331 if (elems[elem]) |
605 middle: testDocument.getElementById("middle"), | 332 { |
606 inside: testDocument.getElementById("inside"), | 333 if (expectations[elem]) |
607 sibling: testDocument.getElementById("sibling"), | 334 expectVisible(elems[elem], elem); |
608 sibling2: testDocument.getElementById("sibling2"), | 335 else |
609 toHide: testDocument.getElementById("tohide") | 336 expectHidden(elems[elem], elem); |
610 }; | 337 } |
611 | 338 } |
612 if (await applyElemHideEmulation(test, [selector])) | 339 } |
613 compareExpectations(test, elems, expectations); | 340 |
614 | 341 describe("Has Selector", () => |
615 test.done(); | 342 { |
616 } | 343 it("Simple", async() => |
617 | 344 { |
618 exports.testPseudoClassContainsText = function(test) | 345 let toHide = createElementWithStyle("{}"); |
619 { | 346 |
620 let expectations = { | 347 if (await applyElemHideEmulation(["div:-abp-has(div)"])) |
621 parent: true, | 348 expectVisible(toHide); |
622 middle: true, | 349 }); |
623 inside: true, | 350 |
624 sibling: false, | 351 it("With prefix", async() => |
625 sibling2: true, | 352 { |
626 toHide: true | 353 let parent = createElementWithStyle("{}"); |
627 }; | 354 let child = createElementWithStyle("{}", parent); |
628 runTestPseudoClassContains( | 355 |
629 test, "#parent div:-abp-contains(to hide)", expectations); | 356 if (await applyElemHideEmulation(["div:-abp-has(div)"])) |
630 }; | 357 { |
631 | 358 expectHidden(parent); |
632 exports.testPseudoClassContainsRegexp = function(test) | 359 expectVisible(child); |
633 { | 360 } |
634 let expectations = { | 361 }); |
635 parent: true, | 362 |
636 middle: true, | 363 it("With suffix", async() => |
637 inside: true, | 364 { |
638 sibling: false, | 365 let parent = createElementWithStyle("{}"); |
639 sibling2: true, | 366 let middle = createElementWithStyle("{}", parent); |
640 toHide: true | 367 let child = createElementWithStyle("{}", middle); |
641 }; | 368 |
642 runTestPseudoClassContains( | 369 if (await applyElemHideEmulation(["div:-abp-has(div) > div"])) |
643 test, "#parent div:-abp-contains(/to\\shide/)", expectations); | 370 { |
644 }; | 371 expectVisible(parent); |
645 | 372 expectHidden(middle); |
646 exports.testPseudoClassContainsRegexpIFlag = function(test) | 373 expectHidden(child); |
647 { | 374 } |
648 let expectations = { | 375 }); |
649 parent: true, | 376 |
650 middle: true, | 377 it("With suffix sibling", async() => |
651 inside: true, | 378 { |
652 sibling: false, | 379 let parent = createElementWithStyle("{}"); |
653 sibling2: true, | 380 let middle = createElementWithStyle("{}", parent); |
654 toHide: true | 381 let toHide = createElementWithStyle("{}"); |
655 }; | 382 |
656 runTestPseudoClassContains( | 383 if (await applyElemHideEmulation(["div:-abp-has(div) + div"])) |
657 test, "#parent div:-abp-contains(/to\\sHide/i)", expectations); | 384 { |
658 }; | 385 expectVisible(parent); |
659 | 386 expectVisible(middle); |
660 exports.testPseudoClassContainsRegexpUFlag = function(test) | 387 expectHidden(toHide); |
661 { | 388 } |
662 let expectations = { | 389 }); |
663 parent: true, | 390 |
664 middle: true, | 391 it("With suffix sibling child", async() => |
665 inside: true, | 392 { |
666 sibling: false, | 393 // <div> |
667 sibling2: true, | 394 // <div></div> |
668 toHide: true | 395 // <div> |
669 }; | 396 // <div>to hide</div> |
670 runTestPseudoClassContains( | 397 // </div> |
671 test, "#parent div:-abp-contains(/to\\shide\\s.!/u)", expectations); | 398 // </div> |
672 }; | 399 let parent = createElementWithStyle("{}"); |
673 | 400 let middle = createElementWithStyle("{}", parent); |
674 exports.testPseudoClassContainsWildcardNoMatch = function(test) | 401 let sibling = createElementWithStyle("{}"); |
675 { | 402 let toHide = createElementWithStyle("{}", sibling); |
676 let expectations = { | 403 |
677 parent: true, | 404 if (await applyElemHideEmulation(["div:-abp-has(div) + div > div"])) |
678 middle: true, | 405 { |
679 inside: true, | 406 expectVisible(parent); |
680 sibling: true, | 407 expectVisible(middle); |
681 sibling2: true, | 408 expectVisible(sibling); |
682 toHide: true | 409 expectHidden(toHide); |
683 }; | 410 } |
684 // this filter shouldn't match anything as "*" has no meaning. | 411 }); |
685 runTestPseudoClassContains( | 412 |
686 test, "#parent div:-abp-contains(to *hide)", expectations); | 413 async function runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling(se
lector, expectations) |
687 }; | 414 { |
688 | 415 testDocument.body.innerHTML = `<div id="parent"> |
689 exports.testPseudoClassContainsWildcardMatch = function(test) | 416 <div id="middle"> |
690 { | 417 <div id="middle1"><div id="inside" class="inside"></div></div> |
691 let expectations = { | 418 </div> |
692 parent: true, | 419 <div id="sibling"> |
693 middle: true, | 420 <div id="tohide"><span>to hide</span></div> |
694 inside: true, | 421 </div> |
695 sibling: true, | 422 <div id="sibling2"> |
696 sibling2: false, | 423 <div id="sibling21"><div id="sibling211" class="inside"></div></div> |
697 toHide: true | 424 </div> |
698 }; | 425 </div>`; |
699 runTestPseudoClassContains( | 426 let elems = { |
700 test, "#parent div:-abp-contains(Ad*)", expectations); | 427 parent: testDocument.getElementById("parent"), |
701 }; | 428 middle: testDocument.getElementById("middle"), |
702 | 429 inside: testDocument.getElementById("inside"), |
703 exports.testPseudoClassHasSelectorWithPropSelector = async function(test) | 430 sibling: testDocument.getElementById("sibling"), |
704 { | 431 sibling2: testDocument.getElementById("sibling2"), |
705 let parent = createElementWithStyle("{}"); | 432 toHide: testDocument.getElementById("tohide") |
706 let child = createElementWithStyle("{background-color: #000}", parent); | 433 }; |
707 | 434 |
708 let selectors = ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0, 0)
))"]; | 435 insertStyleRule(".inside {}"); |
709 | 436 if (await applyElemHideEmulation([selector])) |
710 if (await applyElemHideEmulation(test, selectors)) | 437 compareExpectations(elems, expectations); |
711 { | 438 } |
712 expectVisible(test, child); | 439 |
713 expectHidden(test, parent); | 440 it("With has and with suffix sibling", () => |
714 } | 441 { |
715 | 442 let expectations = { |
716 test.done(); | 443 parent: true, |
717 }; | 444 middile: true, |
718 | 445 inside: true, |
719 exports.testPseudoClassHasSelectorWithPropSelector2 = async function(test) | 446 sibling: true, |
720 { | 447 sibling2: true, |
721 let parent = createElementWithStyle("{}"); | 448 toHide: false |
722 let child = createElementWithStyle("{}", parent); | 449 }; |
723 | 450 runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling( |
724 let selectors = ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0, 0)
))"]; | 451 "div:-abp-has(:-abp-has(div.inside)) + div > div", expectations); |
725 | 452 }); |
726 insertStyleRule("body #" + parent.id + " > div { background-color: #000}"); | 453 |
727 | 454 it("With has an with suffix sibling (2)", () => |
728 if (await applyElemHideEmulation(test, selectors)) | 455 { |
729 { | 456 let expectations = { |
730 expectVisible(test, child); | 457 parent: true, |
731 expectHidden(test, parent); | 458 middile: true, |
732 } | 459 inside: true, |
733 | 460 sibling: true, |
734 test.done(); | 461 sibling2: true, |
735 }; | 462 toHide: false |
736 | 463 }; |
737 exports.testDomUpdatesStyle = async function(test) | 464 runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling( |
738 { | 465 "div:-abp-has(:-abp-has(> div.inside)) + div > div", expectations); |
739 let parent = createElementWithStyle("{}"); | 466 }); |
740 let child = createElementWithStyle("{}", parent); | 467 |
741 | 468 it("With has an with suffix sibling (3)", () => |
742 let selectors = ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0, 0)
))"]; | 469 { |
743 | 470 let expectations = { |
744 if (await applyElemHideEmulation(test, selectors)) | 471 parent: true, |
745 { | 472 middile: true, |
746 expectVisible(test, child); | 473 inside: true, |
747 expectVisible(test, parent); | 474 sibling: true, |
748 | 475 sibling2: true, |
749 insertStyleRule("body #" + parent.id + " > div { background-color: #000}"); | 476 toHide: false |
750 await timeout(0); | 477 }; |
751 | 478 runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling( |
752 expectVisible(test, child); | 479 "div:-abp-has(> div:-abp-has(div.inside)) + div > div", expectations); |
753 expectVisible(test, parent); | 480 }); |
754 await timeout(REFRESH_INTERVAL); | 481 |
755 | 482 it("With suffix sibling no-op", () => |
756 expectVisible(test, child); | 483 { |
757 expectHidden(test, parent); | 484 let expectations = { |
758 } | 485 parent: true, |
759 | 486 middile: true, |
760 test.done(); | 487 inside: true, |
761 }; | 488 sibling: true, |
762 | 489 sibling2: true, |
763 exports.testDomUpdatesContent = async function(test) | 490 toHide: true |
764 { | 491 }; |
765 let parent = createElementWithStyle("{}"); | 492 runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling( |
766 let child = createElementWithStyle("{}", parent); | 493 "div:-abp-has(> body div.inside) + div > div", expectations); |
767 | 494 }); |
768 if (await applyElemHideEmulation(test, ["div > div:-abp-contains(hide me)"])) | 495 |
769 { | 496 it("With suffix sibling contains", () => |
770 expectVisible(test, parent); | 497 { |
771 expectVisible(test, child); | 498 let expectations = { |
772 | 499 parent: true, |
773 child.textContent = "hide me"; | 500 middile: true, |
774 await timeout(0); | 501 inside: true, |
775 | 502 sibling: true, |
776 expectVisible(test, parent); | 503 sibling2: true, |
777 expectVisible(test, child); | 504 toHide: true |
778 await timeout(REFRESH_INTERVAL); | 505 }; |
779 | 506 runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling( |
780 expectVisible(test, parent); | 507 "div:-abp-has(> span:-abp-contains(Advertisment))", expectations); |
781 expectHidden(test, child); | 508 }); |
782 } | 509 }); |
783 | 510 |
784 test.done(); | 511 describe("Property Selector Qualifiers", () => |
785 }; | 512 { |
786 | 513 async function runTestQualifier(selector) |
787 exports.testDomUpdatesNewElement = async function(test) | 514 { |
788 { | 515 testDocument.body.innerHTML = ` |
789 let parent = createElementWithStyle("{}"); | 516 <style> |
790 let child = createElementWithStyle("{ background-color: #000}", parent); | 517 span::before { |
791 let sibling; | 518 content: "any"; |
792 let child2; | 519 } |
793 | 520 </style> |
794 let selectors = ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0, 0)
))"]; | 521 <div id="toHide"> |
795 | 522 <a> |
796 if (await applyElemHideEmulation(test, selectors)) | 523 <p> |
797 { | 524 <span></span> |
798 expectHidden(test, parent); | 525 </p> |
799 expectVisible(test, child); | 526 </a> |
800 | 527 </div>`; |
801 sibling = createElementWithStyle("{}"); | 528 |
802 await timeout(0); | 529 if (await applyElemHideEmulation([selector])) |
803 | 530 expectHidden(testDocument.getElementById("toHide")); |
804 expectHidden(test, parent); | 531 } |
805 expectVisible(test, child); | 532 |
806 expectVisible(test, sibling); | 533 // See issue https://issues.adblockplus.org/ticket/7428 |
807 | 534 it("Combinator", () => |
808 await timeout(REFRESH_INTERVAL); | 535 { |
809 | 536 runTestQualifier( |
810 expectHidden(test, parent); | 537 "div:-abp-has(> a p > :-abp-properties(content: \"any\"))" |
811 expectVisible(test, child); | 538 ); |
812 expectVisible(test, sibling); | 539 }); |
813 | 540 |
814 child2 = createElementWithStyle("{ background-color: #000}", | 541 // See issue https://issues.adblockplus.org/ticket/7359 |
815 sibling); | 542 it("Nested Combinator", () => |
816 await timeout(0); | 543 { |
817 | 544 runTestQualifier( |
818 expectVisible(test, child2); | 545 "div:-abp-has(> a p:-abp-has(> :-abp-properties(content: \"any\")))" |
819 await timeout(REFRESH_INTERVAL); | 546 ); |
820 | 547 }); |
821 expectHidden(test, parent); | 548 |
822 expectVisible(test, child); | 549 // See issue https://issues.adblockplus.org/ticket/7400 |
823 expectHidden(test, sibling); | 550 it("Identical", () => |
824 expectVisible(test, child2); | 551 { |
825 } | 552 runTestQualifier( |
826 | 553 "div:-abp-has(span:-abp-properties(content: \"any\"))" |
827 test.done(); | 554 ); |
828 }; | 555 }); |
829 | 556 |
830 exports.testPseudoClassPropertiesOnStyleSheetLoad = async function(test) | 557 // See issue https://issues.adblockplus.org/ticket/7400 |
831 { | 558 it("Nested Identical", () => |
832 let parent = createElement(); | 559 { |
833 let child = createElement(parent); | 560 runTestQualifier( |
834 | 561 "div:-abp-has(p:-abp-has(span:-abp-properties(content: \"any\")))" |
835 let selectors = [ | 562 ); |
836 "div:-abp-properties(background-color: rgb(0, 0, 0))", | 563 }); |
837 "div:-abp-contains(hide me)", | 564 }); |
838 "div:-abp-has(> div.hideMe)" | 565 |
839 ]; | 566 describe("Contains selector", () => |
840 | 567 { |
841 if (await applyElemHideEmulation(test, selectors)) | 568 async function runTestPseudoClassContains(selector, expectations) |
842 { | 569 { |
843 await timeout(REFRESH_INTERVAL); | 570 testDocument.body.innerHTML = `<div id="parent"> |
844 | 571 <div id="middle"> |
845 expectVisible(test, parent); | 572 <div id="middle1"><div id="inside" class="inside"></div></div> |
846 expectVisible(test, child); | 573 </div> |
847 | 574 <div id="sibling"> |
848 // Load a style sheet that targets the parent element. This should run only | 575 <div id="tohide">to hide \ud83d\ude42!</div> |
849 // the "div:-abp-properties(background-color: rgb(0, 0, 0))" pattern. | 576 </div> |
850 insertStyleRule("#" + parent.id + " {background-color: #000}"); | 577 <div id="sibling2"> |
851 | 578 <div id="sibling21"> |
852 await timeout(REFRESH_INTERVAL); | 579 <div id="sibling211" class="inside">Ad*</div> |
853 | 580 </div> |
854 expectHidden(test, parent); | 581 </div> |
855 expectVisible(test, child); | 582 </div>`; |
856 } | 583 let elems = { |
857 | 584 parent: testDocument.getElementById("parent"), |
858 test.done(); | 585 middle: testDocument.getElementById("middle"), |
859 }; | 586 inside: testDocument.getElementById("inside"), |
860 | 587 sibling: testDocument.getElementById("sibling"), |
861 exports.testPlainAttributeOnDomMutation = async function(test) | 588 sibling2: testDocument.getElementById("sibling2"), |
862 { | 589 toHide: testDocument.getElementById("tohide") |
863 let parent = createElement(); | 590 }; |
864 let child = createElement(parent); | 591 |
865 | 592 if (await applyElemHideEmulation([selector])) |
866 let selectors = [ | 593 compareExpectations(elems, expectations); |
867 "div:-abp-properties(background-color: rgb(0, 0, 0))", | 594 } |
868 "div[data-hide-me]", | 595 |
869 "div:-abp-contains(hide me)", | 596 it("Text", () => |
870 "div:-abp-has(> div.hideMe)" | 597 { |
871 ]; | 598 let expectations = { |
872 | 599 parent: true, |
873 if (await applyElemHideEmulation(test, selectors)) | 600 middle: true, |
874 { | 601 inside: true, |
875 await timeout(REFRESH_INTERVAL); | 602 sibling: false, |
876 | 603 sibling2: true, |
877 expectVisible(test, parent); | 604 toHide: true |
878 expectVisible(test, child); | 605 }; |
879 | 606 runTestPseudoClassContains( |
880 // Set the "data-hide-me" attribute on the child element. | 607 "#parent div:-abp-contains(to hide)", expectations); |
881 // | 608 }); |
882 // Note: Since the "div[data-hide-me]" pattern has already been processed | 609 |
883 // and the selector added to the document's style sheet, this will in fact | 610 it("Regexp", () => |
884 // not do anything at our end, but the browser will just match the selector | 611 { |
885 // and hide the element. | 612 let expectations = { |
886 child.setAttribute("data-hide-me", ""); | 613 parent: true, |
887 | 614 middle: true, |
888 await timeout(REFRESH_INTERVAL); | 615 inside: true, |
889 | 616 sibling: false, |
890 expectVisible(test, parent); | 617 sibling2: true, |
891 expectHidden(test, child); | 618 toHide: true |
892 } | 619 }; |
893 | 620 runTestPseudoClassContains( |
894 test.done(); | 621 "#parent div:-abp-contains(/to\\shide/)", expectations); |
895 }; | 622 }); |
896 | 623 |
897 exports.testPseudoClassContainsOnDomMutation = async function(test) | 624 it("Regexp i flag", () => |
898 { | 625 { |
899 let parent = createElement(); | 626 let expectations = { |
900 let child = createElement(parent); | 627 parent: true, |
901 | 628 middle: true, |
902 let selectors = [ | 629 inside: true, |
903 "div:-abp-properties(background-color: rgb(0, 0, 0))", | 630 sibling: false, |
904 "div[data-hide-me]", | 631 sibling2: true, |
905 "div:-abp-contains(hide me)", | 632 toHide: true |
906 "div:-abp-has(> div.hideMe)" | 633 }; |
907 ]; | 634 runTestPseudoClassContains( |
908 | 635 "#parent div:-abp-contains(/to\\sHide/i)", expectations); |
909 child.innerText = "do nothing"; | 636 }); |
910 | 637 |
911 if (await applyElemHideEmulation(test, selectors)) | 638 it("Regexp u flag", () => |
912 { | 639 { |
913 await timeout(REFRESH_INTERVAL); | 640 let expectations = { |
914 | 641 parent: true, |
915 expectVisible(test, parent); | 642 middle: true, |
916 expectVisible(test, child); | 643 inside: true, |
917 | 644 sibling: false, |
918 // Set the child element's text to "hide me". This should run only the | 645 sibling2: true, |
919 // "div:-abp-contains(hide me)" pattern. | 646 toHide: true |
920 // | 647 }; |
921 // Note: We need to set Node.innerText here in order to trigger the | 648 runTestPseudoClassContains( |
922 // "characterData" DOM mutation on Chromium. If we set Node.textContent | 649 "#parent div:-abp-contains(/to\\shide\\s.!/u)", expectations); |
923 // instead, it triggers the "childList" DOM mutation instead. | 650 }); |
924 child.innerText = "hide me"; | 651 |
925 | 652 it("Wildcard no match", () => |
926 await timeout(REFRESH_INTERVAL); | 653 { |
927 | 654 let expectations = { |
928 expectHidden(test, parent); | 655 parent: true, |
929 expectVisible(test, child); | 656 middle: true, |
930 } | 657 inside: true, |
931 | 658 sibling: true, |
932 test.done(); | 659 sibling2: true, |
933 }; | 660 toHide: true |
934 | 661 }; |
935 exports.testPseudoClassHasOnDomMutation = async function(test) | 662 // this filter shouldn't match anything as "*" has no meaning. |
936 { | 663 runTestPseudoClassContains( |
937 let parent = createElement(); | 664 "#parent div:-abp-contains(to *hide)", expectations); |
938 let child = null; | 665 }); |
939 | 666 |
940 let selectors = [ | 667 it("Wildcard match", () => |
941 "div:-abp-properties(background-color: rgb(0, 0, 0))", | 668 { |
942 "div[data-hide-me]", | 669 let expectations = { |
943 "div:-abp-contains(hide me)", | 670 parent: true, |
944 "div:-abp-has(> div)" | 671 middle: true, |
945 ]; | 672 inside: true, |
946 | 673 sibling: true, |
947 if (await applyElemHideEmulation(test, selectors)) | 674 sibling2: false, |
948 { | 675 toHide: true |
949 await timeout(REFRESH_INTERVAL); | 676 }; |
950 | 677 runTestPseudoClassContains( |
951 expectVisible(test, parent); | 678 "#parent div:-abp-contains(Ad*)", expectations); |
952 | 679 }); |
953 // Add the child element. This should run all the DOM-dependent patterns | 680 }); |
954 // ("div:-abp-contains(hide me)" and "div:-abp-has(> div)"). | 681 |
955 child = createElement(parent); | 682 describe("Has Selector with prop selector", () => |
956 | 683 { |
957 await timeout(REFRESH_INTERVAL); | 684 it("Already present", async() => |
958 | 685 { |
959 expectHidden(test, parent); | 686 let parent = createElementWithStyle("{}"); |
960 expectVisible(test, child); | 687 let child = createElementWithStyle("{background-color: #000}", parent); |
961 } | 688 |
962 | 689 let selectors = ["div:-abp-has(:-abp-properties(background-color: rgb(0,
0, 0)))"]; |
963 test.done(); | 690 |
964 }; | 691 if (await applyElemHideEmulation(selectors)) |
965 | 692 { |
966 exports.testPseudoClassHasWithClassOnDomMutation = async function(test) | 693 expectVisible(child); |
967 { | 694 expectHidden(parent); |
968 let parent = createElement(); | 695 } |
969 let child = createElement(parent); | 696 }); |
970 | 697 |
971 let selectors = [ | 698 it("Dynamically added", async() => |
972 "div:-abp-properties(background-color: rgb(0, 0, 0))", | 699 { |
973 "div[data-hide-me]", | 700 let parent = createElementWithStyle("{}"); |
974 "div:-abp-contains(hide me)", | 701 let child = createElementWithStyle("{}", parent); |
975 "div:-abp-has(> div.hideMe)" | 702 |
976 ]; | 703 let selectors = ["div:-abp-has(:-abp-properties(background-color: rgb(0,
0, 0)))"]; |
977 | 704 |
978 if (await applyElemHideEmulation(test, selectors)) | 705 insertStyleRule("body #" + parent.id + " > div { background-color: #000}
"); |
979 { | 706 |
980 await timeout(REFRESH_INTERVAL); | 707 if (await applyElemHideEmulation(selectors)) |
981 | 708 { |
982 expectVisible(test, parent); | 709 expectVisible(child); |
983 expectVisible(test, child); | 710 expectHidden(parent); |
984 | 711 } |
985 // Set the child element's class to "hideMe". This should run only the | 712 }); |
986 // "div:-abp-has(> div.hideMe)" pattern. | 713 }); |
987 child.className = "hideMe"; | 714 }); |
988 | 715 |
989 await timeout(REFRESH_INTERVAL); | 716 describe("DOM updates", () => |
990 | 717 { |
991 expectHidden(test, parent); | 718 it("Style", async() => |
992 expectVisible(test, child); | 719 { |
993 } | 720 let parent = createElementWithStyle("{}"); |
994 | 721 let child = createElementWithStyle("{}", parent); |
995 test.done(); | 722 |
996 }; | 723 let selectors = ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0
, 0)))"]; |
997 | 724 |
998 exports.testPseudoClassHasWithPseudoClassContainsOnDomMutation = async function(
test) | 725 if (await applyElemHideEmulation(selectors)) |
999 { | 726 { |
1000 let parent = createElement(); | 727 expectVisible(child); |
1001 let child = createElement(parent); | 728 expectVisible(parent); |
1002 | 729 |
1003 let selectors = [ | 730 insertStyleRule("body #" + parent.id + " > div { background-color: #000}
"); |
1004 "div:-abp-properties(background-color: rgb(0, 0, 0))", | 731 await timeout(0); |
1005 "div[data-hide-me]", | 732 |
1006 "div:-abp-contains(hide me)", | 733 expectVisible(child); |
1007 "div:-abp-has(> div:-abp-contains(hide me))" | 734 expectVisible(parent); |
1008 ]; | 735 await timeout(REFRESH_INTERVAL); |
1009 | 736 |
1010 child.innerText = "do nothing"; | 737 expectVisible(child); |
1011 | 738 expectHidden(parent); |
1012 if (await applyElemHideEmulation(test, selectors)) | 739 } |
1013 { | 740 }); |
1014 await timeout(REFRESH_INTERVAL); | 741 |
1015 | 742 it("Content", async() => |
1016 expectVisible(test, parent); | 743 { |
1017 expectVisible(test, child); | 744 let parent = createElementWithStyle("{}"); |
1018 | 745 let child = createElementWithStyle("{}", parent); |
1019 // Set the child element's text to "hide me". This should run only the | 746 |
1020 // "div:-abp-contains(hide me)" and | 747 if (await applyElemHideEmulation(["div > div:-abp-contains(hide me)"])) |
1021 // "div:-abp-has(> div:-abp-contains(hide me))" patterns. | 748 { |
1022 child.innerText = "hide me"; | 749 expectVisible(parent); |
1023 | 750 expectVisible(child); |
1024 await timeout(REFRESH_INTERVAL); | 751 |
1025 | 752 child.textContent = "hide me"; |
1026 // Note: Even though it runs both the :-abp-contains() patterns, it only | 753 await timeout(0); |
1027 // hides the parent element because of revision d7d51d29aa34. | 754 |
1028 expectHidden(test, parent); | 755 expectVisible(parent); |
1029 expectVisible(test, child); | 756 expectVisible(child); |
1030 } | 757 await timeout(REFRESH_INTERVAL); |
1031 | 758 |
1032 test.done(); | 759 expectVisible(parent); |
1033 }; | 760 expectHidden(child); |
1034 | 761 } |
1035 exports.testOnlyRelevantElementsProcessed = async function(test) | 762 }); |
1036 { | 763 |
1037 // <body> | 764 it("New element", async() => |
1038 // <div id="n1"> | 765 { |
1039 // <p id="n1_1"></p> | 766 let parent = createElementWithStyle("{}"); |
1040 // <p id="n1_2"></p> | 767 let child = createElementWithStyle("{ background-color: #000}", parent); |
1041 // <p id="n1_4">Hello</p> | 768 let sibling; |
1042 // </div> | 769 let child2; |
1043 // <div id="n2"> | 770 |
1044 // <p id="n2_1"></p> | 771 let selectors = ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0
, 0)))"]; |
1045 // <p id="n2_2"></p> | 772 |
1046 // <p id="n2_4">Hello</p> | 773 if (await applyElemHideEmulation(selectors)) |
1047 // </div> | 774 { |
1048 // <div id="n3"> | 775 expectHidden(parent); |
1049 // <p id="n3_1"></p> | 776 expectVisible(child); |
1050 // <p id="n3_2"></p> | 777 |
1051 // <p id="n3_4">Hello</p> | 778 sibling = createElementWithStyle("{}"); |
1052 // </div> | 779 await timeout(0); |
1053 // <div id="n4"> | 780 |
1054 // <p id="n4_1"></p> | 781 expectHidden(parent); |
1055 // <p id="n4_2"></p> | 782 expectVisible(child); |
1056 // <p id="n4_4">Hello</p> | 783 expectVisible(sibling); |
1057 // </div> | 784 |
1058 // </body> | 785 await timeout(REFRESH_INTERVAL); |
1059 for (let i of [1, 2, 3, 4]) | 786 |
1060 { | 787 expectHidden(parent); |
1061 let n = createElement(null, "div", `n${i}`); | 788 expectVisible(child); |
1062 for (let [j, text] of [[1], [2], [4, "Hello"]]) | 789 expectVisible(sibling); |
1063 createElement(n, "p", `n${i}_${j}`, text); | 790 |
1064 } | 791 child2 = createElementWithStyle("{ background-color: #000}", |
1065 | 792 sibling); |
1066 let selectors = [ | 793 await timeout(0); |
1067 "p:-abp-contains(Hello)", | 794 |
1068 "div:-abp-contains(Try me!)", | 795 expectVisible(child2); |
1069 "div:-abp-has(p:-abp-contains(This is good))" | 796 await timeout(REFRESH_INTERVAL); |
1070 ]; | 797 |
1071 | 798 expectHidden(parent); |
1072 if (await applyElemHideEmulation(test, selectors)) | 799 expectVisible(child); |
1073 { | 800 expectHidden(sibling); |
1074 await timeout(REFRESH_INTERVAL); | 801 expectVisible(child2); |
1075 | 802 } |
1076 // This is only a sanity check to make sure everything else is working | 803 }); |
1077 // before we do the actual test. | 804 }); |
| 805 |
| 806 it("Pseudo class properties on stylesheet load", async() => |
| 807 { |
| 808 let parent = createElement(); |
| 809 let child = createElement(parent); |
| 810 |
| 811 let selectors = [ |
| 812 "div:-abp-properties(background-color: rgb(0, 0, 0))", |
| 813 "div:-abp-contains(hide me)", |
| 814 "div:-abp-has(> div.hideMe)" |
| 815 ]; |
| 816 |
| 817 if (await applyElemHideEmulation(selectors)) |
| 818 { |
| 819 await timeout(REFRESH_INTERVAL); |
| 820 |
| 821 expectVisible(parent); |
| 822 expectVisible(child); |
| 823 |
| 824 // Load a style sheet that targets the parent element. This should run onl
y |
| 825 // the "div:-abp-properties(background-color: rgb(0, 0, 0))" pattern. |
| 826 insertStyleRule("#" + parent.id + " {background-color: #000}"); |
| 827 |
| 828 await timeout(REFRESH_INTERVAL); |
| 829 |
| 830 expectHidden(parent); |
| 831 expectVisible(child); |
| 832 } |
| 833 }); |
| 834 |
| 835 describe("On DOM mutation", () => |
| 836 { |
| 837 it("Plain attributes", async() => |
| 838 { |
| 839 let parent = createElement(); |
| 840 let child = createElement(parent); |
| 841 |
| 842 let selectors = [ |
| 843 "div:-abp-properties(background-color: rgb(0, 0, 0))", |
| 844 "div[data-hide-me]", |
| 845 "div:-abp-contains(hide me)", |
| 846 "div:-abp-has(> div.hideMe)" |
| 847 ]; |
| 848 |
| 849 if (await applyElemHideEmulation(selectors)) |
| 850 { |
| 851 await timeout(REFRESH_INTERVAL); |
| 852 |
| 853 expectVisible(parent); |
| 854 expectVisible(child); |
| 855 |
| 856 // Set the "data-hide-me" attribute on the child element. |
| 857 // |
| 858 // Note: Since the "div[data-hide-me]" pattern has already been processe
d |
| 859 // and the selector added to the document's style sheet, this will in fa
ct |
| 860 // not do anything at our end, but the browser will just match the selec
tor |
| 861 // and hide the element. |
| 862 child.setAttribute("data-hide-me", ""); |
| 863 |
| 864 await timeout(REFRESH_INTERVAL); |
| 865 |
| 866 expectVisible(parent); |
| 867 expectHidden(child); |
| 868 } |
| 869 }); |
| 870 |
| 871 it("Pseudo class contains", async() => |
| 872 { |
| 873 let parent = createElement(); |
| 874 let child = createElement(parent); |
| 875 |
| 876 let selectors = [ |
| 877 "div:-abp-properties(background-color: rgb(0, 0, 0))", |
| 878 "div[data-hide-me]", |
| 879 "div:-abp-contains(hide me)", |
| 880 "div:-abp-has(> div.hideMe)" |
| 881 ]; |
| 882 |
| 883 child.innerText = "do nothing"; |
| 884 |
| 885 if (await applyElemHideEmulation(selectors)) |
| 886 { |
| 887 await timeout(REFRESH_INTERVAL); |
| 888 |
| 889 expectVisible(parent); |
| 890 expectVisible(child); |
| 891 |
| 892 // Set the child element's text to "hide me". This should run only the |
| 893 // "div:-abp-contains(hide me)" pattern. |
| 894 // |
| 895 // Note: We need to set Node.innerText here in order to trigger the |
| 896 // "characterData" DOM mutation on Chromium. If we set Node.textContent |
| 897 // instead, it triggers the "childList" DOM mutation instead. |
| 898 child.innerText = "hide me"; |
| 899 |
| 900 await timeout(REFRESH_INTERVAL); |
| 901 |
| 902 expectHidden(parent); |
| 903 expectVisible(child); |
| 904 } |
| 905 }); |
| 906 |
| 907 it("Pseudo class has", async() => |
| 908 { |
| 909 let parent = createElement(); |
| 910 let child = null; |
| 911 |
| 912 let selectors = [ |
| 913 "div:-abp-properties(background-color: rgb(0, 0, 0))", |
| 914 "div[data-hide-me]", |
| 915 "div:-abp-contains(hide me)", |
| 916 "div:-abp-has(> div)" |
| 917 ]; |
| 918 |
| 919 if (await applyElemHideEmulation(selectors)) |
| 920 { |
| 921 await timeout(REFRESH_INTERVAL); |
| 922 |
| 923 expectVisible(parent); |
| 924 |
| 925 // Add the child element. This should run all the DOM-dependent patterns |
| 926 // ("div:-abp-contains(hide me)" and "div:-abp-has(> div)"). |
| 927 child = createElement(parent); |
| 928 |
| 929 await timeout(REFRESH_INTERVAL); |
| 930 |
| 931 expectHidden(parent); |
| 932 expectVisible(child); |
| 933 } |
| 934 }); |
| 935 |
| 936 it("Pseudo class has", async() => |
| 937 { |
| 938 let parent = createElement(); |
| 939 let child = createElement(parent); |
| 940 |
| 941 let selectors = [ |
| 942 "div:-abp-properties(background-color: rgb(0, 0, 0))", |
| 943 "div[data-hide-me]", |
| 944 "div:-abp-contains(hide me)", |
| 945 "div:-abp-has(> div.hideMe)" |
| 946 ]; |
| 947 |
| 948 if (await applyElemHideEmulation(selectors)) |
| 949 { |
| 950 await timeout(REFRESH_INTERVAL); |
| 951 |
| 952 expectVisible(parent); |
| 953 expectVisible(child); |
| 954 |
| 955 // Set the child element's class to "hideMe". This should run only the |
| 956 // "div:-abp-has(> div.hideMe)" pattern. |
| 957 child.className = "hideMe"; |
| 958 |
| 959 await timeout(REFRESH_INTERVAL); |
| 960 |
| 961 expectHidden(parent); |
| 962 expectVisible(child); |
| 963 } |
| 964 }); |
| 965 |
| 966 it("Pseudo class has with pseudo class contains", async() => |
| 967 { |
| 968 let parent = createElement(); |
| 969 let child = createElement(parent); |
| 970 |
| 971 let selectors = [ |
| 972 "div:-abp-properties(background-color: rgb(0, 0, 0))", |
| 973 "div[data-hide-me]", |
| 974 "div:-abp-contains(hide me)", |
| 975 "div:-abp-has(> div:-abp-contains(hide me))" |
| 976 ]; |
| 977 |
| 978 child.innerText = "do nothing"; |
| 979 |
| 980 if (await applyElemHideEmulation(selectors)) |
| 981 { |
| 982 await timeout(REFRESH_INTERVAL); |
| 983 |
| 984 expectVisible(parent); |
| 985 expectVisible(child); |
| 986 |
| 987 // Set the child element's text to "hide me". This should run only the |
| 988 // "div:-abp-contains(hide me)" and |
| 989 // "div:-abp-has(> div:-abp-contains(hide me))" patterns. |
| 990 child.innerText = "hide me"; |
| 991 |
| 992 await timeout(REFRESH_INTERVAL); |
| 993 |
| 994 // Note: Even though it runs both the :-abp-contains() patterns, it only |
| 995 // hides the parent element because of revision d7d51d29aa34. |
| 996 expectHidden(parent); |
| 997 expectVisible(child); |
| 998 } |
| 999 }); |
| 1000 }); |
| 1001 |
| 1002 it("Only relevant elements are processed", async() => |
| 1003 { |
| 1004 // <body> |
| 1005 // <div id="n1"> |
| 1006 // <p id="n1_1"></p> |
| 1007 // <p id="n1_2"></p> |
| 1008 // <p id="n1_4">Hello</p> |
| 1009 // </div> |
| 1010 // <div id="n2"> |
| 1011 // <p id="n2_1"></p> |
| 1012 // <p id="n2_2"></p> |
| 1013 // <p id="n2_4">Hello</p> |
| 1014 // </div> |
| 1015 // <div id="n3"> |
| 1016 // <p id="n3_1"></p> |
| 1017 // <p id="n3_2"></p> |
| 1018 // <p id="n3_4">Hello</p> |
| 1019 // </div> |
| 1020 // <div id="n4"> |
| 1021 // <p id="n4_1"></p> |
| 1022 // <p id="n4_2"></p> |
| 1023 // <p id="n4_4">Hello</p> |
| 1024 // </div> |
| 1025 // </body> |
1078 for (let i of [1, 2, 3, 4]) | 1026 for (let i of [1, 2, 3, 4]) |
1079 { | 1027 { |
1080 for (let j of [1, 2, 4]) | 1028 let n = createElement(null, "div", `n${i}`); |
1081 { | 1029 for (let [j, text] of [[1], [2], [4, "Hello"]]) |
1082 let id = `n${i}_${j}`; | 1030 createElement(n, "p", `n${i}_${j}`, text); |
1083 if (j == 4) | 1031 } |
1084 expectHidden(test, testDocument.getElementById(id), id); | 1032 |
| 1033 let selectors = [ |
| 1034 "p:-abp-contains(Hello)", |
| 1035 "div:-abp-contains(Try me!)", |
| 1036 "div:-abp-has(p:-abp-contains(This is good))" |
| 1037 ]; |
| 1038 |
| 1039 if (await applyElemHideEmulation(selectors)) |
| 1040 { |
| 1041 await timeout(REFRESH_INTERVAL); |
| 1042 |
| 1043 // This is only a sanity check to make sure everything else is working |
| 1044 // before we do the actual test. |
| 1045 for (let i of [1, 2, 3, 4]) |
| 1046 { |
| 1047 for (let j of [1, 2, 4]) |
| 1048 { |
| 1049 let id = `n${i}_${j}`; |
| 1050 if (j == 4) |
| 1051 expectHidden(testDocument.getElementById(id), id); |
| 1052 else |
| 1053 expectVisible(testDocument.getElementById(id), id); |
| 1054 } |
| 1055 } |
| 1056 |
| 1057 // All <div> and <p> elements should be processed initially. |
| 1058 for (let element of [...testDocument.getElementsByTagName("div"), |
| 1059 ...testDocument.getElementsByTagName("p")]) |
| 1060 { |
| 1061 expectProcessed(element, element.id); |
| 1062 } |
| 1063 |
| 1064 // Modify the text in <p id="n4_1"> |
| 1065 testDocument.getElementById("n4_1").innerText = "Try me!"; |
| 1066 |
| 1067 await timeout(REFRESH_INTERVAL); |
| 1068 |
| 1069 // When an element's text is modified, only the element or one of its |
| 1070 // ancestors matching any selector is processed for :-abp-has() and |
| 1071 // :-abp-contains() |
| 1072 for (let element of [...testDocument.getElementsByTagName("div"), |
| 1073 ...testDocument.getElementsByTagName("p")]) |
| 1074 { |
| 1075 if (element.id == "n4" || element.id == "n4_1") |
| 1076 expectProcessed(element, element.id); |
1085 else | 1077 else |
1086 expectVisible(test, testDocument.getElementById(id), id); | 1078 expectNotProcessed(element, element.id); |
| 1079 } |
| 1080 |
| 1081 // Create a new <p id="n2_3"> element with no text. |
| 1082 createElement(testDocument.getElementById("n2"), "p", "n2_3"); |
| 1083 |
| 1084 await timeout(REFRESH_INTERVAL); |
| 1085 |
| 1086 // When a new element is added, only the element or one of its ancestors |
| 1087 // matching any selector is processed for :-abp-has() and :-abp-contains() |
| 1088 for (let element of [...testDocument.getElementsByTagName("div"), |
| 1089 ...testDocument.getElementsByTagName("p")]) |
| 1090 { |
| 1091 if (element.id == "n2" || element.id == "n2_3") |
| 1092 expectProcessed(element, element.id); |
| 1093 else |
| 1094 expectNotProcessed(element, element.id); |
1087 } | 1095 } |
1088 } | 1096 } |
1089 | 1097 }); |
1090 // All <div> and <p> elements should be processed initially. | 1098 }); |
1091 for (let element of [...testDocument.getElementsByTagName("div"), | |
1092 ...testDocument.getElementsByTagName("p")]) | |
1093 { | |
1094 expectProcessed(test, element, element.id); | |
1095 } | |
1096 | |
1097 // Modify the text in <p id="n4_1"> | |
1098 testDocument.getElementById("n4_1").innerText = "Try me!"; | |
1099 | |
1100 await timeout(REFRESH_INTERVAL); | |
1101 | |
1102 // When an element's text is modified, only the element or one of its | |
1103 // ancestors matching any selector is processed for :-abp-has() and | |
1104 // :-abp-contains() | |
1105 for (let element of [...testDocument.getElementsByTagName("div"), | |
1106 ...testDocument.getElementsByTagName("p")]) | |
1107 { | |
1108 if (element.id == "n4" || element.id == "n4_1") | |
1109 expectProcessed(test, element, element.id); | |
1110 else | |
1111 expectNotProcessed(test, element, element.id); | |
1112 } | |
1113 | |
1114 // Create a new <p id="n2_3"> element with no text. | |
1115 createElement(testDocument.getElementById("n2"), "p", "n2_3"); | |
1116 | |
1117 await timeout(REFRESH_INTERVAL); | |
1118 | |
1119 // When a new element is added, only the element or one of its ancestors | |
1120 // matching any selector is processed for :-abp-has() and :-abp-contains() | |
1121 for (let element of [...testDocument.getElementsByTagName("div"), | |
1122 ...testDocument.getElementsByTagName("p")]) | |
1123 { | |
1124 if (element.id == "n2" || element.id == "n2_3") | |
1125 expectProcessed(test, element, element.id); | |
1126 else | |
1127 expectNotProcessed(test, element, element.id); | |
1128 } | |
1129 } | |
1130 | |
1131 test.done(); | |
1132 }; | |
OLD | NEW |