Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: test/browser/elemHideEmulation.js

Issue 29383960: Issue 3143 - Filter elements with :-abp-has() (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore
Patch Set: Last comments. Created June 8, 2017, 12:15 a.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« chrome/content/elemHideEmulation.js ('K') | « chrome/content/elemHideEmulation.js ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: test/browser/elemHideEmulation.js
===================================================================
--- a/test/browser/elemHideEmulation.js
+++ b/test/browser/elemHideEmulation.js
@@ -12,25 +12,33 @@
* 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/>.
*/
"use strict";
-/* globals ElemHideEmulation */
+/* globals ElemHideEmulation, splitSelector,
+ parseSelectorContent,
+ parseSelector, positionInParent, makeSelector,
+ PlainSelector, HasSelector, PropsSelector */
let myUrl = document.currentScript.src;
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)
+ document.body.removeChild(child);
Wladimir Palant 2017/06/08 13:12:42 If you store the child in an intermediate variable
hub 2017/06/08 15:45:48 Done.
+
callback();
};
function unexpectedError(error)
{
console.error(error);
this.ok(false, "Unexpected error: " + error);
}
@@ -64,72 +72,328 @@
else
{
styleElement = document.createElement("style");
document.head.appendChild(styleElement);
}
styleElement.sheet.insertRule(rule, styleElement.sheet.cssRules.length);
}
-function createElementWithStyle(styleBlock)
+// insert a <div> with a unique id and and empty CSS rule
Wladimir Palant 2017/06/08 13:12:43 You have "and" twice here. Also, how is this an em
hub 2017/06/08 15:45:50 Done.
+// for the the selector matching the id.
+function createElementWithStyle(styleBlock, parent)
{
let element = document.createElement("div");
element.id = findUniqueId();
- document.body.appendChild(element);
+ if (!parent)
+ document.body.appendChild(element);
+ else
+ parent.appendChild(element);
insertStyleRule("#" + element.id + " " + styleBlock);
return element;
}
-function applyElemHideEmulation(selectors)
+// Will ensure the class ElemHideEmulation is loaded
+// and then will call the callback.
Wladimir Palant 2017/06/08 13:12:41 There are no callbacks here, this function returns
hub 2017/06/08 15:45:50 I forgot to update the comment when we switched th
+// NOTE: if it never loads, this will probably hang in an infinite
+// loop
Wladimir Palant 2017/06/08 13:12:42 There is no loop here. But - yes, loadScript() mig
hub 2017/06/08 15:45:52 Done.
+function loadElemHideEmulation()
{
if (typeof ElemHideEmulation == "undefined")
{
return loadScript(myUrl + "/../../../lib/common.js").then(() =>
{
return loadScript(myUrl + "/../../../chrome/content/elemHideEmulation.js");
}).then(() =>
{
- return applyElemHideEmulation(selectors);
+ return loadElemHideEmulation();
});
}
- let elemHideEmulation = new ElemHideEmulation(
- window,
- callback =>
- {
- let patterns = [];
- selectors.forEach(selector =>
- {
- patterns.push({selector});
- });
- callback(patterns);
- }, newSelectors =>
- {
- if (!newSelectors.length)
- return;
- let selector = newSelectors.join(", ");
- insertStyleRule(selector + "{display: none !important;}");
- }
- );
-
- elemHideEmulation.apply();
return Promise.resolve();
}
+// instantiate a ElemHideEmulation with @selectors.
Wladimir Palant 2017/06/08 13:12:43 "an ElemHideEmulation instance"?
hub 2017/06/08 15:45:48 Done.
+function applyElemHideEmulation(selectors)
+{
+ return loadElemHideEmulation().then(() =>
+ {
+ let elemHideEmulation = new ElemHideEmulation(
+ window,
+ callback =>
+ {
+ let patterns = [];
+ selectors.forEach(selector =>
+ {
+ patterns.push({selector});
+ });
+ callback(patterns);
+ },
+ newSelectors =>
+ {
+ if (!newSelectors.length)
+ return;
+ let selector = newSelectors.join(", ");
+ insertStyleRule(selector + "{display: none !important;}");
+ },
+ elems =>
+ {
+ if (!elems.length)
+ return;
Wladimir Palant 2017/06/08 13:12:42 This check is pointless, we can just let the loop
hub 2017/06/08 15:45:49 Done.
+ for (let elem of elems)
+ elem.style.display = "none";
+ }
+ );
+
+ elemHideEmulation.apply();
+ return Promise.resolve();
Wladimir Palant 2017/06/08 13:12:43 While it was like that before your changes already
hub 2017/06/08 15:45:50 Done.
+ });
+}
+
+exports.testParseSelectorContent = function(test)
+{
+ loadElemHideEmulation().then(() =>
+ {
+ let parsed = parseSelectorContent(":-abp-has(> div) > div", 10);
+ test.equal(parsed.text, "> div");
+ test.equal(parsed.end, 15);
+
+ parsed = parseSelectorContent("\"> div\") > div", 0);
+ test.equal(parsed.text, "\"> div\"");
+ test.equal(parsed.end, 7);
+ parsed = parseSelectorContent(" \"> div\" ) > div", 0);
+ test.equal(parsed.text, " \"> div\" ");
+ test.equal(parsed.end, 9);
+
+ // parens not closed.
+ parsed = parseSelectorContent("> div > div", 0);
+ test.equal(parsed, null);
+ }).catch(unexpectedError.bind(test)).then(() => test.done());
Wladimir Palant 2017/06/08 13:12:40 I'm not really a friend of testing implementation
hub 2017/06/08 15:45:49 I actually think that *also* testing internal func
Wladimir Palant 2017/06/13 13:16:25 As you wish but I certainly won't object to anybod
+};
+
+exports.testParseSelector = function(test)
+{
+ loadElemHideEmulation().then(() =>
+ {
+ let selectors = parseSelector("");
+ test.equal(selectors.length, 0);
+
+ let selector = "div > :-abp-properties('background-color: rgb(0, 0, 0)')";
+ selectors = parseSelector(selector);
+ test.equal(selectors.length, 2);
+ test.ok(selectors[0] instanceof PlainSelector);
+ test.ok(selectors[1] instanceof PropsSelector);
+
+ selector = "div > :-abp-has(> div.inside) > div";
+ selectors = parseSelector(selector);
+ test.equal(selectors.length, 3);
+ test.ok(selectors[0] instanceof PlainSelector);
+ test.ok(selectors[1] instanceof HasSelector);
+ test.ok(selectors[2] instanceof PlainSelector);
+
+ selector = "div > div:-abp-has(> div.inside) > div";
+ selectors = parseSelector(selector);
+
+ test.equal(selectors.length, 3);
+ test.ok(selectors[0] instanceof PlainSelector);
+ test.ok(selectors[1] instanceof HasSelector);
+ test.ok(selectors[2] instanceof PlainSelector);
+
+ selector = "div > :-abp-has(> div.inside) > :-abp-properties(background-color: rgb(0, 0, 0))";
+ selectors = parseSelector(selector);
+
+ test.equal(selectors.length, 4);
+ test.ok(selectors[0] instanceof PlainSelector);
+ test.ok(selectors[1] instanceof HasSelector);
+ test.ok(selectors[2] instanceof PlainSelector);
+ test.ok(selectors[3] instanceof PropsSelector);
+
+ selector = "div > :-abp-has(> div.inside > :-abp-properties(background-color: rgb(0, 0, 0))";
+ selectors = parseSelector(selector);
+ test.equal(selectors, null);
+
+ // -abp-has-unsupported() is unknown. Ensure we fail parsing.
+ selector = 'div[arial-label="Story"]:-abp-has(> div > div > span > span:-abp-unsupported("Suggested Post"))';
+ selectors = parseSelector(selector);
+ test.equal(selectors, null);
+ }).catch(unexpectedError.bind(test)).then(() => test.done());
+};
+
+function buildDom(doc)
+{
+ doc.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 middle1 = document.getElementById("middle1");
+ let inside = document.getElementById("inside");
+ let sibling = document.getElementById("sibling");
+ let sibling2 = document.getElementById("sibling2");
+ let toHide = document.getElementById("tohide");
+ return {parent, middle, middle1, inside, sibling, sibling2, toHide};
+}
+
+exports.testPositionInParent = function(test)
+{
+ let nodes = buildDom(document);
+
+ loadElemHideEmulation().then(() =>
+ {
+ test.equal(positionInParent(nodes.middle1), 1);
+ test.equal(positionInParent(nodes.inside), 1);
+ test.equal(positionInParent(nodes.sibling2), 3);
+ }).catch(unexpectedError.bind(test)).then(() => test.done());
+};
+
+exports.testMakeSelector = function(test)
+{
+ let nodes = buildDom(document);
+
+ loadElemHideEmulation().then(() =>
+ {
+ test.equal(makeSelector(nodes.middle, ""),
+ ":root > BODY:nth-child(2) > DIV:nth-child(1) > DIV:nth-child(1)");
+ test.equal(makeSelector(nodes.toHide, ""),
+ ":root > BODY:nth-child(2) > DIV:nth-child(1) > DIV:nth-child(2) > DIV:nth-child(1)");
+ }).catch(unexpectedError.bind(test)).then(() => test.done());
+};
+
+exports.testPlainSelector = function(test)
+{
+ buildDom(document);
+
+ loadElemHideEmulation().then(() =>
+ {
+ let selector = new PlainSelector("div > div");
+
+ let iter = selector.getSelectors("foo > ");
+ let value = iter.next();
+ test.equal(value.value[0], "foo > div > div");
+ test.ok(iter.next().done);
+ }).catch(unexpectedError.bind(test)).then(() => test.done());
+};
+
+exports.testHasSelector = function(test)
+{
+ buildDom(document);
+
+ loadElemHideEmulation().then(() =>
+ {
+ let selector = new HasSelector("> div.inside");
+
+ let iter = selector.getSelectors("", document, document.sheet);
+ let value = iter.next();
+ test.ok(!value.done);
+ test.equal(value.value[0],
+ ":root > BODY:nth-child(2) > DIV:nth-child(1) > DIV:nth-child(1) > DIV:nth-child(1)");
+
+ iter = selector.getElements("", document, document.sheet);
+ value = iter.next();
+ test.ok(!value.done);
+ test.equal(value.value.id, "middle1");
+ value = iter.next();
+ test.ok(!value.done);
+ test.equal(value.value.id, "sibling21");
+ value = iter.next();
+ test.ok(value.done);
+
+ selector = new HasSelector(":-abp-has(> div.inside)");
+
+ test.ok(selector._innerSelectors);
+ }).catch(unexpectedError.bind(test)).then(() => test.done());
+};
+
+exports.testSplitStyleRule = function(test)
+{
+ loadElemHideEmulation().then(() =>
+ {
+ let selectors = splitSelector("div:-abp-has(div) > [-abp-properties='background-color: rgb(0, 0, 0)'] > span");
+ test.ok(selectors);
+ test.equal(selectors.length, 1, "There is only one selector");
+
+ selectors = splitSelector("div:-abp-has(div), [-abp-properties='background-color: rgb(0, 0, 0)']");
+ test.ok(selectors);
+ test.equal(selectors.length, 2, "There are two selectors");
+ }).catch(unexpectedError.bind(test)).then(() => test.done());
+};
+
exports.testVerbatimPropertySelector = function(test)
{
let toHide = createElementWithStyle("{background-color: #000}");
applyElemHideEmulation(
[":-abp-properties(background-color: rgb(0, 0, 0))"]
).then(() =>
{
expectHidden(test, toHide);
}).catch(unexpectedError.bind(test)).then(() => test.done());
};
+exports.testVerbatimPropertySelectorWithPrefix = function(test)
+{
+ let parent = createElementWithStyle("{background-color: #000}");
+ let toHide = createElementWithStyle("{background-color: #000}", parent);
+ applyElemHideEmulation(
+ ["div > :-abp-properties(background-color: rgb(0, 0, 0))"]
+ ).then(() =>
+ {
+ expectVisible(test, parent);
+ expectHidden(test, toHide);
+ }).catch(unexpectedError.bind(test)).then(() => test.done());
+};
+
+exports.testVerbatimPropertySelectorWithPrefixNoMatch = function(test)
+{
+ let parent = createElementWithStyle("{background-color: #000}");
+ let toHide = createElementWithStyle("{background-color: #fff}", parent);
+ applyElemHideEmulation(
+ ["div > :-abp-properties(background-color: rgb(0, 0, 0))"]
+ ).then(() =>
+ {
+ expectVisible(test, parent);
+ expectVisible(test, toHide);
+ }).catch(unexpectedError.bind(test)).then(() => test.done());
+};
+
+exports.testVerbatimPropertySelectorWithSuffix = function(test)
+{
+ let parent = createElementWithStyle("{background-color: #000}");
+ let toHide = createElementWithStyle("{background-color: #000}", parent);
+ applyElemHideEmulation(
+ [":-abp-properties(background-color: rgb(0, 0, 0)) > div"]
+ ).then(() =>
+ {
+ expectVisible(test, parent);
+ expectHidden(test, toHide);
+ }).catch(unexpectedError.bind(test)).then(() => test.done());
+};
+
+exports.testVerbatimPropertyPseudoSelectorWithPrefixAndSuffix = function(test)
+{
+ let parent = createElementWithStyle("{background-color: #000}");
+ let middle = createElementWithStyle("{background-color: #000}", parent);
+ let toHide = createElementWithStyle("{background-color: #000}", middle);
+ applyElemHideEmulation(
+ ["div > :-abp-properties(background-color: rgb(0, 0, 0)) > div"]
+ ).then(() =>
+ {
+ expectVisible(test, parent);
+ expectVisible(test, middle);
+ expectHidden(test, toHide);
+ }).catch(unexpectedError.bind(test)).then(() => test.done());
+};
+
exports.testPropertySelectorWithWildcard = function(test)
{
let toHide = createElementWithStyle("{background-color: #000}");
applyElemHideEmulation(
[":-abp-properties(*color: rgb(0, 0, 0))"]
).then(() =>
{
expectHidden(test, toHide);
@@ -183,8 +447,143 @@
window.setTimeout(() =>
{
expectHidden(test, toHide);
resolve();
}, 0);
});
}).catch(unexpectedError.bind(test)).then(() => test.done());
};
+
+exports.testPseudoClassHasSelector = function(test)
+{
+ let toHide = createElementWithStyle("{}");
+ applyElemHideEmulation(
+ ["div:-abp-has(div)"]
+ ).then(() =>
+ {
+ expectVisible(test, toHide);
+ }).catch(unexpectedError.bind(test)).then(() => test.done());
+};
+
+exports.testPseudoClassHasSelectorWithPrefix = function(test)
+{
+ let parent = createElementWithStyle("{}");
+ let child = createElementWithStyle("{}", parent);
+ applyElemHideEmulation(
+ ["div:-abp-has(div)"]
+ ).then(() =>
+ {
+ expectHidden(test, parent);
+ expectVisible(test, child);
+ }).catch(unexpectedError.bind(test)).then(() => test.done());
+};
+
+exports.testPseudoClassHasSelectorWithSuffix = function(test)
+{
+ let parent = createElementWithStyle("{}");
+ let middle = createElementWithStyle("{}", parent);
+ let child = createElementWithStyle("{}", middle);
+ applyElemHideEmulation(
+ ["div:-abp-has(div) > div"]
+ ).then(() =>
+ {
+ expectVisible(test, parent);
+ expectHidden(test, middle);
+ expectHidden(test, child);
+ }).catch(unexpectedError.bind(test)).then(() => test.done());
+};
+
+exports.testPseudoClassHasSelectorWithSuffixSibling = function(test)
+{
+ let parent = createElementWithStyle("{}");
+ let middle = createElementWithStyle("{}", parent);
+ let toHide = createElementWithStyle("{}");
+ applyElemHideEmulation(
+ ["div:-abp-has(div) + div"]
+ ).then(() =>
+ {
+ expectVisible(test, parent);
+ expectVisible(test, middle);
+ expectHidden(test, toHide);
+ }).catch(unexpectedError.bind(test)).then(() => test.done());
+};
+
+exports.testPseudoClassHasSelectorWithSuffixSiblingChild = 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);
+ applyElemHideEmulation(
+ ["div:-abp-has(div) + div > div"]
+ ).then(() =>
+ {
+ expectVisible(test, parent);
+ expectVisible(test, middle);
+ expectVisible(test, sibling);
+ expectHidden(test, toHide);
+ }).catch(unexpectedError.bind(test)).then(() => test.done());
+};
+
+function runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling(test, selector)
+{
+ document.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");
+
+ insertStyleRule(".inside {}");
+
+ applyElemHideEmulation(
+ [selector]
+ ).then(() =>
+ {
+ expectVisible(test, parent);
+ expectVisible(test, middle);
+ expectVisible(test, inside);
+ expectVisible(test, sibling);
+ expectVisible(test, sibling2);
+ expectHidden(test, toHide);
+ }).catch(unexpectedError.bind(test)).then(() => test.done());
+}
+
+exports.testPseudoClassHasSelectorWithHasAndWithSuffixSibling = function(test)
+{
+ runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling(test, "div:-abp-has(:-abp-has(div.inside)) + div > div");
+};
+
+exports.testPseudoClassHasSelectorWithHasAndWithSuffixSibling2 = function(test)
+{
+ runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling(test, "div:-abp-has(:-abp-has(> div.inside)) + div > div");
+};
+
+exports.testPseudoClassHasSelectorWithPropSelector = 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(() =>
+ {
+ expectVisible(test, child);
+ expectHidden(test, parent);
+ }).catch(unexpectedError.bind(test)).then(() => test.done());
+};
« chrome/content/elemHideEmulation.js ('K') | « chrome/content/elemHideEmulation.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld