 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/| Index: test/browser/elemHideEmulation.js | 
| =================================================================== | 
| --- a/test/browser/elemHideEmulation.js | 
| +++ b/test/browser/elemHideEmulation.js | 
| @@ -14,25 +14,33 @@ | 
| * You should have received a copy of the GNU General Public License | 
| * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. | 
| */ | 
| "use strict"; | 
| const {ElemHideEmulation} = require("../../lib/content/elemHideEmulation"); | 
| +let testDocument = null; | 
| + | 
| +exports.setUp = function(callback) | 
| +{ | 
| + testDocument = null; | 
| 
Wladimir Palant
2017/08/23 13:23:31
This assignment seems pointless.
 
hub
2017/08/23 16:38:00
Done.
 | 
| + let iframe = document.createElement("iframe"); | 
| + iframe.id = "test-iframe"; | 
| + document.body.appendChild(iframe); | 
| + testDocument = iframe.contentDocument; | 
| + | 
| + callback(); | 
| +}; | 
| + | 
| exports.tearDown = function(callback) | 
| { | 
| - let styleElements = document.head.getElementsByTagName("style"); | 
| - while (styleElements.length) | 
| - styleElements[0].parentNode.removeChild(styleElements[0]); | 
| - | 
| - let child; | 
| - while (child = document.body.firstChild) | 
| - child.parentNode.removeChild(child); | 
| + 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.
 | 
| + 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.
 | 
| callback(); | 
| }; | 
| function unexpectedError(error) | 
| { | 
| console.error(error); | 
| this.ok(false, "Unexpected error: " + error); | 
| @@ -48,56 +56,56 @@ | 
| { | 
| test.notEqual(window.getComputedStyle(element).display, "none", | 
| "The element's display property should not be set to 'none'"); | 
| } | 
| function findUniqueId() | 
| { | 
| let id = "elemHideEmulationTest-" + Math.floor(Math.random() * 10000); | 
| - if (!document.getElementById(id)) | 
| + if (!testDocument.getElementById(id)) | 
| return id; | 
| return findUniqueId(); | 
| } | 
| function insertStyleRule(rule) | 
| { | 
| let styleElement; | 
| - let styleElements = document.head.getElementsByTagName("style"); | 
| + let styleElements = testDocument.head.getElementsByTagName("style"); | 
| if (styleElements.length) | 
| styleElement = styleElements[0]; | 
| else | 
| { | 
| - styleElement = document.createElement("style"); | 
| - document.head.appendChild(styleElement); | 
| + styleElement = testDocument.createElement("style"); | 
| + testDocument.head.appendChild(styleElement); | 
| } | 
| styleElement.sheet.insertRule(rule, styleElement.sheet.cssRules.length); | 
| } | 
| // Insert a <div> with a unique id and a CSS rule | 
| // for the the selector matching the id. | 
| function createElementWithStyle(styleBlock, parent) | 
| { | 
| - let element = document.createElement("div"); | 
| + let element = testDocument.createElement("div"); | 
| element.id = findUniqueId(); | 
| if (!parent) | 
| - document.body.appendChild(element); | 
| + testDocument.body.appendChild(element); | 
| else | 
| parent.appendChild(element); | 
| insertStyleRule("#" + element.id + " " + styleBlock); | 
| return element; | 
| } | 
| // Create a new ElemHideEmulation instance with @selectors. | 
| function applyElemHideEmulation(selectors) | 
| { | 
| return Promise.resolve().then(() => | 
| { | 
| let elemHideEmulation = new ElemHideEmulation( | 
| - window, | 
| + testDocument.defaultView, | 
| callback => | 
| { | 
| let patterns = []; | 
| selectors.forEach(selector => | 
| { | 
| patterns.push({selector}); | 
| }); | 
| callback(patterns); | 
| @@ -341,34 +349,34 @@ | 
| expectVisible(test, middle); | 
| expectVisible(test, sibling); | 
| expectHidden(test, toHide); | 
| }).catch(unexpectedError.bind(test)).then(() => test.done()); | 
| }; | 
| function runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling(test, selector, expectations) | 
| { | 
| - document.body.innerHTML = `<div id="parent"> | 
| + testDocument.body.innerHTML = `<div id="parent"> | 
| <div id="middle"> | 
| <div id="middle1"><div id="inside" class="inside"></div></div> | 
| </div> | 
| <div id="sibling"> | 
| <div id="tohide">to hide</div> | 
| </div> | 
| <div id="sibling2"> | 
| <div id="sibling21"><div id="sibling211" class="inside"></div></div> | 
| </div> | 
| </div>`; | 
| let elems = { | 
| - parent: document.getElementById("parent"), | 
| - middle: document.getElementById("middle"), | 
| - inside: document.getElementById("inside"), | 
| - sibling: document.getElementById("sibling"), | 
| - sibling2: document.getElementById("sibling2"), | 
| - toHide: document.getElementById("tohide") | 
| + parent: testDocument.getElementById("parent"), | 
| + middle: testDocument.getElementById("middle"), | 
| + inside: testDocument.getElementById("inside"), | 
| + sibling: testDocument.getElementById("sibling"), | 
| + sibling2: testDocument.getElementById("sibling2"), | 
| + toHide: testDocument.getElementById("tohide") | 
| }; | 
| insertStyleRule(".inside {}"); | 
| applyElemHideEmulation( | 
| [selector] | 
| ).then(() => | 
| { | 
| @@ -422,33 +430,33 @@ | 
| toHide: true | 
| }; | 
| runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling( | 
| test, "div:-abp-has(> body div.inside) + div > div", expectations); | 
| }; | 
| exports.testPseudoClassContains = function(test) | 
| { | 
| - document.body.innerHTML = `<div id="parent"> | 
| + testDocument.body.innerHTML = `<div id="parent"> | 
| <div id="middle"> | 
| <div id="middle1"><div id="inside" class="inside"></div></div> | 
| </div> | 
| <div id="sibling"> | 
| <div id="tohide">to hide</div> | 
| </div> | 
| <div id="sibling2"> | 
| <div id="sibling21"><div id="sibling211" class="inside"></div></div> | 
| </div> | 
| </div>`; | 
| - let parent = document.getElementById("parent"); | 
| - let middle = document.getElementById("middle"); | 
| - let inside = document.getElementById("inside"); | 
| - let sibling = document.getElementById("sibling"); | 
| - let sibling2 = document.getElementById("sibling2"); | 
| - let toHide = document.getElementById("tohide"); | 
| + let parent = testDocument.getElementById("parent"); | 
| + let middle = testDocument.getElementById("middle"); | 
| + let inside = testDocument.getElementById("inside"); | 
| + let sibling = testDocument.getElementById("sibling"); | 
| + let sibling2 = testDocument.getElementById("sibling2"); | 
| + let toHide = testDocument.getElementById("tohide"); | 
| applyElemHideEmulation( | 
| ["#parent div:-abp-contains(to hide)"] | 
| ).then(() => | 
| { | 
| expectVisible(test, parent); | 
| expectVisible(test, middle); | 
| expectVisible(test, inside); | 
| @@ -479,8 +487,103 @@ | 
| applyElemHideEmulation( | 
| ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0, 0)))"] | 
| ).then(() => | 
| { | 
| expectVisible(test, child); | 
| expectHidden(test, parent); | 
| }).catch(unexpectedError.bind(test)).then(() => test.done()); | 
| }; | 
| + | 
| +exports.testDomUpdatesStyle = function(test) | 
| +{ | 
| + let parent = createElementWithStyle("{}"); | 
| + let child = createElementWithStyle("{}", parent); | 
| + applyElemHideEmulation( | 
| + ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0, 0)))"] | 
| + ).then(() => | 
| + { | 
| + expectVisible(test, child); | 
| + expectVisible(test, parent); | 
| + | 
| + insertStyleRule("body #" + parent.id + " > div { background-color: #000}"); | 
| + | 
| + return new Promise((resolve, reject) => | 
| + { | 
| + expectVisible(test, child); | 
| + expectVisible(test, parent); | 
| + window.setTimeout(() => | 
| + { | 
| + expectVisible(test, child); | 
| + expectHidden(test, parent); | 
| + resolve(); | 
| + }, 4000); | 
| + }); | 
| 
Wladimir Palant
2017/08/23 13:23:32
Please use a helper to promisify timeouts:
  func
 
hub
2017/08/23 16:38:00
Done.
 | 
| + }).catch(unexpectedError.bind(test)).then(() => test.done()); | 
| +}; | 
| + | 
| +exports.testDomUpdatesContent = function(test) | 
| +{ | 
| + let parent = createElementWithStyle("{}"); | 
| + let child = createElementWithStyle("{}", parent); | 
| + applyElemHideEmulation( | 
| + ["div > div:-abp-contains(hide me)"] | 
| + ).then(() => | 
| + { | 
| + expectVisible(test, parent); | 
| + expectVisible(test, child); | 
| + | 
| + 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.
 | 
| + return new Promise((resolve, reject) => | 
| + { | 
| + expectVisible(test, parent); | 
| + expectVisible(test, child); | 
| + window.setTimeout(() => | 
| + { | 
| + expectVisible(test, parent); | 
| + expectHidden(test, child); | 
| + resolve(); | 
| + }, 4000); | 
| + }); | 
| + }).catch(unexpectedError.bind(test)).then(() => test.done()); | 
| +}; | 
| + | 
| +exports.testDomUpdatesNewElement = function(test) | 
| +{ | 
| + let parent = createElementWithStyle("{}"); | 
| + let child = createElementWithStyle("{ background-color: #000}", parent); | 
| + applyElemHideEmulation( | 
| + ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0, 0)))"] | 
| + ).then(() => | 
| + { | 
| + expectHidden(test, parent); | 
| + expectVisible(test, child); | 
| + | 
| + let sibling = createElementWithStyle("{}"); | 
| + expectVisible(test, sibling); | 
| + | 
| + return new Promise((resolve, reject) => | 
| + { | 
| + expectHidden(test, parent); | 
| + expectVisible(test, child); | 
| + expectVisible(test, sibling); | 
| + window.setTimeout(() => | 
| + { | 
| + expectHidden(test, parent); | 
| + expectVisible(test, child); | 
| + expectVisible(test, sibling); | 
| + | 
| + let child2 = createElementWithStyle("{ background-color: #000}", | 
| + sibling); | 
| + expectVisible(test, child2); | 
| + window.setTimeout(() => | 
| + { | 
| + expectHidden(test, parent); | 
| + expectVisible(test, child); | 
| + expectHidden(test, sibling); | 
| + expectVisible(test, child2); | 
| + | 
| + resolve(); | 
| + }, 4000); | 
| + }, 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
 | 
| + }); | 
| + }).catch(unexpectedError.bind(test)).then(() => test.done()); | 
| +}; |