LEFT | RIGHT |
(no file at all) | |
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 const REFRESH_INTERVAL = 200; |
| 23 |
| 24 let testDocument = null; |
| 25 |
| 26 exports.setUp = function(callback) |
| 27 { |
| 28 let iframe = document.createElement("iframe"); |
| 29 document.body.appendChild(iframe); |
| 30 testDocument = iframe.contentDocument; |
| 31 |
| 32 callback(); |
| 33 }; |
| 34 |
22 exports.tearDown = function(callback) | 35 exports.tearDown = function(callback) |
23 { | 36 { |
24 let styleElements = document.head.getElementsByTagName("style"); | 37 let iframe = testDocument.defaultView.frameElement; |
25 while (styleElements.length) | 38 iframe.parentNode.removeChild(iframe); |
26 styleElements[0].parentNode.removeChild(styleElements[0]); | 39 testDocument = null; |
27 | |
28 let child; | |
29 while (child = document.body.firstChild) | |
30 child.parentNode.removeChild(child); | |
31 | 40 |
32 callback(); | 41 callback(); |
33 }; | 42 }; |
| 43 |
| 44 function timeout(delay) |
| 45 { |
| 46 return new Promise((resolve, reject) => |
| 47 { |
| 48 window.setTimeout(resolve, delay); |
| 49 }); |
| 50 } |
34 | 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}"); |
| 518 return timeout(0); |
| 519 }).then(() => |
| 520 { |
| 521 expectVisible(test, child); |
| 522 expectVisible(test, parent); |
| 523 return timeout(REFRESH_INTERVAL); |
| 524 }).then(() => |
| 525 { |
| 526 expectVisible(test, child); |
| 527 expectHidden(test, parent); |
| 528 }).catch(unexpectedError.bind(test)).then(() => test.done()); |
| 529 }; |
| 530 |
| 531 exports.testDomUpdatesContent = function(test) |
| 532 { |
| 533 let parent = createElementWithStyle("{}"); |
| 534 let child = createElementWithStyle("{}", parent); |
| 535 applyElemHideEmulation( |
| 536 ["div > div:-abp-contains(hide me)"] |
| 537 ).then(() => |
| 538 { |
| 539 expectVisible(test, parent); |
| 540 expectVisible(test, child); |
| 541 |
| 542 child.textContent = "hide me"; |
| 543 return timeout(0); |
| 544 }).then(() => |
| 545 { |
| 546 expectVisible(test, parent); |
| 547 expectVisible(test, child); |
| 548 return timeout(REFRESH_INTERVAL); |
| 549 }).then(() => |
| 550 { |
| 551 expectVisible(test, parent); |
| 552 expectHidden(test, child); |
| 553 }).catch(unexpectedError.bind(test)).then(() => test.done()); |
| 554 }; |
| 555 |
| 556 exports.testDomUpdatesNewElement = function(test) |
| 557 { |
| 558 let parent = createElementWithStyle("{}"); |
| 559 let child = createElementWithStyle("{ background-color: #000}", parent); |
| 560 let sibling; |
| 561 let child2; |
| 562 applyElemHideEmulation( |
| 563 ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0, 0)))"] |
| 564 ).then(() => |
| 565 { |
| 566 expectHidden(test, parent); |
| 567 expectVisible(test, child); |
| 568 |
| 569 sibling = createElementWithStyle("{}"); |
| 570 return timeout(0); |
| 571 }).then(() => |
| 572 { |
| 573 expectHidden(test, parent); |
| 574 expectVisible(test, child); |
| 575 expectVisible(test, sibling); |
| 576 |
| 577 return timeout(REFRESH_INTERVAL); |
| 578 }).then(() => |
| 579 { |
| 580 expectHidden(test, parent); |
| 581 expectVisible(test, child); |
| 582 expectVisible(test, sibling); |
| 583 |
| 584 child2 = createElementWithStyle("{ background-color: #000}", |
| 585 sibling); |
| 586 return timeout(0); |
| 587 }).then(() => |
| 588 { |
| 589 expectVisible(test, child2); |
| 590 return timeout(REFRESH_INTERVAL); |
| 591 }).then(() => |
| 592 { |
| 593 expectHidden(test, parent); |
| 594 expectVisible(test, child); |
| 595 expectHidden(test, sibling); |
| 596 expectVisible(test, child2); |
| 597 }).catch(unexpectedError.bind(test)).then(() => test.done()); |
| 598 }; |
LEFT | RIGHT |