Left: | ||
Right: |
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 "use strict"; | 18 "use strict"; |
19 | 19 |
20 const {ElemHideEmulation} = require("../../lib/content/elemHideEmulation"); | 20 const {ElemHideEmulation} = require("../../lib/content/elemHideEmulation"); |
21 | 21 |
22 exports.tearDown = function(callback) | 22 const REFRESH_INTERVAL = 200; |
23 | |
24 let testDocument = null; | |
25 | |
26 exports.setUp = function(callback) | |
23 { | 27 { |
24 let styleElements = document.head.getElementsByTagName("style"); | 28 let iframe = document.createElement("iframe"); |
25 while (styleElements.length) | 29 document.body.appendChild(iframe); |
26 styleElements[0].parentNode.removeChild(styleElements[0]); | 30 testDocument = iframe.contentDocument; |
27 | |
28 let child; | |
29 while (child = document.body.firstChild) | |
30 child.parentNode.removeChild(child); | |
31 | 31 |
32 callback(); | 32 callback(); |
33 }; | 33 }; |
34 | 34 |
35 exports.tearDown = function(callback) | |
36 { | |
37 let iframe = testDocument.defaultView.frameElement; | |
38 iframe.parentNode.removeChild(iframe); | |
39 testDocument = null; | |
40 | |
41 callback(); | |
42 }; | |
43 | |
44 function timeout(delay) | |
45 { | |
46 return new Promise((resolve, reject) => | |
47 { | |
48 window.setTimeout(resolve, delay); | |
49 }); | |
50 } | |
51 | |
35 function unexpectedError(error) | 52 function unexpectedError(error) |
36 { | 53 { |
37 console.error(error); | 54 console.error(error); |
38 this.ok(false, "Unexpected error: " + error); | 55 this.ok(false, "Unexpected error: " + error); |
39 } | 56 } |
40 | 57 |
41 function expectHidden(test, element) | 58 function expectHidden(test, element) |
42 { | 59 { |
43 test.equal(window.getComputedStyle(element).display, "none", | 60 test.equal(window.getComputedStyle(element).display, "none", |
44 "The element's display property should be set to 'none'"); | 61 "The element's display property should be set to 'none'"); |
45 } | 62 } |
46 | 63 |
47 function expectVisible(test, element) | 64 function expectVisible(test, element) |
48 { | 65 { |
49 test.notEqual(window.getComputedStyle(element).display, "none", | 66 test.notEqual(window.getComputedStyle(element).display, "none", |
50 "The element's display property should not be set to 'none'"); | 67 "The element's display property should not be set to 'none'"); |
51 } | 68 } |
52 | 69 |
53 function findUniqueId() | 70 function findUniqueId() |
54 { | 71 { |
55 let id = "elemHideEmulationTest-" + Math.floor(Math.random() * 10000); | 72 let id = "elemHideEmulationTest-" + Math.floor(Math.random() * 10000); |
56 if (!document.getElementById(id)) | 73 if (!testDocument.getElementById(id)) |
57 return id; | 74 return id; |
58 return findUniqueId(); | 75 return findUniqueId(); |
59 } | 76 } |
60 | 77 |
61 function insertStyleRule(rule) | 78 function insertStyleRule(rule) |
62 { | 79 { |
63 let styleElement; | 80 let styleElement; |
64 let styleElements = document.head.getElementsByTagName("style"); | 81 let styleElements = testDocument.head.getElementsByTagName("style"); |
65 if (styleElements.length) | 82 if (styleElements.length) |
66 styleElement = styleElements[0]; | 83 styleElement = styleElements[0]; |
67 else | 84 else |
68 { | 85 { |
69 styleElement = document.createElement("style"); | 86 styleElement = testDocument.createElement("style"); |
70 document.head.appendChild(styleElement); | 87 testDocument.head.appendChild(styleElement); |
71 } | 88 } |
72 styleElement.sheet.insertRule(rule, styleElement.sheet.cssRules.length); | 89 styleElement.sheet.insertRule(rule, styleElement.sheet.cssRules.length); |
73 } | 90 } |
74 | 91 |
75 // Insert a <div> with a unique id and a CSS rule | 92 // Insert a <div> with a unique id and a CSS rule |
76 // for the the selector matching the id. | 93 // for the the selector matching the id. |
77 function createElementWithStyle(styleBlock, parent) | 94 function createElementWithStyle(styleBlock, parent) |
78 { | 95 { |
79 let element = document.createElement("div"); | 96 let element = testDocument.createElement("div"); |
80 element.id = findUniqueId(); | 97 element.id = findUniqueId(); |
81 if (!parent) | 98 if (!parent) |
82 document.body.appendChild(element); | 99 testDocument.body.appendChild(element); |
83 else | 100 else |
84 parent.appendChild(element); | 101 parent.appendChild(element); |
85 insertStyleRule("#" + element.id + " " + styleBlock); | 102 insertStyleRule("#" + element.id + " " + styleBlock); |
86 return element; | 103 return element; |
87 } | 104 } |
88 | 105 |
89 // Create a new ElemHideEmulation instance with @selectors. | 106 // Create a new ElemHideEmulation instance with @selectors. |
90 function applyElemHideEmulation(selectors) | 107 function applyElemHideEmulation(selectors) |
91 { | 108 { |
92 return Promise.resolve().then(() => | 109 return Promise.resolve().then(() => |
93 { | 110 { |
94 let elemHideEmulation = new ElemHideEmulation( | 111 let elemHideEmulation = new ElemHideEmulation( |
95 window, | 112 testDocument.defaultView, |
96 callback => | 113 callback => |
97 { | 114 { |
98 let patterns = []; | 115 let patterns = []; |
99 selectors.forEach(selector => | 116 selectors.forEach(selector => |
100 { | 117 { |
101 patterns.push({selector}); | 118 patterns.push({selector}); |
102 }); | 119 }); |
103 callback(patterns); | 120 callback(patterns); |
104 }, | 121 }, |
105 newSelectors => | 122 newSelectors => |
106 { | 123 { |
107 if (!newSelectors.length) | 124 if (!newSelectors.length) |
108 return; | 125 return; |
109 let selector = newSelectors.join(", "); | 126 let selector = newSelectors.join(", "); |
110 insertStyleRule(selector + "{display: none !important;}"); | 127 insertStyleRule(selector + "{display: none !important;}"); |
111 }, | 128 }, |
112 elems => | 129 elems => |
113 { | 130 { |
114 for (let elem of elems) | 131 for (let elem of elems) |
115 elem.style.display = "none"; | 132 elem.style.display = "none"; |
116 } | 133 } |
117 ); | 134 ); |
118 | 135 |
136 elemHideEmulation.MIN_INVOCATION_INTERVAL = REFRESH_INTERVAL / 2; | |
119 elemHideEmulation.apply(); | 137 elemHideEmulation.apply(); |
120 return elemHideEmulation; | 138 return elemHideEmulation; |
121 }); | 139 }); |
122 } | 140 } |
123 | 141 |
124 exports.testVerbatimPropertySelector = function(test) | 142 exports.testVerbatimPropertySelector = function(test) |
125 { | 143 { |
126 let toHide = createElementWithStyle("{background-color: #000}"); | 144 let toHide = createElementWithStyle("{background-color: #000}"); |
127 applyElemHideEmulation( | 145 applyElemHideEmulation( |
128 [":-abp-properties(background-color: rgb(0, 0, 0))"] | 146 [":-abp-properties(background-color: rgb(0, 0, 0))"] |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
232 | 250 |
233 exports.testDynamicallyChangedProperty = function(test) | 251 exports.testDynamicallyChangedProperty = function(test) |
234 { | 252 { |
235 let toHide = createElementWithStyle("{}"); | 253 let toHide = createElementWithStyle("{}"); |
236 applyElemHideEmulation( | 254 applyElemHideEmulation( |
237 [":-abp-properties(background-color: rgb(0, 0, 0))"] | 255 [":-abp-properties(background-color: rgb(0, 0, 0))"] |
238 ).then(() => | 256 ).then(() => |
239 { | 257 { |
240 expectVisible(test, toHide); | 258 expectVisible(test, toHide); |
241 insertStyleRule("#" + toHide.id + " {background-color: #000}"); | 259 insertStyleRule("#" + toHide.id + " {background-color: #000}"); |
242 return new Promise((resolve, reject) => | 260 |
243 { | 261 return timeout(0); |
244 // Re-evaluation will only happen after a few seconds | 262 }).then(() => |
245 expectVisible(test, toHide); | 263 { |
246 window.setTimeout(() => | 264 // Re-evaluation will only happen after a delay |
247 { | 265 expectVisible(test, toHide); |
248 expectHidden(test, toHide); | 266 return timeout(REFRESH_INTERVAL); |
249 resolve(); | 267 }).then(() => |
250 }, 4000); | 268 { |
251 }); | 269 expectHidden(test, toHide); |
252 }).catch(unexpectedError.bind(test)).then(() => test.done()); | 270 }).catch(unexpectedError.bind(test)).then(() => test.done()); |
253 }; | 271 }; |
254 | 272 |
255 exports.testPseudoClassWithPropBeforeSelector = function(test) | 273 exports.testPseudoClassWithPropBeforeSelector = function(test) |
256 { | 274 { |
257 let parent = createElementWithStyle("{}"); | 275 let parent = createElementWithStyle("{}"); |
258 let child = createElementWithStyle("{background-color: #000}", parent); | 276 let child = createElementWithStyle("{background-color: #000}", parent); |
259 insertStyleRule(`#${child.id}::before {content: "publicite"}`); | 277 insertStyleRule(`#${child.id}::before {content: "publicite"}`); |
260 | 278 |
261 applyElemHideEmulation( | 279 applyElemHideEmulation( |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
339 { | 357 { |
340 expectVisible(test, parent); | 358 expectVisible(test, parent); |
341 expectVisible(test, middle); | 359 expectVisible(test, middle); |
342 expectVisible(test, sibling); | 360 expectVisible(test, sibling); |
343 expectHidden(test, toHide); | 361 expectHidden(test, toHide); |
344 }).catch(unexpectedError.bind(test)).then(() => test.done()); | 362 }).catch(unexpectedError.bind(test)).then(() => test.done()); |
345 }; | 363 }; |
346 | 364 |
347 function runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling(test, selector , expectations) | 365 function runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling(test, selector , expectations) |
348 { | 366 { |
349 document.body.innerHTML = `<div id="parent"> | 367 testDocument.body.innerHTML = `<div id="parent"> |
350 <div id="middle"> | 368 <div id="middle"> |
351 <div id="middle1"><div id="inside" class="inside"></div></div> | 369 <div id="middle1"><div id="inside" class="inside"></div></div> |
352 </div> | 370 </div> |
353 <div id="sibling"> | 371 <div id="sibling"> |
354 <div id="tohide">to hide</div> | 372 <div id="tohide">to hide</div> |
355 </div> | 373 </div> |
356 <div id="sibling2"> | 374 <div id="sibling2"> |
357 <div id="sibling21"><div id="sibling211" class="inside"></div></div> | 375 <div id="sibling21"><div id="sibling211" class="inside"></div></div> |
358 </div> | 376 </div> |
359 </div>`; | 377 </div>`; |
360 let elems = { | 378 let elems = { |
361 parent: document.getElementById("parent"), | 379 parent: testDocument.getElementById("parent"), |
362 middle: document.getElementById("middle"), | 380 middle: testDocument.getElementById("middle"), |
363 inside: document.getElementById("inside"), | 381 inside: testDocument.getElementById("inside"), |
364 sibling: document.getElementById("sibling"), | 382 sibling: testDocument.getElementById("sibling"), |
365 sibling2: document.getElementById("sibling2"), | 383 sibling2: testDocument.getElementById("sibling2"), |
366 toHide: document.getElementById("tohide") | 384 toHide: testDocument.getElementById("tohide") |
367 }; | 385 }; |
368 | 386 |
369 insertStyleRule(".inside {}"); | 387 insertStyleRule(".inside {}"); |
370 | 388 |
371 applyElemHideEmulation( | 389 applyElemHideEmulation( |
372 [selector] | 390 [selector] |
373 ).then(() => | 391 ).then(() => |
374 { | 392 { |
375 for (let elem in expectations) | 393 for (let elem in expectations) |
376 if (elems[elem]) | 394 if (elems[elem]) |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
420 sibling: true, | 438 sibling: true, |
421 sibling2: true, | 439 sibling2: true, |
422 toHide: true | 440 toHide: true |
423 }; | 441 }; |
424 runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling( | 442 runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling( |
425 test, "div:-abp-has(> body div.inside) + div > div", expectations); | 443 test, "div:-abp-has(> body div.inside) + div > div", expectations); |
426 }; | 444 }; |
427 | 445 |
428 exports.testPseudoClassContains = function(test) | 446 exports.testPseudoClassContains = function(test) |
429 { | 447 { |
430 document.body.innerHTML = `<div id="parent"> | 448 testDocument.body.innerHTML = `<div id="parent"> |
431 <div id="middle"> | 449 <div id="middle"> |
432 <div id="middle1"><div id="inside" class="inside"></div></div> | 450 <div id="middle1"><div id="inside" class="inside"></div></div> |
433 </div> | 451 </div> |
434 <div id="sibling"> | 452 <div id="sibling"> |
435 <div id="tohide">to hide</div> | 453 <div id="tohide">to hide</div> |
436 </div> | 454 </div> |
437 <div id="sibling2"> | 455 <div id="sibling2"> |
438 <div id="sibling21"><div id="sibling211" class="inside"></div></div> | 456 <div id="sibling21"><div id="sibling211" class="inside"></div></div> |
439 </div> | 457 </div> |
440 </div>`; | 458 </div>`; |
441 let parent = document.getElementById("parent"); | 459 let parent = testDocument.getElementById("parent"); |
442 let middle = document.getElementById("middle"); | 460 let middle = testDocument.getElementById("middle"); |
443 let inside = document.getElementById("inside"); | 461 let inside = testDocument.getElementById("inside"); |
444 let sibling = document.getElementById("sibling"); | 462 let sibling = testDocument.getElementById("sibling"); |
445 let sibling2 = document.getElementById("sibling2"); | 463 let sibling2 = testDocument.getElementById("sibling2"); |
446 let toHide = document.getElementById("tohide"); | 464 let toHide = testDocument.getElementById("tohide"); |
447 | 465 |
448 applyElemHideEmulation( | 466 applyElemHideEmulation( |
449 ["#parent div:-abp-contains(to hide)"] | 467 ["#parent div:-abp-contains(to hide)"] |
450 ).then(() => | 468 ).then(() => |
451 { | 469 { |
452 expectVisible(test, parent); | 470 expectVisible(test, parent); |
453 expectVisible(test, middle); | 471 expectVisible(test, middle); |
454 expectVisible(test, inside); | 472 expectVisible(test, inside); |
455 expectHidden(test, sibling); | 473 expectHidden(test, sibling); |
456 expectVisible(test, sibling2); | 474 expectVisible(test, sibling2); |
(...skipping 20 matching lines...) Expand all Loading... | |
477 let child = createElementWithStyle("{}", parent); | 495 let child = createElementWithStyle("{}", parent); |
478 insertStyleRule("body #" + parent.id + " > div { background-color: #000}"); | 496 insertStyleRule("body #" + parent.id + " > div { background-color: #000}"); |
479 applyElemHideEmulation( | 497 applyElemHideEmulation( |
480 ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0, 0)))"] | 498 ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0, 0)))"] |
481 ).then(() => | 499 ).then(() => |
482 { | 500 { |
483 expectVisible(test, child); | 501 expectVisible(test, child); |
484 expectHidden(test, parent); | 502 expectHidden(test, parent); |
485 }).catch(unexpectedError.bind(test)).then(() => test.done()); | 503 }).catch(unexpectedError.bind(test)).then(() => test.done()); |
486 }; | 504 }; |
505 | |
506 exports.testDomUpdatesStyle = function(test) | |
507 { | |
508 let parent = createElementWithStyle("{}"); | |
509 let child = createElementWithStyle("{}", parent); | |
510 applyElemHideEmulation( | |
511 ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0, 0)))"] | |
512 ).then(() => | |
513 { | |
514 expectVisible(test, child); | |
515 expectVisible(test, parent); | |
516 | |
517 insertStyleRule("body #" + parent.id + " > div { background-color: #000}"); | |
Wladimir Palant
2017/08/25 20:57:41
`return timeout(0)` before retesting state?
hub
2017/08/26 01:45:07
Done.
| |
518 | |
519 expectVisible(test, child); | |
520 expectVisible(test, parent); | |
521 return timeout(REFRESH_INTERVAL); | |
522 }).then(() => | |
523 { | |
524 expectVisible(test, child); | |
525 expectHidden(test, parent); | |
526 }).catch(unexpectedError.bind(test)).then(() => test.done()); | |
527 }; | |
528 | |
529 exports.testDomUpdatesContent = function(test) | |
530 { | |
531 let parent = createElementWithStyle("{}"); | |
532 let child = createElementWithStyle("{}", parent); | |
533 applyElemHideEmulation( | |
534 ["div > div:-abp-contains(hide me)"] | |
535 ).then(() => | |
536 { | |
537 expectVisible(test, parent); | |
538 expectVisible(test, child); | |
539 | |
540 child.textContent = "hide me"; | |
Wladimir Palant
2017/08/25 20:57:41
`return timeout(0)` before retesting state?
hub
2017/08/26 01:45:07
Done.
| |
541 | |
542 expectVisible(test, parent); | |
543 expectVisible(test, child); | |
544 return timeout(REFRESH_INTERVAL); | |
545 }).then(() => | |
546 { | |
547 expectVisible(test, parent); | |
548 expectHidden(test, child); | |
549 }).catch(unexpectedError.bind(test)).then(() => test.done()); | |
550 }; | |
551 | |
552 exports.testDomUpdatesNewElement = function(test) | |
553 { | |
554 let parent = createElementWithStyle("{}"); | |
555 let child = createElementWithStyle("{ background-color: #000}", parent); | |
556 let sibling; | |
557 let child2; | |
558 applyElemHideEmulation( | |
559 ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0, 0)))"] | |
560 ).then(() => | |
561 { | |
562 expectHidden(test, parent); | |
563 expectVisible(test, child); | |
564 | |
565 sibling = createElementWithStyle("{}"); | |
Wladimir Palant
2017/08/25 20:57:41
`return timeout(0)` before retesting state?
hub
2017/08/26 01:45:06
Done.
| |
566 expectHidden(test, parent); | |
567 expectVisible(test, child); | |
568 expectVisible(test, sibling); | |
569 | |
570 return timeout(REFRESH_INTERVAL); | |
571 }).then(() => | |
572 { | |
573 expectHidden(test, parent); | |
574 expectVisible(test, child); | |
575 expectVisible(test, sibling); | |
576 | |
577 child2 = createElementWithStyle("{ background-color: #000}", | |
578 sibling); | |
Wladimir Palant
2017/08/25 20:57:41
`return timeout(0)` before retesting state?
hub
2017/08/26 01:45:06
Done.
| |
579 expectVisible(test, child2); | |
580 return timeout(REFRESH_INTERVAL); | |
581 }).then(() => | |
582 { | |
583 expectHidden(test, parent); | |
584 expectVisible(test, child); | |
585 expectHidden(test, sibling); | |
586 expectVisible(test, child2); | |
587 }).catch(unexpectedError.bind(test)).then(() => test.done()); | |
588 }; | |
OLD | NEW |