 Issue 29494577:
  Issue 5438 - Observer DOM changes to reapply filters.  (Closed) 
  Base URL: https://hg.adblockplus.org/adblockpluscore/
    
  
    Issue 29494577:
  Issue 5438 - Observer DOM changes to reapply filters.  (Closed) 
  Base URL: https://hg.adblockplus.org/adblockpluscore/| 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 let testDocument = null; | |
| 23 | |
| 24 exports.setUp = function(callback) | |
| 25 { | |
| 26 testDocument = null; | |
| 
Wladimir Palant
2017/08/23 13:23:31
This assignment seems pointless.
 
hub
2017/08/23 16:38:00
Done.
 | |
| 27 let iframe = document.createElement("iframe"); | |
| 28 iframe.id = "test-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 = document.getElementById("test-iframe"); | 
| 
Wladimir Palant
2017/08/23 13:23:32
Use `testDocument.defaultView.frameElement` here?
 
hub
2017/08/23 16:38:00
Done.
 | |
| 25 while (styleElements.length) | 38 iframe.parentNode.removeChild(iframe); | 
| 
Wladimir Palant
2017/08/23 13:23:31
Please null out testDocument as well, so that tryi
 
hub
2017/08/23 16:38:00
Done.
 | |
| 26 styleElements[0].parentNode.removeChild(styleElements[0]); | |
| 27 | |
| 28 let child; | |
| 29 while (child = document.body.firstChild) | |
| 30 child.parentNode.removeChild(child); | |
| 31 | 39 | 
| 32 callback(); | 40 callback(); | 
| 33 }; | 41 }; | 
| 34 | 42 | 
| 35 function unexpectedError(error) | 43 function unexpectedError(error) | 
| 36 { | 44 { | 
| 37 console.error(error); | 45 console.error(error); | 
| 38 this.ok(false, "Unexpected error: " + error); | 46 this.ok(false, "Unexpected error: " + error); | 
| 39 } | 47 } | 
| 40 | 48 | 
| 41 function expectHidden(test, element) | 49 function expectHidden(test, element) | 
| 42 { | 50 { | 
| 43 test.equal(window.getComputedStyle(element).display, "none", | 51 test.equal(window.getComputedStyle(element).display, "none", | 
| 44 "The element's display property should be set to 'none'"); | 52 "The element's display property should be set to 'none'"); | 
| 45 } | 53 } | 
| 46 | 54 | 
| 47 function expectVisible(test, element) | 55 function expectVisible(test, element) | 
| 48 { | 56 { | 
| 49 test.notEqual(window.getComputedStyle(element).display, "none", | 57 test.notEqual(window.getComputedStyle(element).display, "none", | 
| 50 "The element's display property should not be set to 'none'"); | 58 "The element's display property should not be set to 'none'"); | 
| 51 } | 59 } | 
| 52 | 60 | 
| 53 function findUniqueId() | 61 function findUniqueId() | 
| 54 { | 62 { | 
| 55 let id = "elemHideEmulationTest-" + Math.floor(Math.random() * 10000); | 63 let id = "elemHideEmulationTest-" + Math.floor(Math.random() * 10000); | 
| 56 if (!document.getElementById(id)) | 64 if (!testDocument.getElementById(id)) | 
| 57 return id; | 65 return id; | 
| 58 return findUniqueId(); | 66 return findUniqueId(); | 
| 59 } | 67 } | 
| 60 | 68 | 
| 61 function insertStyleRule(rule) | 69 function insertStyleRule(rule) | 
| 62 { | 70 { | 
| 63 let styleElement; | 71 let styleElement; | 
| 64 let styleElements = document.head.getElementsByTagName("style"); | 72 let styleElements = testDocument.head.getElementsByTagName("style"); | 
| 65 if (styleElements.length) | 73 if (styleElements.length) | 
| 66 styleElement = styleElements[0]; | 74 styleElement = styleElements[0]; | 
| 67 else | 75 else | 
| 68 { | 76 { | 
| 69 styleElement = document.createElement("style"); | 77 styleElement = testDocument.createElement("style"); | 
| 70 document.head.appendChild(styleElement); | 78 testDocument.head.appendChild(styleElement); | 
| 71 } | 79 } | 
| 72 styleElement.sheet.insertRule(rule, styleElement.sheet.cssRules.length); | 80 styleElement.sheet.insertRule(rule, styleElement.sheet.cssRules.length); | 
| 73 } | 81 } | 
| 74 | 82 | 
| 75 // Insert a <div> with a unique id and a CSS rule | 83 // Insert a <div> with a unique id and a CSS rule | 
| 76 // for the the selector matching the id. | 84 // for the the selector matching the id. | 
| 77 function createElementWithStyle(styleBlock, parent) | 85 function createElementWithStyle(styleBlock, parent) | 
| 78 { | 86 { | 
| 79 let element = document.createElement("div"); | 87 let element = testDocument.createElement("div"); | 
| 80 element.id = findUniqueId(); | 88 element.id = findUniqueId(); | 
| 81 if (!parent) | 89 if (!parent) | 
| 82 document.body.appendChild(element); | 90 testDocument.body.appendChild(element); | 
| 83 else | 91 else | 
| 84 parent.appendChild(element); | 92 parent.appendChild(element); | 
| 85 insertStyleRule("#" + element.id + " " + styleBlock); | 93 insertStyleRule("#" + element.id + " " + styleBlock); | 
| 86 return element; | 94 return element; | 
| 87 } | 95 } | 
| 88 | 96 | 
| 89 // Create a new ElemHideEmulation instance with @selectors. | 97 // Create a new ElemHideEmulation instance with @selectors. | 
| 90 function applyElemHideEmulation(selectors) | 98 function applyElemHideEmulation(selectors) | 
| 91 { | 99 { | 
| 92 return Promise.resolve().then(() => | 100 return Promise.resolve().then(() => | 
| 93 { | 101 { | 
| 94 let elemHideEmulation = new ElemHideEmulation( | 102 let elemHideEmulation = new ElemHideEmulation( | 
| 95 window, | 103 testDocument.defaultView, | 
| 96 callback => | 104 callback => | 
| 97 { | 105 { | 
| 98 let patterns = []; | 106 let patterns = []; | 
| 99 selectors.forEach(selector => | 107 selectors.forEach(selector => | 
| 100 { | 108 { | 
| 101 patterns.push({selector}); | 109 patterns.push({selector}); | 
| 102 }); | 110 }); | 
| 103 callback(patterns); | 111 callback(patterns); | 
| 104 }, | 112 }, | 
| 105 newSelectors => | 113 newSelectors => | 
| (...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 339 { | 347 { | 
| 340 expectVisible(test, parent); | 348 expectVisible(test, parent); | 
| 341 expectVisible(test, middle); | 349 expectVisible(test, middle); | 
| 342 expectVisible(test, sibling); | 350 expectVisible(test, sibling); | 
| 343 expectHidden(test, toHide); | 351 expectHidden(test, toHide); | 
| 344 }).catch(unexpectedError.bind(test)).then(() => test.done()); | 352 }).catch(unexpectedError.bind(test)).then(() => test.done()); | 
| 345 }; | 353 }; | 
| 346 | 354 | 
| 347 function runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling(test, selector , expectations) | 355 function runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling(test, selector , expectations) | 
| 348 { | 356 { | 
| 349 document.body.innerHTML = `<div id="parent"> | 357 testDocument.body.innerHTML = `<div id="parent"> | 
| 350 <div id="middle"> | 358 <div id="middle"> | 
| 351 <div id="middle1"><div id="inside" class="inside"></div></div> | 359 <div id="middle1"><div id="inside" class="inside"></div></div> | 
| 352 </div> | 360 </div> | 
| 353 <div id="sibling"> | 361 <div id="sibling"> | 
| 354 <div id="tohide">to hide</div> | 362 <div id="tohide">to hide</div> | 
| 355 </div> | 363 </div> | 
| 356 <div id="sibling2"> | 364 <div id="sibling2"> | 
| 357 <div id="sibling21"><div id="sibling211" class="inside"></div></div> | 365 <div id="sibling21"><div id="sibling211" class="inside"></div></div> | 
| 358 </div> | 366 </div> | 
| 359 </div>`; | 367 </div>`; | 
| 360 let elems = { | 368 let elems = { | 
| 361 parent: document.getElementById("parent"), | 369 parent: testDocument.getElementById("parent"), | 
| 362 middle: document.getElementById("middle"), | 370 middle: testDocument.getElementById("middle"), | 
| 363 inside: document.getElementById("inside"), | 371 inside: testDocument.getElementById("inside"), | 
| 364 sibling: document.getElementById("sibling"), | 372 sibling: testDocument.getElementById("sibling"), | 
| 365 sibling2: document.getElementById("sibling2"), | 373 sibling2: testDocument.getElementById("sibling2"), | 
| 366 toHide: document.getElementById("tohide") | 374 toHide: testDocument.getElementById("tohide") | 
| 367 }; | 375 }; | 
| 368 | 376 | 
| 369 insertStyleRule(".inside {}"); | 377 insertStyleRule(".inside {}"); | 
| 370 | 378 | 
| 371 applyElemHideEmulation( | 379 applyElemHideEmulation( | 
| 372 [selector] | 380 [selector] | 
| 373 ).then(() => | 381 ).then(() => | 
| 374 { | 382 { | 
| 375 for (let elem in expectations) | 383 for (let elem in expectations) | 
| 376 if (elems[elem]) | 384 if (elems[elem]) | 
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 420 sibling: true, | 428 sibling: true, | 
| 421 sibling2: true, | 429 sibling2: true, | 
| 422 toHide: true | 430 toHide: true | 
| 423 }; | 431 }; | 
| 424 runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling( | 432 runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling( | 
| 425 test, "div:-abp-has(> body div.inside) + div > div", expectations); | 433 test, "div:-abp-has(> body div.inside) + div > div", expectations); | 
| 426 }; | 434 }; | 
| 427 | 435 | 
| 428 exports.testPseudoClassContains = function(test) | 436 exports.testPseudoClassContains = function(test) | 
| 429 { | 437 { | 
| 430 document.body.innerHTML = `<div id="parent"> | 438 testDocument.body.innerHTML = `<div id="parent"> | 
| 431 <div id="middle"> | 439 <div id="middle"> | 
| 432 <div id="middle1"><div id="inside" class="inside"></div></div> | 440 <div id="middle1"><div id="inside" class="inside"></div></div> | 
| 433 </div> | 441 </div> | 
| 434 <div id="sibling"> | 442 <div id="sibling"> | 
| 435 <div id="tohide">to hide</div> | 443 <div id="tohide">to hide</div> | 
| 436 </div> | 444 </div> | 
| 437 <div id="sibling2"> | 445 <div id="sibling2"> | 
| 438 <div id="sibling21"><div id="sibling211" class="inside"></div></div> | 446 <div id="sibling21"><div id="sibling211" class="inside"></div></div> | 
| 439 </div> | 447 </div> | 
| 440 </div>`; | 448 </div>`; | 
| 441 let parent = document.getElementById("parent"); | 449 let parent = testDocument.getElementById("parent"); | 
| 442 let middle = document.getElementById("middle"); | 450 let middle = testDocument.getElementById("middle"); | 
| 443 let inside = document.getElementById("inside"); | 451 let inside = testDocument.getElementById("inside"); | 
| 444 let sibling = document.getElementById("sibling"); | 452 let sibling = testDocument.getElementById("sibling"); | 
| 445 let sibling2 = document.getElementById("sibling2"); | 453 let sibling2 = testDocument.getElementById("sibling2"); | 
| 446 let toHide = document.getElementById("tohide"); | 454 let toHide = testDocument.getElementById("tohide"); | 
| 447 | 455 | 
| 448 applyElemHideEmulation( | 456 applyElemHideEmulation( | 
| 449 ["#parent div:-abp-contains(to hide)"] | 457 ["#parent div:-abp-contains(to hide)"] | 
| 450 ).then(() => | 458 ).then(() => | 
| 451 { | 459 { | 
| 452 expectVisible(test, parent); | 460 expectVisible(test, parent); | 
| 453 expectVisible(test, middle); | 461 expectVisible(test, middle); | 
| 454 expectVisible(test, inside); | 462 expectVisible(test, inside); | 
| 455 expectHidden(test, sibling); | 463 expectHidden(test, sibling); | 
| 456 expectVisible(test, sibling2); | 464 expectVisible(test, sibling2); | 
| (...skipping 20 matching lines...) Expand all Loading... | |
| 477 let child = createElementWithStyle("{}", parent); | 485 let child = createElementWithStyle("{}", parent); | 
| 478 insertStyleRule("body #" + parent.id + " > div { background-color: #000}"); | 486 insertStyleRule("body #" + parent.id + " > div { background-color: #000}"); | 
| 479 applyElemHideEmulation( | 487 applyElemHideEmulation( | 
| 480 ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0, 0)))"] | 488 ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0, 0)))"] | 
| 481 ).then(() => | 489 ).then(() => | 
| 482 { | 490 { | 
| 483 expectVisible(test, child); | 491 expectVisible(test, child); | 
| 484 expectHidden(test, parent); | 492 expectHidden(test, parent); | 
| 485 }).catch(unexpectedError.bind(test)).then(() => test.done()); | 493 }).catch(unexpectedError.bind(test)).then(() => test.done()); | 
| 486 }; | 494 }; | 
| 495 | |
| 496 exports.testDomUpdatesStyle = function(test) | |
| 497 { | |
| 498 let parent = createElementWithStyle("{}"); | |
| 499 let child = createElementWithStyle("{}", parent); | |
| 500 applyElemHideEmulation( | |
| 501 ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0, 0)))"] | |
| 502 ).then(() => | |
| 503 { | |
| 504 expectVisible(test, child); | |
| 505 expectVisible(test, parent); | |
| 506 | |
| 507 insertStyleRule("body #" + parent.id + " > div { background-color: #000}"); | |
| 508 | |
| 509 return new Promise((resolve, reject) => | |
| 510 { | |
| 511 expectVisible(test, child); | |
| 512 expectVisible(test, parent); | |
| 513 window.setTimeout(() => | |
| 514 { | |
| 515 expectVisible(test, child); | |
| 516 expectHidden(test, parent); | |
| 517 resolve(); | |
| 518 }, 4000); | |
| 519 }); | |
| 
Wladimir Palant
2017/08/23 13:23:32
Please use a helper to promisify timeouts:
  func
 
hub
2017/08/23 16:38:00
Done.
 | |
| 520 }).catch(unexpectedError.bind(test)).then(() => test.done()); | |
| 521 }; | |
| 522 | |
| 523 exports.testDomUpdatesContent = function(test) | |
| 524 { | |
| 525 let parent = createElementWithStyle("{}"); | |
| 526 let child = createElementWithStyle("{}", parent); | |
| 527 applyElemHideEmulation( | |
| 528 ["div > div:-abp-contains(hide me)"] | |
| 529 ).then(() => | |
| 530 { | |
| 531 expectVisible(test, parent); | |
| 532 expectVisible(test, child); | |
| 533 | |
| 534 child.innerText = "hide me"; | |
| 
Wladimir Palant
2017/08/23 13:23:32
Please use child.textContent, innerText is non-sta
 
hub
2017/08/23 16:38:00
Done.
 | |
| 535 return new Promise((resolve, reject) => | |
| 536 { | |
| 537 expectVisible(test, parent); | |
| 538 expectVisible(test, child); | |
| 539 window.setTimeout(() => | |
| 540 { | |
| 541 expectVisible(test, parent); | |
| 542 expectHidden(test, child); | |
| 543 resolve(); | |
| 544 }, 4000); | |
| 545 }); | |
| 546 }).catch(unexpectedError.bind(test)).then(() => test.done()); | |
| 547 }; | |
| 548 | |
| 549 exports.testDomUpdatesNewElement = function(test) | |
| 550 { | |
| 551 let parent = createElementWithStyle("{}"); | |
| 552 let child = createElementWithStyle("{ background-color: #000}", parent); | |
| 553 applyElemHideEmulation( | |
| 554 ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0, 0)))"] | |
| 555 ).then(() => | |
| 556 { | |
| 557 expectHidden(test, parent); | |
| 558 expectVisible(test, child); | |
| 559 | |
| 560 let sibling = createElementWithStyle("{}"); | |
| 561 expectVisible(test, sibling); | |
| 562 | |
| 563 return new Promise((resolve, reject) => | |
| 564 { | |
| 565 expectHidden(test, parent); | |
| 566 expectVisible(test, child); | |
| 567 expectVisible(test, sibling); | |
| 568 window.setTimeout(() => | |
| 569 { | |
| 570 expectHidden(test, parent); | |
| 571 expectVisible(test, child); | |
| 572 expectVisible(test, sibling); | |
| 573 | |
| 574 let child2 = createElementWithStyle("{ background-color: #000}", | |
| 575 sibling); | |
| 576 expectVisible(test, child2); | |
| 577 window.setTimeout(() => | |
| 578 { | |
| 579 expectHidden(test, parent); | |
| 580 expectVisible(test, child); | |
| 581 expectHidden(test, sibling); | |
| 582 expectVisible(test, child2); | |
| 583 | |
| 584 resolve(); | |
| 585 }, 4000); | |
| 586 }, 4000); | |
| 
Wladimir Palant
2017/08/23 13:23:32
The huge delays here are an issue. We need to chan
 
hub
2017/08/23 16:38:00
IMHO the best approach would be to have it configu
 | |
| 587 }); | |
| 588 }).catch(unexpectedError.bind(test)).then(() => test.done()); | |
| 589 }; | |
| OLD | NEW |