| Index: test/browser/elemHideEmulation.js |
| =================================================================== |
| --- a/test/browser/elemHideEmulation.js |
| +++ b/test/browser/elemHideEmulation.js |
| @@ -10,1123 +10,1089 @@ |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
| */ |
| +/* global assert */ |
| + |
| "use strict"; |
| const {ElemHideEmulation, setTestMode, |
| getTestInfo} = require("../../lib/content/elemHideEmulation"); |
| const {timeout} = require("./_utils"); |
| -const REFRESH_INTERVAL = 200; |
| - |
| -let testDocument = null; |
| - |
| -exports.setUp = function(callback) |
| -{ |
| - setTestMode(); |
| - |
| - let iframe = document.createElement("iframe"); |
| - document.body.appendChild(iframe); |
| - testDocument = iframe.contentDocument; |
| - |
| - callback(); |
| -}; |
| - |
| -exports.tearDown = function(callback) |
| -{ |
| - let iframe = testDocument.defaultView.frameElement; |
| - iframe.parentNode.removeChild(iframe); |
| - testDocument = null; |
| - |
| - callback(); |
| -}; |
| - |
| -function unexpectedError(test, error) |
| -{ |
| - console.error(error); |
| - test.ok(false, "Unexpected error: " + error); |
| -} |
| - |
| -function expectHidden(test, element, id) |
| -{ |
| - let withId = ""; |
| - if (typeof id != "undefined") |
| - withId = ` with ID '${id}'`; |
| - |
| - test.equal( |
| - window.getComputedStyle(element).display, "none", |
| - `The element${withId}'s display property should be set to 'none'`); |
| -} |
| - |
| -function expectVisible(test, element, id) |
| -{ |
| - let withId = ""; |
| - if (typeof id != "undefined") |
| - withId = ` with ID '${id}'`; |
| - |
| - test.notEqual( |
| - window.getComputedStyle(element).display, "none", |
| - `The element${withId}'s display property should not be set to 'none'`); |
| -} |
| - |
| -function expectProcessed(test, element, id = null) |
| -{ |
| - let withId = ""; |
| - if (id) |
| - withId = ` with ID '${id}'`; |
| - |
| - test.ok( |
| - getTestInfo().lastProcessedElements.has(element), |
| - `The element${withId} should have been processed`); |
| -} |
| - |
| -function expectNotProcessed(test, element, id = null) |
| -{ |
| - let withId = ""; |
| - if (id) |
| - withId = ` with ID '${id}'`; |
| - |
| - test.ok( |
| - !getTestInfo().lastProcessedElements.has(element), |
| - `The element${withId} should not have been processed`); |
| -} |
| - |
| -function findUniqueId() |
| -{ |
| - let id = "elemHideEmulationTest-" + Math.floor(Math.random() * 10000); |
| - if (!testDocument.getElementById(id)) |
| - return id; |
| - return findUniqueId(); |
| -} |
| - |
| -function insertStyleRule(rule) |
| +describe("Element Hiding Emulation", () => |
| { |
| - let styleElement; |
| - let styleElements = testDocument.head.getElementsByTagName("style"); |
| - if (styleElements.length) |
| - styleElement = styleElements[0]; |
| - else |
| - { |
| - styleElement = testDocument.createElement("style"); |
| - testDocument.head.appendChild(styleElement); |
| - } |
| - styleElement.sheet.insertRule(rule, styleElement.sheet.cssRules.length); |
| -} |
| + const REFRESH_INTERVAL = 200; |
| -function createElement(parent, type = "div", id = findUniqueId(), |
| - innerText = null) |
| -{ |
| - let element = testDocument.createElement(type); |
| - element.id = id; |
| - if (!parent) |
| - testDocument.body.appendChild(element); |
| - else |
| - parent.appendChild(element); |
| - if (innerText) |
| - element.innerText = innerText; |
| - return element; |
| -} |
| + let testDocument = null; |
| -// Insert a <div> with a unique id and a CSS rule |
| -// for the the selector matching the id. |
| -function createElementWithStyle(styleBlock, parent) |
| -{ |
| - let element = createElement(parent); |
| - insertStyleRule("#" + element.id + " " + styleBlock); |
| - return element; |
| -} |
| - |
| -// Create a new ElemHideEmulation instance with @selectors. |
| -async function applyElemHideEmulation(test, selectors) |
| -{ |
| - await Promise.resolve(); |
| - |
| - try |
| + beforeEach(() => |
| { |
| - let elemHideEmulation = new ElemHideEmulation( |
| - elems => |
| - { |
| - for (let elem of elems) |
| - elem.style.display = "none"; |
| - } |
| - ); |
| + setTestMode(); |
| - elemHideEmulation.document = testDocument; |
| - elemHideEmulation.MIN_INVOCATION_INTERVAL = REFRESH_INTERVAL / 2; |
| - elemHideEmulation.apply(selectors.map( |
| - selector => ({selector, text: selector}) |
| - )); |
| - |
| - return elemHideEmulation; |
| - } |
| - catch (error) |
| - { |
| - unexpectedError(test, error); |
| - } |
| -} |
| + let iframe = document.createElement("iframe"); |
| + document.body.appendChild(iframe); |
| + testDocument = iframe.contentDocument; |
| + }); |
| -exports.testVerbatimPropertySelector = async function(test) |
| -{ |
| - let toHide = createElementWithStyle("{background-color: #000}"); |
| - let selectors = [":-abp-properties(background-color: rgb(0, 0, 0))"]; |
| - |
| - if (await applyElemHideEmulation(test, selectors)) |
| - expectHidden(test, toHide); |
| - |
| - test.done(); |
| -}; |
| + afterEach(() => |
| + { |
| + let iframe = testDocument.defaultView.frameElement; |
| + iframe.parentNode.removeChild(iframe); |
| + testDocument = null; |
| + }); |
| -exports.testVerbatimPropertySelectorWithPrefix = async function(test) |
| -{ |
| - let parent = createElementWithStyle("{background-color: #000}"); |
| - let toHide = createElementWithStyle("{background-color: #000}", parent); |
| - |
| - let selectors = ["div > :-abp-properties(background-color: rgb(0, 0, 0))"]; |
| - |
| - if (await applyElemHideEmulation(test, selectors)) |
| + function unexpectedError(error) |
| { |
| - expectVisible(test, parent); |
| - expectHidden(test, toHide); |
| + console.error(error); |
| + assert.ok(false, "Unexpected error: " + error); |
| } |
| - test.done(); |
| -}; |
| + function expectHidden(element, id) |
| + { |
| + let withId = ""; |
| + if (typeof id != "undefined") |
| + withId = ` with ID '${id}'`; |
| + |
| + assert.equal( |
| + window.getComputedStyle(element).display, "none", |
| + `The element${withId}'s display property should be set to 'none'`); |
| + } |
| + |
| + function expectVisible(element, id) |
| + { |
| + let withId = ""; |
| + if (typeof id != "undefined") |
| + withId = ` with ID '${id}'`; |
| -exports.testVerbatimPropertySelectorWithPrefixNoMatch = async function(test) |
| -{ |
| - let parent = createElementWithStyle("{background-color: #000}"); |
| - let toHide = createElementWithStyle("{background-color: #fff}", parent); |
| + assert.notEqual( |
| + window.getComputedStyle(element).display, "none", |
| + `The element${withId}'s display property should not be set to 'none'`); |
| + } |
| + |
| + function expectProcessed(element, id = null) |
| + { |
| + let withId = ""; |
| + if (id) |
| + withId = ` with ID '${id}'`; |
| - let selectors = ["div > :-abp-properties(background-color: rgb(0, 0, 0))"]; |
| + assert.ok( |
| + getTestInfo().lastProcessedElements.has(element), |
| + `The element${withId} should have been processed`); |
| + } |
| - if (await applyElemHideEmulation(test, selectors)) |
| + function expectNotProcessed(element, id = null) |
| { |
| - expectVisible(test, parent); |
| - expectVisible(test, toHide); |
| + let withId = ""; |
| + if (id) |
| + withId = ` with ID '${id}'`; |
| + |
| + assert.ok( |
| + !getTestInfo().lastProcessedElements.has(element), |
| + `The element${withId} should not have been processed`); |
| } |
| - test.done(); |
| -}; |
| - |
| -exports.testVerbatimPropertySelectorWithSuffix = async function(test) |
| -{ |
| - let parent = createElementWithStyle("{background-color: #000}"); |
| - let toHide = createElementWithStyle("{background-color: #000}", parent); |
| - |
| - let selectors = [":-abp-properties(background-color: rgb(0, 0, 0)) > div"]; |
| - |
| - if (await applyElemHideEmulation(test, selectors)) |
| + function findUniqueId() |
| { |
| - expectVisible(test, parent); |
| - expectHidden(test, toHide); |
| - } |
| - |
| - test.done(); |
| -}; |
| - |
| -exports.testVerbatimPropertyPseudoSelectorWithPrefixAndSuffix = async function(test) |
| -{ |
| - let parent = createElementWithStyle("{background-color: #000}"); |
| - let middle = createElementWithStyle("{background-color: #000}", parent); |
| - let toHide = createElementWithStyle("{background-color: #000}", middle); |
| - |
| - let selectors = ["div > :-abp-properties(background-color: rgb(0, 0, 0)) > div"]; |
| - |
| - if (await applyElemHideEmulation(test, selectors)) |
| - { |
| - expectVisible(test, parent); |
| - expectVisible(test, middle); |
| - expectHidden(test, toHide); |
| + let id = "elemHideEmulationTest-" + Math.floor(Math.random() * 10000); |
| + if (!testDocument.getElementById(id)) |
| + return id; |
| + return findUniqueId(); |
| } |
| - test.done(); |
| -}; |
| - |
| -// Add the style. Then add the element for that style. |
| -// This should retrigger the filtering and hide it. |
| -exports.testPropertyPseudoSelectorAddStyleAndElement = async function(test) |
| -{ |
| - let styleElement; |
| - let toHide; |
| - |
| - let selectors = [":-abp-properties(background-color: rgb(0, 0, 0))"]; |
| - |
| - if (await applyElemHideEmulation(test, selectors)) |
| + function insertStyleRule(rule) |
| { |
| - styleElement = testDocument.createElement("style"); |
| - testDocument.head.appendChild(styleElement); |
| - styleElement.sheet.insertRule("#toHide {background-color: #000}"); |
| - await timeout(REFRESH_INTERVAL); |
| - |
| - toHide = createElement(); |
| - toHide.id = "toHide"; |
| - expectVisible(test, toHide); |
| - await timeout(REFRESH_INTERVAL); |
| - |
| - expectHidden(test, toHide); |
| + let styleElement; |
| + let styleElements = testDocument.head.getElementsByTagName("style"); |
| + if (styleElements.length) |
| + styleElement = styleElements[0]; |
| + else |
| + { |
| + styleElement = testDocument.createElement("style"); |
| + testDocument.head.appendChild(styleElement); |
| + } |
| + styleElement.sheet.insertRule(rule, styleElement.sheet.cssRules.length); |
| } |
| - test.done(); |
| -}; |
| - |
| -exports.testPropertySelectorWithWildcard = async function(test) |
| -{ |
| - let toHide = createElementWithStyle("{background-color: #000}"); |
| - let selectors = [":-abp-properties(*color: rgb(0, 0, 0))"]; |
| - |
| - if (await applyElemHideEmulation(test, selectors)) |
| - expectHidden(test, toHide); |
| - |
| - test.done(); |
| -}; |
| - |
| -exports.testPropertySelectorWithRegularExpression = async function(test) |
| -{ |
| - let toHide = createElementWithStyle("{background-color: #000}"); |
| - let selectors = [":-abp-properties(/.*color: rgb\\(0, 0, 0\\)/)"]; |
| - |
| - if (await applyElemHideEmulation(test, selectors)) |
| - expectHidden(test, toHide); |
| - |
| - test.done(); |
| -}; |
| - |
| -exports.testDynamicallyChangedProperty = async function(test) |
| -{ |
| - let toHide = createElementWithStyle("{}"); |
| - let selectors = [":-abp-properties(background-color: rgb(0, 0, 0))"]; |
| - |
| - if (await applyElemHideEmulation(test, selectors)) |
| + function createElement(parent, type = "div", id = findUniqueId(), |
| + innerText = null) |
| { |
| - expectVisible(test, toHide); |
| - insertStyleRule("#" + toHide.id + " {background-color: #000}"); |
| - |
| - await timeout(0); |
| - |
| - // Re-evaluation will only happen after a delay |
| - expectVisible(test, toHide); |
| - await timeout(REFRESH_INTERVAL); |
| - |
| - expectHidden(test, toHide); |
| + let element = testDocument.createElement(type); |
| + element.id = id; |
| + if (!parent) |
| + testDocument.body.appendChild(element); |
| + else |
| + parent.appendChild(element); |
| + if (innerText) |
| + element.innerText = innerText; |
| + return element; |
| } |
| - test.done(); |
| -}; |
| - |
| -exports.testPseudoClassWithPropBeforeSelector = async function(test) |
| -{ |
| - let parent = createElementWithStyle("{}"); |
| - let child = createElementWithStyle("{background-color: #000}", parent); |
| - |
| - let selectors = ["div:-abp-properties(content: \"publicite\")"]; |
| - |
| - insertStyleRule(`#${child.id}::before {content: "publicite"}`); |
| - |
| - if (await applyElemHideEmulation(test, selectors)) |
| + // Insert a <div> with a unique id and a CSS rule |
| + // for the the selector matching the id. |
| + function createElementWithStyle(styleBlock, parent) |
| { |
| - expectHidden(test, child); |
| - expectVisible(test, parent); |
| - } |
| - |
| - test.done(); |
| -}; |
| - |
| -exports.testPseudoClassHasSelector = async function(test) |
| -{ |
| - let toHide = createElementWithStyle("{}"); |
| - |
| - if (await applyElemHideEmulation(test, ["div:-abp-has(div)"])) |
| - expectVisible(test, toHide); |
| - |
| - test.done(); |
| -}; |
| - |
| -exports.testPseudoClassHasSelectorWithPrefix = async function(test) |
| -{ |
| - let parent = createElementWithStyle("{}"); |
| - let child = createElementWithStyle("{}", parent); |
| - |
| - if (await applyElemHideEmulation(test, ["div:-abp-has(div)"])) |
| - { |
| - expectHidden(test, parent); |
| - expectVisible(test, child); |
| + let element = createElement(parent); |
| + insertStyleRule("#" + element.id + " " + styleBlock); |
| + return element; |
| } |
| - test.done(); |
| -}; |
| - |
| -exports.testPseudoClassHasSelectorWithSuffix = async function(test) |
| -{ |
| - let parent = createElementWithStyle("{}"); |
| - let middle = createElementWithStyle("{}", parent); |
| - let child = createElementWithStyle("{}", middle); |
| - |
| - if (await applyElemHideEmulation(test, ["div:-abp-has(div) > div"])) |
| + // Create a new ElemHideEmulation instance with @selectors. |
| + async function applyElemHideEmulation(selectors) |
| { |
| - expectVisible(test, parent); |
| - expectHidden(test, middle); |
| - expectHidden(test, child); |
| - } |
| - |
| - test.done(); |
| -}; |
| - |
| -exports.testPseudoClassHasSelectorWithSuffixSibling = async function(test) |
| -{ |
| - let parent = createElementWithStyle("{}"); |
| - let middle = createElementWithStyle("{}", parent); |
| - let toHide = createElementWithStyle("{}"); |
| - |
| - if (await applyElemHideEmulation(test, ["div:-abp-has(div) + div"])) |
| - { |
| - expectVisible(test, parent); |
| - expectVisible(test, middle); |
| - expectHidden(test, toHide); |
| - } |
| - |
| - test.done(); |
| -}; |
| + await Promise.resolve(); |
| -exports.testPseudoClassHasSelectorWithSuffixSiblingChild = async function(test) |
| -{ |
| - // <div> |
| - // <div></div> |
| - // <div> |
| - // <div>to hide</div> |
| - // </div> |
| - // </div> |
| - let parent = createElementWithStyle("{}"); |
| - let middle = createElementWithStyle("{}", parent); |
| - let sibling = createElementWithStyle("{}"); |
| - let toHide = createElementWithStyle("{}", sibling); |
| + try |
| + { |
| + let elemHideEmulation = new ElemHideEmulation( |
| + elems => |
| + { |
| + for (let elem of elems) |
| + elem.style.display = "none"; |
| + } |
| + ); |
| - if (await applyElemHideEmulation(test, ["div:-abp-has(div) + div > div"])) |
| - { |
| - expectVisible(test, parent); |
| - expectVisible(test, middle); |
| - expectVisible(test, sibling); |
| - expectHidden(test, toHide); |
| - } |
| - |
| - test.done(); |
| -}; |
| + elemHideEmulation.document = testDocument; |
| + elemHideEmulation.MIN_INVOCATION_INTERVAL = REFRESH_INTERVAL / 2; |
| + elemHideEmulation.apply(selectors.map( |
| + selector => ({selector, text: selector}) |
| + )); |
| -function compareExpectations(test, elems, expectations) |
| -{ |
| - for (let elem in expectations) |
| - { |
| - if (elems[elem]) |
| + return elemHideEmulation; |
| + } |
| + catch (error) |
| { |
| - if (expectations[elem]) |
| - expectVisible(test, elems[elem], elem); |
| - else |
| - expectHidden(test, elems[elem], elem); |
| + unexpectedError(error); |
| } |
| } |
| -} |
| -async function runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling(test, selector, expectations) |
| -{ |
| - 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"><span>to hide</span></div> |
| - </div> |
| - <div id="sibling2"> |
| - <div id="sibling21"><div id="sibling211" class="inside"></div></div> |
| - </div> |
| - </div>`; |
| - let elems = { |
| - 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 {}"); |
| - |
| - if (await applyElemHideEmulation(test, [selector])) |
| - compareExpectations(test, elems, expectations); |
| - |
| - test.done(); |
| -} |
| + describe("Verbatim Property Selector", () => |
| + { |
| + it("Regular", async() => |
| + { |
| + let toHide = createElementWithStyle("{background-color: #000}"); |
| + let selectors = [":-abp-properties(background-color: rgb(0, 0, 0))"]; |
| -exports.testPseudoClassHasSelectorWithHasAndWithSuffixSibling = function(test) |
| -{ |
| - let expectations = { |
| - parent: true, |
| - middile: true, |
| - inside: true, |
| - sibling: true, |
| - sibling2: true, |
| - toHide: false |
| - }; |
| - runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling( |
| - test, "div:-abp-has(:-abp-has(div.inside)) + div > div", expectations); |
| -}; |
| + if (await applyElemHideEmulation(selectors)) |
| + expectHidden(toHide); |
| + }); |
| -exports.testPseudoClassHasSelectorWithHasAndWithSuffixSibling2 = function(test) |
| -{ |
| - let expectations = { |
| - parent: true, |
| - middile: true, |
| - inside: true, |
| - sibling: true, |
| - sibling2: true, |
| - toHide: false |
| - }; |
| - runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling( |
| - test, "div:-abp-has(:-abp-has(> div.inside)) + div > div", expectations); |
| -}; |
| + it("With Prefix", async() => |
| + { |
| + let parent = createElementWithStyle("{background-color: #000}"); |
| + let toHide = createElementWithStyle("{background-color: #000}", parent); |
| -exports.testPseudoClassHasSelectorWithHasAndWithSuffixSibling3 = function(test) |
| -{ |
| - let expectations = { |
| - parent: true, |
| - middile: true, |
| - inside: true, |
| - sibling: true, |
| - sibling2: true, |
| - toHide: false |
| - }; |
| - runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling( |
| - test, "div:-abp-has(> div:-abp-has(div.inside)) + div > div", expectations); |
| -}; |
| + let selectors = ["div > :-abp-properties(background-color: rgb(0, 0, 0))"]; |
| -exports.testPseudoClassHasSelectorWithSuffixSiblingNoop = function(test) |
| -{ |
| - let expectations = { |
| - parent: true, |
| - middile: true, |
| - inside: true, |
| - sibling: true, |
| - sibling2: true, |
| - toHide: true |
| - }; |
| - runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling( |
| - test, "div:-abp-has(> body div.inside) + div > div", expectations); |
| -}; |
| - |
| -exports.testPseudoClassHasSelectorWithSuffixSiblingContains = function(test) |
| -{ |
| - let expectations = { |
| - parent: true, |
| - middile: true, |
| - inside: true, |
| - sibling: true, |
| - sibling2: true, |
| - toHide: true |
| - }; |
| - runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling( |
| - test, "div:-abp-has(> span:-abp-contains(Advertisment))", expectations); |
| -}; |
| + if (await applyElemHideEmulation(selectors)) |
| + { |
| + expectVisible(parent); |
| + expectHidden(toHide); |
| + } |
| + }); |
| -async function runTestQualifier(test, selector) |
| -{ |
| - testDocument.body.innerHTML = ` |
| - <style> |
| - span::before { |
| - content: "any"; |
| - } |
| - </style> |
| - <div id="toHide"> |
| - <a> |
| - <p> |
| - <span></span> |
| - </p> |
| - </a> |
| - </div>`; |
| + it("With Prefix No Match", async() => |
| + { |
| + let parent = createElementWithStyle("{background-color: #000}"); |
| + let toHide = createElementWithStyle("{background-color: #fff}", parent); |
| - if (await applyElemHideEmulation(test, [selector])) |
| - expectHidden(test, testDocument.getElementById("toHide")); |
| - |
| - test.done(); |
| -} |
| + let selectors = ["div > :-abp-properties(background-color: rgb(0, 0, 0))"]; |
| -// See issue https://issues.adblockplus.org/ticket/7428 |
| -exports.testPropertySelectorCombinatorQualifier = function(test) |
| -{ |
| - runTestQualifier( |
| - test, |
| - "div:-abp-has(> a p > :-abp-properties(content: \"any\"))" |
| - ); |
| -}; |
| - |
| -// See issue https://issues.adblockplus.org/ticket/7359 |
| -exports.testPropertySelectorCombinatorQualifierNested = function(test) |
| -{ |
| - runTestQualifier( |
| - test, |
| - "div:-abp-has(> a p:-abp-has(> :-abp-properties(content: \"any\")))" |
| - ); |
| -}; |
| - |
| -// See issue https://issues.adblockplus.org/ticket/7400 |
| -exports.testPropertySelectorIdenticalTypeQualifier = function(test) |
| -{ |
| - runTestQualifier( |
| - test, |
| - "div:-abp-has(span:-abp-properties(content: \"any\"))" |
| - ); |
| -}; |
| - |
| -// See issue https://issues.adblockplus.org/ticket/7400 |
| -exports.testPropertySelectorIdenticalTypeQualifierNested = function(test) |
| -{ |
| - runTestQualifier( |
| - test, |
| - "div:-abp-has(p:-abp-has(span:-abp-properties(content: \"any\")))" |
| - ); |
| -}; |
| + if (await applyElemHideEmulation(selectors)) |
| + { |
| + expectVisible(parent); |
| + expectVisible(toHide); |
| + } |
| + }); |
| -async function runTestPseudoClassContains(test, selector, expectations) |
| -{ |
| - 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 \ud83d\ude42!</div> |
| - </div> |
| - <div id="sibling2"> |
| - <div id="sibling21"><div id="sibling211" class="inside">Ad*</div></div> |
| - </div> |
| - </div>`; |
| - let elems = { |
| - parent: testDocument.getElementById("parent"), |
| - middle: testDocument.getElementById("middle"), |
| - inside: testDocument.getElementById("inside"), |
| - sibling: testDocument.getElementById("sibling"), |
| - sibling2: testDocument.getElementById("sibling2"), |
| - toHide: testDocument.getElementById("tohide") |
| - }; |
| + it("With Suffix", async() => |
| + { |
| + let parent = createElementWithStyle("{background-color: #000}"); |
| + let toHide = createElementWithStyle("{background-color: #000}", parent); |
| - if (await applyElemHideEmulation(test, [selector])) |
| - compareExpectations(test, elems, expectations); |
| - |
| - test.done(); |
| -} |
| + let selectors = [":-abp-properties(background-color: rgb(0, 0, 0)) > div"]; |
| -exports.testPseudoClassContainsText = function(test) |
| -{ |
| - let expectations = { |
| - parent: true, |
| - middle: true, |
| - inside: true, |
| - sibling: false, |
| - sibling2: true, |
| - toHide: true |
| - }; |
| - runTestPseudoClassContains( |
| - test, "#parent div:-abp-contains(to hide)", expectations); |
| -}; |
| + if (await applyElemHideEmulation(selectors)) |
| + { |
| + expectVisible(parent); |
| + expectHidden(toHide); |
| + } |
| + }); |
| -exports.testPseudoClassContainsRegexp = function(test) |
| -{ |
| - let expectations = { |
| - parent: true, |
| - middle: true, |
| - inside: true, |
| - sibling: false, |
| - sibling2: true, |
| - toHide: true |
| - }; |
| - runTestPseudoClassContains( |
| - test, "#parent div:-abp-contains(/to\\shide/)", expectations); |
| -}; |
| - |
| -exports.testPseudoClassContainsRegexpIFlag = function(test) |
| -{ |
| - let expectations = { |
| - parent: true, |
| - middle: true, |
| - inside: true, |
| - sibling: false, |
| - sibling2: true, |
| - toHide: true |
| - }; |
| - runTestPseudoClassContains( |
| - test, "#parent div:-abp-contains(/to\\sHide/i)", expectations); |
| -}; |
| -exports.testPseudoClassContainsRegexpUFlag = function(test) |
| -{ |
| - let expectations = { |
| - parent: true, |
| - middle: true, |
| - inside: true, |
| - sibling: false, |
| - sibling2: true, |
| - toHide: true |
| - }; |
| - runTestPseudoClassContains( |
| - test, "#parent div:-abp-contains(/to\\shide\\s.!/u)", expectations); |
| -}; |
| + it("With prefix and suffix", async() => |
| + { |
| + let parent = createElementWithStyle("{background-color: #000}"); |
| + let middle = createElementWithStyle("{background-color: #000}", parent); |
| + let toHide = createElementWithStyle("{background-color: #000}", middle); |
| -exports.testPseudoClassContainsWildcardNoMatch = function(test) |
| -{ |
| - let expectations = { |
| - parent: true, |
| - middle: true, |
| - inside: true, |
| - sibling: true, |
| - sibling2: true, |
| - toHide: true |
| - }; |
| - // this filter shouldn't match anything as "*" has no meaning. |
| - runTestPseudoClassContains( |
| - test, "#parent div:-abp-contains(to *hide)", expectations); |
| -}; |
| - |
| -exports.testPseudoClassContainsWildcardMatch = function(test) |
| -{ |
| - let expectations = { |
| - parent: true, |
| - middle: true, |
| - inside: true, |
| - sibling: true, |
| - sibling2: false, |
| - toHide: true |
| - }; |
| - runTestPseudoClassContains( |
| - test, "#parent div:-abp-contains(Ad*)", expectations); |
| -}; |
| - |
| -exports.testPseudoClassHasSelectorWithPropSelector = async function(test) |
| -{ |
| - let parent = createElementWithStyle("{}"); |
| - let child = createElementWithStyle("{background-color: #000}", parent); |
| + let selectors = ["div > :-abp-properties(background-color: rgb(0, 0, 0)) > div"]; |
| - let selectors = ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0, 0)))"]; |
| - |
| - if (await applyElemHideEmulation(test, selectors)) |
| - { |
| - expectVisible(test, child); |
| - expectHidden(test, parent); |
| - } |
| - |
| - test.done(); |
| -}; |
| + if (await applyElemHideEmulation(selectors)) |
| + { |
| + expectVisible(parent); |
| + expectVisible(middle); |
| + expectHidden(toHide); |
| + } |
| + }); |
| + }); |
| -exports.testPseudoClassHasSelectorWithPropSelector2 = async function(test) |
| -{ |
| - let parent = createElementWithStyle("{}"); |
| - let child = createElementWithStyle("{}", parent); |
| - |
| - let selectors = ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0, 0)))"]; |
| - |
| - insertStyleRule("body #" + parent.id + " > div { background-color: #000}"); |
| - |
| - if (await applyElemHideEmulation(test, selectors)) |
| + // Add the style. Then add the element for that style. |
| + // This should retrigger the filtering and hide it. |
| + it("Property Pseudo Selector Add Style and elemment", async() => |
| { |
| - expectVisible(test, child); |
| - expectHidden(test, parent); |
| - } |
| - |
| - test.done(); |
| -}; |
| - |
| -exports.testDomUpdatesStyle = async function(test) |
| -{ |
| - let parent = createElementWithStyle("{}"); |
| - let child = createElementWithStyle("{}", parent); |
| + let styleElement; |
| + let toHide; |
| - let selectors = ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0, 0)))"]; |
| - |
| - if (await applyElemHideEmulation(test, selectors)) |
| - { |
| - expectVisible(test, child); |
| - expectVisible(test, parent); |
| - |
| - insertStyleRule("body #" + parent.id + " > div { background-color: #000}"); |
| - await timeout(0); |
| - |
| - expectVisible(test, child); |
| - expectVisible(test, parent); |
| - await timeout(REFRESH_INTERVAL); |
| + let selectors = [":-abp-properties(background-color: rgb(0, 0, 0))"]; |
| - expectVisible(test, child); |
| - expectHidden(test, parent); |
| - } |
| - |
| - test.done(); |
| -}; |
| - |
| -exports.testDomUpdatesContent = async function(test) |
| -{ |
| - let parent = createElementWithStyle("{}"); |
| - let child = createElementWithStyle("{}", parent); |
| - |
| - if (await applyElemHideEmulation(test, ["div > div:-abp-contains(hide me)"])) |
| - { |
| - expectVisible(test, parent); |
| - expectVisible(test, child); |
| - |
| - child.textContent = "hide me"; |
| - await timeout(0); |
| - |
| - expectVisible(test, parent); |
| - expectVisible(test, child); |
| - await timeout(REFRESH_INTERVAL); |
| - |
| - expectVisible(test, parent); |
| - expectHidden(test, child); |
| - } |
| - |
| - test.done(); |
| -}; |
| - |
| -exports.testDomUpdatesNewElement = async function(test) |
| -{ |
| - let parent = createElementWithStyle("{}"); |
| - let child = createElementWithStyle("{ background-color: #000}", parent); |
| - let sibling; |
| - let child2; |
| + if (await applyElemHideEmulation(selectors)) |
| + { |
| + styleElement = testDocument.createElement("style"); |
| + testDocument.head.appendChild(styleElement); |
| + styleElement.sheet.insertRule("#toHide {background-color: #000}"); |
| + await timeout(REFRESH_INTERVAL); |
| - let selectors = ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0, 0)))"]; |
| - |
| - if (await applyElemHideEmulation(test, selectors)) |
| - { |
| - expectHidden(test, parent); |
| - expectVisible(test, child); |
| - |
| - sibling = createElementWithStyle("{}"); |
| - await timeout(0); |
| - |
| - expectHidden(test, parent); |
| - expectVisible(test, child); |
| - expectVisible(test, sibling); |
| - |
| - await timeout(REFRESH_INTERVAL); |
| - |
| - expectHidden(test, parent); |
| - expectVisible(test, child); |
| - expectVisible(test, sibling); |
| + toHide = createElement(); |
| + toHide.id = "toHide"; |
| + expectVisible(toHide); |
| + await timeout(REFRESH_INTERVAL); |
| - child2 = createElementWithStyle("{ background-color: #000}", |
| - sibling); |
| - await timeout(0); |
| - |
| - expectVisible(test, child2); |
| - await timeout(REFRESH_INTERVAL); |
| - |
| - expectHidden(test, parent); |
| - expectVisible(test, child); |
| - expectHidden(test, sibling); |
| - expectVisible(test, child2); |
| - } |
| - |
| - test.done(); |
| -}; |
| - |
| -exports.testPseudoClassPropertiesOnStyleSheetLoad = async function(test) |
| -{ |
| - let parent = createElement(); |
| - let child = createElement(parent); |
| + expectHidden(toHide); |
| + } |
| + }); |
| - let selectors = [ |
| - "div:-abp-properties(background-color: rgb(0, 0, 0))", |
| - "div:-abp-contains(hide me)", |
| - "div:-abp-has(> div.hideMe)" |
| - ]; |
| - |
| - if (await applyElemHideEmulation(test, selectors)) |
| - { |
| - await timeout(REFRESH_INTERVAL); |
| - |
| - expectVisible(test, parent); |
| - expectVisible(test, child); |
| - |
| - // Load a style sheet that targets the parent element. This should run only |
| - // the "div:-abp-properties(background-color: rgb(0, 0, 0))" pattern. |
| - insertStyleRule("#" + parent.id + " {background-color: #000}"); |
| - |
| - await timeout(REFRESH_INTERVAL); |
| - |
| - expectHidden(test, parent); |
| - expectVisible(test, child); |
| - } |
| - |
| - test.done(); |
| -}; |
| - |
| -exports.testPlainAttributeOnDomMutation = async function(test) |
| -{ |
| - let parent = createElement(); |
| - let child = createElement(parent); |
| - |
| - let selectors = [ |
| - "div:-abp-properties(background-color: rgb(0, 0, 0))", |
| - "div[data-hide-me]", |
| - "div:-abp-contains(hide me)", |
| - "div:-abp-has(> div.hideMe)" |
| - ]; |
| - |
| - if (await applyElemHideEmulation(test, selectors)) |
| + describe("Property Selector", () => |
| { |
| - await timeout(REFRESH_INTERVAL); |
| - |
| - expectVisible(test, parent); |
| - expectVisible(test, child); |
| + it("With Wildcard", async() => |
| + { |
| + let toHide = createElementWithStyle("{background-color: #000}"); |
| + let selectors = [":-abp-properties(*color: rgb(0, 0, 0))"]; |
| - // Set the "data-hide-me" attribute on the child element. |
| - // |
| - // Note: Since the "div[data-hide-me]" pattern has already been processed |
| - // and the selector added to the document's style sheet, this will in fact |
| - // not do anything at our end, but the browser will just match the selector |
| - // and hide the element. |
| - child.setAttribute("data-hide-me", ""); |
| - |
| - await timeout(REFRESH_INTERVAL); |
| - |
| - expectVisible(test, parent); |
| - expectHidden(test, child); |
| - } |
| + if (await applyElemHideEmulation(selectors)) |
| + expectHidden(toHide); |
| + }); |
| - test.done(); |
| -}; |
| - |
| -exports.testPseudoClassContainsOnDomMutation = async function(test) |
| -{ |
| - let parent = createElement(); |
| - let child = createElement(parent); |
| + it("With regular expression", async() => |
| + { |
| + let toHide = createElementWithStyle("{background-color: #000}"); |
| + let selectors = [":-abp-properties(/.*color: rgb\\(0, 0, 0\\)/)"]; |
| - let selectors = [ |
| - "div:-abp-properties(background-color: rgb(0, 0, 0))", |
| - "div[data-hide-me]", |
| - "div:-abp-contains(hide me)", |
| - "div:-abp-has(> div.hideMe)" |
| - ]; |
| + if (await applyElemHideEmulation(selectors)) |
| + expectHidden(toHide); |
| + }); |
| + }); |
| - child.innerText = "do nothing"; |
| - |
| - if (await applyElemHideEmulation(test, selectors)) |
| + it("Dynamically Changed Property", async() => |
| { |
| - await timeout(REFRESH_INTERVAL); |
| - |
| - expectVisible(test, parent); |
| - expectVisible(test, child); |
| + let toHide = createElementWithStyle("{}"); |
| + let selectors = [":-abp-properties(background-color: rgb(0, 0, 0))"]; |
| - // Set the child element's text to "hide me". This should run only the |
| - // "div:-abp-contains(hide me)" pattern. |
| - // |
| - // Note: We need to set Node.innerText here in order to trigger the |
| - // "characterData" DOM mutation on Chromium. If we set Node.textContent |
| - // instead, it triggers the "childList" DOM mutation instead. |
| - child.innerText = "hide me"; |
| - |
| - await timeout(REFRESH_INTERVAL); |
| - |
| - expectHidden(test, parent); |
| - expectVisible(test, child); |
| - } |
| - |
| - test.done(); |
| -}; |
| + if (await applyElemHideEmulation(selectors)) |
| + { |
| + expectVisible(toHide); |
| + insertStyleRule("#" + toHide.id + " {background-color: #000}"); |
| -exports.testPseudoClassHasOnDomMutation = async function(test) |
| -{ |
| - let parent = createElement(); |
| - let child = null; |
| - |
| - let selectors = [ |
| - "div:-abp-properties(background-color: rgb(0, 0, 0))", |
| - "div[data-hide-me]", |
| - "div:-abp-contains(hide me)", |
| - "div:-abp-has(> div)" |
| - ]; |
| + await timeout(0); |
| - if (await applyElemHideEmulation(test, selectors)) |
| - { |
| - await timeout(REFRESH_INTERVAL); |
| - |
| - expectVisible(test, parent); |
| - |
| - // Add the child element. This should run all the DOM-dependent patterns |
| - // ("div:-abp-contains(hide me)" and "div:-abp-has(> div)"). |
| - child = createElement(parent); |
| - |
| - await timeout(REFRESH_INTERVAL); |
| + // Re-evaluation will only happen after a delay |
| + expectVisible(toHide); |
| + await timeout(REFRESH_INTERVAL); |
| - expectHidden(test, parent); |
| - expectVisible(test, child); |
| - } |
| - |
| - test.done(); |
| -}; |
| + expectHidden(toHide); |
| + } |
| + }); |
| -exports.testPseudoClassHasWithClassOnDomMutation = async function(test) |
| -{ |
| - let parent = createElement(); |
| - let child = createElement(parent); |
| - |
| - let selectors = [ |
| - "div:-abp-properties(background-color: rgb(0, 0, 0))", |
| - "div[data-hide-me]", |
| - "div:-abp-contains(hide me)", |
| - "div:-abp-has(> div.hideMe)" |
| - ]; |
| - |
| - if (await applyElemHideEmulation(test, selectors)) |
| + describe("Pseudo Class", () => |
| { |
| - await timeout(REFRESH_INTERVAL); |
| - |
| - expectVisible(test, parent); |
| - expectVisible(test, child); |
| - |
| - // Set the child element's class to "hideMe". This should run only the |
| - // "div:-abp-has(> div.hideMe)" pattern. |
| - child.className = "hideMe"; |
| - |
| - await timeout(REFRESH_INTERVAL); |
| - |
| - expectHidden(test, parent); |
| - expectVisible(test, child); |
| - } |
| - |
| - test.done(); |
| -}; |
| - |
| -exports.testPseudoClassHasWithPseudoClassContainsOnDomMutation = async function(test) |
| -{ |
| - let parent = createElement(); |
| - let child = createElement(parent); |
| + it("With prop before selector", async() => |
| + { |
| + let parent = createElementWithStyle("{}"); |
| + let child = createElementWithStyle("{background-color: #000}", parent); |
| - let selectors = [ |
| - "div:-abp-properties(background-color: rgb(0, 0, 0))", |
| - "div[data-hide-me]", |
| - "div:-abp-contains(hide me)", |
| - "div:-abp-has(> div:-abp-contains(hide me))" |
| - ]; |
| + let selectors = ["div:-abp-properties(content: \"publicite\")"]; |
| - child.innerText = "do nothing"; |
| - |
| - if (await applyElemHideEmulation(test, selectors)) |
| - { |
| - await timeout(REFRESH_INTERVAL); |
| - |
| - expectVisible(test, parent); |
| - expectVisible(test, child); |
| + insertStyleRule(`#${child.id}::before {content: "publicite"}`); |
| - // Set the child element's text to "hide me". This should run only the |
| - // "div:-abp-contains(hide me)" and |
| - // "div:-abp-has(> div:-abp-contains(hide me))" patterns. |
| - child.innerText = "hide me"; |
| - |
| - await timeout(REFRESH_INTERVAL); |
| - |
| - // Note: Even though it runs both the :-abp-contains() patterns, it only |
| - // hides the parent element because of revision d7d51d29aa34. |
| - expectHidden(test, parent); |
| - expectVisible(test, child); |
| - } |
| - |
| - test.done(); |
| -}; |
| + if (await applyElemHideEmulation(selectors)) |
| + { |
| + expectHidden(child); |
| + expectVisible(parent); |
| + } |
| + }); |
| -exports.testOnlyRelevantElementsProcessed = async function(test) |
| -{ |
| - // <body> |
| - // <div id="n1"> |
| - // <p id="n1_1"></p> |
| - // <p id="n1_2"></p> |
| - // <p id="n1_4">Hello</p> |
| - // </div> |
| - // <div id="n2"> |
| - // <p id="n2_1"></p> |
| - // <p id="n2_2"></p> |
| - // <p id="n2_4">Hello</p> |
| - // </div> |
| - // <div id="n3"> |
| - // <p id="n3_1"></p> |
| - // <p id="n3_2"></p> |
| - // <p id="n3_4">Hello</p> |
| - // </div> |
| - // <div id="n4"> |
| - // <p id="n4_1"></p> |
| - // <p id="n4_2"></p> |
| - // <p id="n4_4">Hello</p> |
| - // </div> |
| - // </body> |
| - for (let i of [1, 2, 3, 4]) |
| - { |
| - let n = createElement(null, "div", `n${i}`); |
| - for (let [j, text] of [[1], [2], [4, "Hello"]]) |
| - createElement(n, "p", `n${i}_${j}`, text); |
| - } |
| - |
| - let selectors = [ |
| - "p:-abp-contains(Hello)", |
| - "div:-abp-contains(Try me!)", |
| - "div:-abp-has(p:-abp-contains(This is good))" |
| - ]; |
| - |
| - if (await applyElemHideEmulation(test, selectors)) |
| - { |
| - await timeout(REFRESH_INTERVAL); |
| - |
| - // This is only a sanity check to make sure everything else is working |
| - // before we do the actual test. |
| - for (let i of [1, 2, 3, 4]) |
| + function compareExpectations(elems, expectations) |
| { |
| - for (let j of [1, 2, 4]) |
| + for (let elem in expectations) |
| { |
| - let id = `n${i}_${j}`; |
| - if (j == 4) |
| - expectHidden(test, testDocument.getElementById(id), id); |
| - else |
| - expectVisible(test, testDocument.getElementById(id), id); |
| + if (elems[elem]) |
| + { |
| + if (expectations[elem]) |
| + expectVisible(elems[elem], elem); |
| + else |
| + expectHidden(elems[elem], elem); |
| + } |
| } |
| } |
| - // All <div> and <p> elements should be processed initially. |
| - for (let element of [...testDocument.getElementsByTagName("div"), |
| - ...testDocument.getElementsByTagName("p")]) |
| + describe("Has Selector", () => |
| + { |
| + it("Simple", async() => |
| + { |
| + let toHide = createElementWithStyle("{}"); |
| + |
| + if (await applyElemHideEmulation(["div:-abp-has(div)"])) |
| + expectVisible(toHide); |
| + }); |
| + |
| + it("With prefix", async() => |
| + { |
| + let parent = createElementWithStyle("{}"); |
| + let child = createElementWithStyle("{}", parent); |
| + |
| + if (await applyElemHideEmulation(["div:-abp-has(div)"])) |
| + { |
| + expectHidden(parent); |
| + expectVisible(child); |
| + } |
| + }); |
| + |
| + it("With suffix", async() => |
| + { |
| + let parent = createElementWithStyle("{}"); |
| + let middle = createElementWithStyle("{}", parent); |
| + let child = createElementWithStyle("{}", middle); |
| + |
| + if (await applyElemHideEmulation(["div:-abp-has(div) > div"])) |
| + { |
| + expectVisible(parent); |
| + expectHidden(middle); |
| + expectHidden(child); |
| + } |
| + }); |
| + |
| + it("With suffix sibling", async() => |
| + { |
| + let parent = createElementWithStyle("{}"); |
| + let middle = createElementWithStyle("{}", parent); |
| + let toHide = createElementWithStyle("{}"); |
| + |
| + if (await applyElemHideEmulation(["div:-abp-has(div) + div"])) |
| + { |
| + expectVisible(parent); |
| + expectVisible(middle); |
| + expectHidden(toHide); |
| + } |
| + }); |
| + |
| + it("With suffix sibling child", async() => |
| + { |
| + // <div> |
| + // <div></div> |
| + // <div> |
| + // <div>to hide</div> |
| + // </div> |
| + // </div> |
| + let parent = createElementWithStyle("{}"); |
| + let middle = createElementWithStyle("{}", parent); |
| + let sibling = createElementWithStyle("{}"); |
| + let toHide = createElementWithStyle("{}", sibling); |
| + |
| + if (await applyElemHideEmulation(["div:-abp-has(div) + div > div"])) |
| + { |
| + expectVisible(parent); |
| + expectVisible(middle); |
| + expectVisible(sibling); |
| + expectHidden(toHide); |
| + } |
| + }); |
| + |
| + async function runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling(selector, expectations) |
| + { |
| + 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"><span>to hide</span></div> |
| + </div> |
| + <div id="sibling2"> |
| + <div id="sibling21"><div id="sibling211" class="inside"></div></div> |
| + </div> |
| + </div>`; |
| + let elems = { |
| + 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 {}"); |
| + if (await applyElemHideEmulation([selector])) |
| + compareExpectations(elems, expectations); |
| + } |
| + |
| + it("With has and with suffix sibling", () => |
| + { |
| + let expectations = { |
| + parent: true, |
| + middile: true, |
| + inside: true, |
| + sibling: true, |
| + sibling2: true, |
| + toHide: false |
| + }; |
| + runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling( |
| + "div:-abp-has(:-abp-has(div.inside)) + div > div", expectations); |
| + }); |
| + |
| + it("With has an with suffix sibling (2)", () => |
| + { |
| + let expectations = { |
| + parent: true, |
| + middile: true, |
| + inside: true, |
| + sibling: true, |
| + sibling2: true, |
| + toHide: false |
| + }; |
| + runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling( |
| + "div:-abp-has(:-abp-has(> div.inside)) + div > div", expectations); |
| + }); |
| + |
| + it("With has an with suffix sibling (3)", () => |
| + { |
| + let expectations = { |
| + parent: true, |
| + middile: true, |
| + inside: true, |
| + sibling: true, |
| + sibling2: true, |
| + toHide: false |
| + }; |
| + runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling( |
| + "div:-abp-has(> div:-abp-has(div.inside)) + div > div", expectations); |
| + }); |
| + |
| + it("With suffix sibling no-op", () => |
| + { |
| + let expectations = { |
| + parent: true, |
| + middile: true, |
| + inside: true, |
| + sibling: true, |
| + sibling2: true, |
| + toHide: true |
| + }; |
| + runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling( |
| + "div:-abp-has(> body div.inside) + div > div", expectations); |
| + }); |
| + |
| + it("With suffix sibling contains", () => |
| + { |
| + let expectations = { |
| + parent: true, |
| + middile: true, |
| + inside: true, |
| + sibling: true, |
| + sibling2: true, |
| + toHide: true |
| + }; |
| + runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling( |
| + "div:-abp-has(> span:-abp-contains(Advertisment))", expectations); |
| + }); |
| + }); |
| + |
| + describe("Property Selector Qualifiers", () => |
| + { |
| + async function runTestQualifier(selector) |
| + { |
| + testDocument.body.innerHTML = ` |
| + <style> |
| + span::before { |
| + content: "any"; |
| + } |
| + </style> |
| + <div id="toHide"> |
| + <a> |
| + <p> |
| + <span></span> |
| + </p> |
| + </a> |
| + </div>`; |
| + |
| + if (await applyElemHideEmulation([selector])) |
| + expectHidden(testDocument.getElementById("toHide")); |
| + } |
| + |
| + // See issue https://issues.adblockplus.org/ticket/7428 |
| + it("Combinator", () => |
| + { |
| + runTestQualifier( |
| + "div:-abp-has(> a p > :-abp-properties(content: \"any\"))" |
| + ); |
| + }); |
| + |
| + // See issue https://issues.adblockplus.org/ticket/7359 |
| + it("Nested Combinator", () => |
| + { |
| + runTestQualifier( |
| + "div:-abp-has(> a p:-abp-has(> :-abp-properties(content: \"any\")))" |
| + ); |
| + }); |
| + |
| + // See issue https://issues.adblockplus.org/ticket/7400 |
| + it("Identical", () => |
| + { |
| + runTestQualifier( |
| + "div:-abp-has(span:-abp-properties(content: \"any\"))" |
| + ); |
| + }); |
| + |
| + // See issue https://issues.adblockplus.org/ticket/7400 |
| + it("Nested Identical", () => |
| + { |
| + runTestQualifier( |
| + "div:-abp-has(p:-abp-has(span:-abp-properties(content: \"any\")))" |
| + ); |
| + }); |
| + }); |
| + |
| + describe("Contains selector", () => |
| + { |
| + async function runTestPseudoClassContains(selector, expectations) |
| + { |
| + 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 \ud83d\ude42!</div> |
| + </div> |
| + <div id="sibling2"> |
| + <div id="sibling21"> |
| + <div id="sibling211" class="inside">Ad*</div> |
| + </div> |
| + </div> |
| + </div>`; |
| + let elems = { |
| + parent: testDocument.getElementById("parent"), |
| + middle: testDocument.getElementById("middle"), |
| + inside: testDocument.getElementById("inside"), |
| + sibling: testDocument.getElementById("sibling"), |
| + sibling2: testDocument.getElementById("sibling2"), |
| + toHide: testDocument.getElementById("tohide") |
| + }; |
| + |
| + if (await applyElemHideEmulation([selector])) |
| + compareExpectations(elems, expectations); |
| + } |
| + |
| + it("Text", () => |
| + { |
| + let expectations = { |
| + parent: true, |
| + middle: true, |
| + inside: true, |
| + sibling: false, |
| + sibling2: true, |
| + toHide: true |
| + }; |
| + runTestPseudoClassContains( |
| + "#parent div:-abp-contains(to hide)", expectations); |
| + }); |
| + |
| + it("Regexp", () => |
| + { |
| + let expectations = { |
| + parent: true, |
| + middle: true, |
| + inside: true, |
| + sibling: false, |
| + sibling2: true, |
| + toHide: true |
| + }; |
| + runTestPseudoClassContains( |
| + "#parent div:-abp-contains(/to\\shide/)", expectations); |
| + }); |
| + |
| + it("Regexp i flag", () => |
| + { |
| + let expectations = { |
| + parent: true, |
| + middle: true, |
| + inside: true, |
| + sibling: false, |
| + sibling2: true, |
| + toHide: true |
| + }; |
| + runTestPseudoClassContains( |
| + "#parent div:-abp-contains(/to\\sHide/i)", expectations); |
| + }); |
| + |
| + it("Regexp u flag", () => |
| + { |
| + let expectations = { |
| + parent: true, |
| + middle: true, |
| + inside: true, |
| + sibling: false, |
| + sibling2: true, |
| + toHide: true |
| + }; |
| + runTestPseudoClassContains( |
| + "#parent div:-abp-contains(/to\\shide\\s.!/u)", expectations); |
| + }); |
| + |
| + it("Wildcard no match", () => |
| + { |
| + let expectations = { |
| + parent: true, |
| + middle: true, |
| + inside: true, |
| + sibling: true, |
| + sibling2: true, |
| + toHide: true |
| + }; |
| + // this filter shouldn't match anything as "*" has no meaning. |
| + runTestPseudoClassContains( |
| + "#parent div:-abp-contains(to *hide)", expectations); |
| + }); |
| + |
| + it("Wildcard match", () => |
| + { |
| + let expectations = { |
| + parent: true, |
| + middle: true, |
| + inside: true, |
| + sibling: true, |
| + sibling2: false, |
| + toHide: true |
| + }; |
| + runTestPseudoClassContains( |
| + "#parent div:-abp-contains(Ad*)", expectations); |
| + }); |
| + }); |
| + |
| + describe("Has Selector with prop selector", () => |
| { |
| - expectProcessed(test, element, element.id); |
| + it("Already present", async() => |
| + { |
| + let parent = createElementWithStyle("{}"); |
| + let child = createElementWithStyle("{background-color: #000}", parent); |
| + |
| + let selectors = ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0, 0)))"]; |
| + |
| + if (await applyElemHideEmulation(selectors)) |
| + { |
| + expectVisible(child); |
| + expectHidden(parent); |
| + } |
| + }); |
| + |
| + it("Dynamically added", async() => |
| + { |
| + let parent = createElementWithStyle("{}"); |
| + let child = createElementWithStyle("{}", parent); |
| + |
| + let selectors = ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0, 0)))"]; |
| + |
| + insertStyleRule("body #" + parent.id + " > div { background-color: #000}"); |
| + |
| + if (await applyElemHideEmulation(selectors)) |
| + { |
| + expectVisible(child); |
| + expectHidden(parent); |
| + } |
| + }); |
| + }); |
| + }); |
| + |
| + describe("DOM updates", () => |
| + { |
| + it("Style", async() => |
| + { |
| + let parent = createElementWithStyle("{}"); |
| + let child = createElementWithStyle("{}", parent); |
| + |
| + let selectors = ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0, 0)))"]; |
| + |
| + if (await applyElemHideEmulation(selectors)) |
| + { |
| + expectVisible(child); |
| + expectVisible(parent); |
| + |
| + insertStyleRule("body #" + parent.id + " > div { background-color: #000}"); |
| + await timeout(0); |
| + |
| + expectVisible(child); |
| + expectVisible(parent); |
| + await timeout(REFRESH_INTERVAL); |
| + |
| + expectVisible(child); |
| + expectHidden(parent); |
| + } |
| + }); |
| + |
| + it("Content", async() => |
| + { |
| + let parent = createElementWithStyle("{}"); |
| + let child = createElementWithStyle("{}", parent); |
| + |
| + if (await applyElemHideEmulation(["div > div:-abp-contains(hide me)"])) |
| + { |
| + expectVisible(parent); |
| + expectVisible(child); |
| + |
| + child.textContent = "hide me"; |
| + await timeout(0); |
| + |
| + expectVisible(parent); |
| + expectVisible(child); |
| + await timeout(REFRESH_INTERVAL); |
| + |
| + expectVisible(parent); |
| + expectHidden(child); |
| + } |
| + }); |
| + |
| + it("New element", async() => |
| + { |
| + let parent = createElementWithStyle("{}"); |
| + let child = createElementWithStyle("{ background-color: #000}", parent); |
| + let sibling; |
| + let child2; |
| + |
| + let selectors = ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0, 0)))"]; |
| + |
| + if (await applyElemHideEmulation(selectors)) |
| + { |
| + expectHidden(parent); |
| + expectVisible(child); |
| + |
| + sibling = createElementWithStyle("{}"); |
| + await timeout(0); |
| + |
| + expectHidden(parent); |
| + expectVisible(child); |
| + expectVisible(sibling); |
| + |
| + await timeout(REFRESH_INTERVAL); |
| + |
| + expectHidden(parent); |
| + expectVisible(child); |
| + expectVisible(sibling); |
| + |
| + child2 = createElementWithStyle("{ background-color: #000}", |
| + sibling); |
| + await timeout(0); |
| + |
| + expectVisible(child2); |
| + await timeout(REFRESH_INTERVAL); |
| + |
| + expectHidden(parent); |
| + expectVisible(child); |
| + expectHidden(sibling); |
| + expectVisible(child2); |
| + } |
| + }); |
| + }); |
| + |
| + it("Pseudo class properties on stylesheet load", async() => |
| + { |
| + let parent = createElement(); |
| + let child = createElement(parent); |
| + |
| + let selectors = [ |
| + "div:-abp-properties(background-color: rgb(0, 0, 0))", |
| + "div:-abp-contains(hide me)", |
| + "div:-abp-has(> div.hideMe)" |
| + ]; |
| + |
| + if (await applyElemHideEmulation(selectors)) |
| + { |
| + await timeout(REFRESH_INTERVAL); |
| + |
| + expectVisible(parent); |
| + expectVisible(child); |
| + |
| + // Load a style sheet that targets the parent element. This should run only |
| + // the "div:-abp-properties(background-color: rgb(0, 0, 0))" pattern. |
| + insertStyleRule("#" + parent.id + " {background-color: #000}"); |
| + |
| + await timeout(REFRESH_INTERVAL); |
| + |
| + expectHidden(parent); |
| + expectVisible(child); |
| + } |
| + }); |
| + |
| + describe("On DOM mutation", () => |
| + { |
| + it("Plain attributes", async() => |
| + { |
| + let parent = createElement(); |
| + let child = createElement(parent); |
| + |
| + let selectors = [ |
| + "div:-abp-properties(background-color: rgb(0, 0, 0))", |
| + "div[data-hide-me]", |
| + "div:-abp-contains(hide me)", |
| + "div:-abp-has(> div.hideMe)" |
| + ]; |
| + |
| + if (await applyElemHideEmulation(selectors)) |
| + { |
| + await timeout(REFRESH_INTERVAL); |
| + |
| + expectVisible(parent); |
| + expectVisible(child); |
| + |
| + // Set the "data-hide-me" attribute on the child element. |
| + // |
| + // Note: Since the "div[data-hide-me]" pattern has already been processed |
| + // and the selector added to the document's style sheet, this will in fact |
| + // not do anything at our end, but the browser will just match the selector |
| + // and hide the element. |
| + child.setAttribute("data-hide-me", ""); |
| + |
| + await timeout(REFRESH_INTERVAL); |
| + |
| + expectVisible(parent); |
| + expectHidden(child); |
| + } |
| + }); |
| + |
| + it("Pseudo class contains", async() => |
| + { |
| + let parent = createElement(); |
| + let child = createElement(parent); |
| + |
| + let selectors = [ |
| + "div:-abp-properties(background-color: rgb(0, 0, 0))", |
| + "div[data-hide-me]", |
| + "div:-abp-contains(hide me)", |
| + "div:-abp-has(> div.hideMe)" |
| + ]; |
| + |
| + child.innerText = "do nothing"; |
| + |
| + if (await applyElemHideEmulation(selectors)) |
| + { |
| + await timeout(REFRESH_INTERVAL); |
| + |
| + expectVisible(parent); |
| + expectVisible(child); |
| + |
| + // Set the child element's text to "hide me". This should run only the |
| + // "div:-abp-contains(hide me)" pattern. |
| + // |
| + // Note: We need to set Node.innerText here in order to trigger the |
| + // "characterData" DOM mutation on Chromium. If we set Node.textContent |
| + // instead, it triggers the "childList" DOM mutation instead. |
| + child.innerText = "hide me"; |
| + |
| + await timeout(REFRESH_INTERVAL); |
| + |
| + expectHidden(parent); |
| + expectVisible(child); |
| + } |
| + }); |
| + |
| + it("Pseudo class has", async() => |
| + { |
| + let parent = createElement(); |
| + let child = null; |
| + |
| + let selectors = [ |
| + "div:-abp-properties(background-color: rgb(0, 0, 0))", |
| + "div[data-hide-me]", |
| + "div:-abp-contains(hide me)", |
| + "div:-abp-has(> div)" |
| + ]; |
| + |
| + if (await applyElemHideEmulation(selectors)) |
| + { |
| + await timeout(REFRESH_INTERVAL); |
| + |
| + expectVisible(parent); |
| + |
| + // Add the child element. This should run all the DOM-dependent patterns |
| + // ("div:-abp-contains(hide me)" and "div:-abp-has(> div)"). |
| + child = createElement(parent); |
| + |
| + await timeout(REFRESH_INTERVAL); |
| + |
| + expectHidden(parent); |
| + expectVisible(child); |
| + } |
| + }); |
| + |
| + it("Pseudo class has", async() => |
| + { |
| + let parent = createElement(); |
| + let child = createElement(parent); |
| + |
| + let selectors = [ |
| + "div:-abp-properties(background-color: rgb(0, 0, 0))", |
| + "div[data-hide-me]", |
| + "div:-abp-contains(hide me)", |
| + "div:-abp-has(> div.hideMe)" |
| + ]; |
| + |
| + if (await applyElemHideEmulation(selectors)) |
| + { |
| + await timeout(REFRESH_INTERVAL); |
| + |
| + expectVisible(parent); |
| + expectVisible(child); |
| + |
| + // Set the child element's class to "hideMe". This should run only the |
| + // "div:-abp-has(> div.hideMe)" pattern. |
| + child.className = "hideMe"; |
| + |
| + await timeout(REFRESH_INTERVAL); |
| + |
| + expectHidden(parent); |
| + expectVisible(child); |
| + } |
| + }); |
| + |
| + it("Pseudo class has with pseudo class contains", async() => |
| + { |
| + let parent = createElement(); |
| + let child = createElement(parent); |
| + |
| + let selectors = [ |
| + "div:-abp-properties(background-color: rgb(0, 0, 0))", |
| + "div[data-hide-me]", |
| + "div:-abp-contains(hide me)", |
| + "div:-abp-has(> div:-abp-contains(hide me))" |
| + ]; |
| + |
| + child.innerText = "do nothing"; |
| + |
| + if (await applyElemHideEmulation(selectors)) |
| + { |
| + await timeout(REFRESH_INTERVAL); |
| + |
| + expectVisible(parent); |
| + expectVisible(child); |
| + |
| + // Set the child element's text to "hide me". This should run only the |
| + // "div:-abp-contains(hide me)" and |
| + // "div:-abp-has(> div:-abp-contains(hide me))" patterns. |
| + child.innerText = "hide me"; |
| + |
| + await timeout(REFRESH_INTERVAL); |
| + |
| + // Note: Even though it runs both the :-abp-contains() patterns, it only |
| + // hides the parent element because of revision d7d51d29aa34. |
| + expectHidden(parent); |
| + expectVisible(child); |
| + } |
| + }); |
| + }); |
| + |
| + it("Only relevant elements are processed", async() => |
| + { |
| + // <body> |
| + // <div id="n1"> |
| + // <p id="n1_1"></p> |
| + // <p id="n1_2"></p> |
| + // <p id="n1_4">Hello</p> |
| + // </div> |
| + // <div id="n2"> |
| + // <p id="n2_1"></p> |
| + // <p id="n2_2"></p> |
| + // <p id="n2_4">Hello</p> |
| + // </div> |
| + // <div id="n3"> |
| + // <p id="n3_1"></p> |
| + // <p id="n3_2"></p> |
| + // <p id="n3_4">Hello</p> |
| + // </div> |
| + // <div id="n4"> |
| + // <p id="n4_1"></p> |
| + // <p id="n4_2"></p> |
| + // <p id="n4_4">Hello</p> |
| + // </div> |
| + // </body> |
| + for (let i of [1, 2, 3, 4]) |
| + { |
| + let n = createElement(null, "div", `n${i}`); |
| + for (let [j, text] of [[1], [2], [4, "Hello"]]) |
| + createElement(n, "p", `n${i}_${j}`, text); |
| } |
| - // Modify the text in <p id="n4_1"> |
| - testDocument.getElementById("n4_1").innerText = "Try me!"; |
| + let selectors = [ |
| + "p:-abp-contains(Hello)", |
| + "div:-abp-contains(Try me!)", |
| + "div:-abp-has(p:-abp-contains(This is good))" |
| + ]; |
| - await timeout(REFRESH_INTERVAL); |
| + if (await applyElemHideEmulation(selectors)) |
| + { |
| + await timeout(REFRESH_INTERVAL); |
| - // When an element's text is modified, only the element or one of its |
| - // ancestors matching any selector is processed for :-abp-has() and |
| - // :-abp-contains() |
| - for (let element of [...testDocument.getElementsByTagName("div"), |
| - ...testDocument.getElementsByTagName("p")]) |
| - { |
| - if (element.id == "n4" || element.id == "n4_1") |
| - expectProcessed(test, element, element.id); |
| - else |
| - expectNotProcessed(test, element, element.id); |
| - } |
| + // This is only a sanity check to make sure everything else is working |
| + // before we do the actual test. |
| + for (let i of [1, 2, 3, 4]) |
| + { |
| + for (let j of [1, 2, 4]) |
| + { |
| + let id = `n${i}_${j}`; |
| + if (j == 4) |
| + expectHidden(testDocument.getElementById(id), id); |
| + else |
| + expectVisible(testDocument.getElementById(id), id); |
| + } |
| + } |
| + |
| + // All <div> and <p> elements should be processed initially. |
| + for (let element of [...testDocument.getElementsByTagName("div"), |
| + ...testDocument.getElementsByTagName("p")]) |
| + { |
| + expectProcessed(element, element.id); |
| + } |
| - // Create a new <p id="n2_3"> element with no text. |
| - createElement(testDocument.getElementById("n2"), "p", "n2_3"); |
| + // Modify the text in <p id="n4_1"> |
| + testDocument.getElementById("n4_1").innerText = "Try me!"; |
| + |
| + await timeout(REFRESH_INTERVAL); |
| - await timeout(REFRESH_INTERVAL); |
| + // When an element's text is modified, only the element or one of its |
| + // ancestors matching any selector is processed for :-abp-has() and |
| + // :-abp-contains() |
| + for (let element of [...testDocument.getElementsByTagName("div"), |
| + ...testDocument.getElementsByTagName("p")]) |
| + { |
| + if (element.id == "n4" || element.id == "n4_1") |
| + expectProcessed(element, element.id); |
| + else |
| + expectNotProcessed(element, element.id); |
| + } |
| - // When a new element is added, only the element or one of its ancestors |
| - // matching any selector is processed for :-abp-has() and :-abp-contains() |
| - for (let element of [...testDocument.getElementsByTagName("div"), |
| - ...testDocument.getElementsByTagName("p")]) |
| - { |
| - if (element.id == "n2" || element.id == "n2_3") |
| - expectProcessed(test, element, element.id); |
| - else |
| - expectNotProcessed(test, element, element.id); |
| + // Create a new <p id="n2_3"> element with no text. |
| + createElement(testDocument.getElementById("n2"), "p", "n2_3"); |
| + |
| + await timeout(REFRESH_INTERVAL); |
| + |
| + // When a new element is added, only the element or one of its ancestors |
| + // matching any selector is processed for :-abp-has() and :-abp-contains() |
| + for (let element of [...testDocument.getElementsByTagName("div"), |
| + ...testDocument.getElementsByTagName("p")]) |
| + { |
| + if (element.id == "n2" || element.id == "n2_3") |
| + expectProcessed(element, element.id); |
| + else |
| + expectNotProcessed(element, element.id); |
| + } |
| } |
| - } |
| - |
| - test.done(); |
| -}; |
| + }); |
| +}); |