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

Unified Diff: test/elemHide.js

Issue 30025555: Issue 6820 - Move tests to mocha (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore/
Patch Set: Rebased Created April 10, 2019, 6:33 p.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
« no previous file with comments | « test/domainRestrictions.js ('k') | test/filterClasses.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: test/elemHide.js
===================================================================
--- a/test/elemHide.js
+++ b/test/elemHide.js
@@ -12,337 +12,340 @@
* 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";
+const assert = require("assert");
const {createSandbox} = require("./_common");
let ElemHide = null;
let createStyleSheet = null;
let rulesFromStyleSheet = null;
let ElemHideExceptions = null;
let Filter = null;
let filtersByDomain = null;
let selectorGroupSize = null;
-exports.setUp = function(callback)
-{
- let sandboxedRequire = createSandbox({
- extraExports: {
- elemHide: ["filtersByDomain", "selectorGroupSize"]
- }
- });
- (
- {ElemHide, createStyleSheet, rulesFromStyleSheet,
- filtersByDomain, selectorGroupSize} = sandboxedRequire("../lib/elemHide"),
- {ElemHideExceptions} = sandboxedRequire("../lib/elemHideExceptions"),
- {Filter} = sandboxedRequire("../lib/filterClasses")
- );
-
- callback();
-};
-
-function normalizeSelectors(selectors)
+describe("ElemHide", () =>
{
- // generateStyleSheetForDomain is currently allowed to return duplicate
- // selectors for performance reasons, so we need to remove duplicates here.
- return selectors.slice().sort().filter((selector, index, sortedSelectors) =>
+ beforeEach(() =>
+ {
+ let sandboxedRequire = createSandbox({
+ extraExports: {
+ elemHide: ["filtersByDomain", "selectorGroupSize"]
+ }
+ });
+ (
+ {ElemHide, createStyleSheet, rulesFromStyleSheet,
+ filtersByDomain, selectorGroupSize} = sandboxedRequire("../lib/elemHide"),
+ {ElemHideExceptions} = sandboxedRequire("../lib/elemHideExceptions"),
+ {Filter} = sandboxedRequire("../lib/filterClasses")
+ );
+ });
+
+ function normalizeSelectors(selectors)
+ {
+ // generateStyleSheetForDomain is currently allowed to return duplicate
+ // selectors for performance reasons, so we need to remove duplicates here.
+ return selectors.slice().sort().filter((selector, index, sortedSelectors) =>
+ {
+ return index == 0 || selector != sortedSelectors[index - 1];
+ });
+ }
+
+ function testResult(domain, expectedSelectors,
+ {specificOnly = false, expectedExceptions = []} = {})
+ {
+ let normalizedExpectedSelectors = normalizeSelectors(expectedSelectors);
+
+ let {code, selectors, exceptions} =
+ ElemHide.generateStyleSheetForDomain(domain, specificOnly, true, true);
+
+ assert.deepEqual(normalizeSelectors(selectors), normalizedExpectedSelectors);
+
+ // Test for consistency in exception free case.
+ assert.deepEqual(ElemHide.generateStyleSheetForDomain(
+ domain, specificOnly, true, false), {
+ code,
+ selectors,
+ exceptions: null
+ });
+
+ assert.deepEqual(exceptions.map(({text}) => text), expectedExceptions);
+
+ // Make sure each expected selector is in the actual CSS code.
+ for (let selector of normalizedExpectedSelectors)
+ {
+ assert.ok(code.includes(selector + ", ") ||
+ code.includes(selector + " {display: none !important;}\n"));
+ }
+ }
+
+ it("Generating Style Sheet", () =>
{
- return index == 0 || selector != sortedSelectors[index - 1];
- });
-}
+ let addFilter = filterText => ElemHide.add(Filter.fromText(filterText));
+ let removeFilter =
+ filterText => ElemHide.remove(Filter.fromText(filterText));
+ let addException =
+ filterText => ElemHideExceptions.add(Filter.fromText(filterText));
+ let removeException =
+ filterText => ElemHideExceptions.remove(Filter.fromText(filterText));
+
+ testResult("", []);
+
+ addFilter("~foo.example.com,example.com##foo");
+ testResult("barfoo.example.com", ["foo"]);
+ testResult("bar.foo.example.com", []);
+ testResult("foo.example.com", []);
+ testResult("example.com", ["foo"]);
+ testResult("com", []);
+ testResult("", []);
+
+ addFilter("foo.example.com##turnip");
+ testResult("foo.example.com", ["turnip"]);
+ testResult("example.com", ["foo"]);
+ testResult("com", []);
+ testResult("", []);
+
+ addException("example.com#@#foo");
+ testResult("foo.example.com", ["turnip"]);
+ testResult("example.com", [], {
+ expectedExceptions: ["example.com#@#foo"]
+ });
+ testResult("com", []);
+ testResult("", []);
+
+ addFilter("com##bar");
+ testResult("foo.example.com", ["turnip", "bar"]);
+ testResult("example.com", ["bar"], {
+ expectedExceptions: ["example.com#@#foo"]
+ });
+ testResult("com", ["bar"]);
+ testResult("", []);
+
+ addException("example.com#@#bar");
+ testResult("foo.example.com", ["turnip"], {
+ expectedExceptions: ["example.com#@#bar"]
+ });
+ testResult("example.com", [], {
+ expectedExceptions: ["example.com#@#foo", "example.com#@#bar"]
+ });
+ testResult("com", ["bar"]);
+ testResult("", []);
+
+ removeException("example.com#@#foo");
+ testResult("foo.example.com", ["turnip"], {
+ expectedExceptions: ["example.com#@#bar"]
+ });
+ testResult("example.com", ["foo"], {
+ expectedExceptions: ["example.com#@#bar"]
+ });
+ testResult("com", ["bar"]);
+ testResult("", []);
+
+ removeException("example.com#@#bar");
+ testResult("foo.example.com", ["turnip", "bar"]);
+ testResult("example.com", ["foo", "bar"]);
+ testResult("com", ["bar"]);
+ testResult("", []);
+
+ addFilter("##generic");
+ testResult("foo.example.com", ["turnip", "bar", "generic"]);
+ testResult("example.com", ["foo", "bar", "generic"]);
+ testResult("com", ["bar", "generic"]);
+ testResult("", ["generic"]);
+ testResult("foo.example.com", ["turnip", "bar"], {specificOnly: true});
+ testResult("example.com", ["foo", "bar"], {specificOnly: true});
+ testResult("com", ["bar"], {specificOnly: true});
+ testResult("", [], {specificOnly: true});
+ removeFilter("##generic");
+
+ addFilter("~adblockplus.org##example");
+ testResult("adblockplus.org", []);
+ testResult("", ["example"]);
+ testResult("foo.example.com", ["turnip", "bar", "example"]);
+ testResult("foo.example.com", ["turnip", "bar"], {specificOnly: true});
+ removeFilter("~adblockplus.org##example");
-function testResult(test, domain, expectedSelectors,
- {specificOnly = false, expectedExceptions = []} = {})
-{
- let normalizedExpectedSelectors = normalizeSelectors(expectedSelectors);
+ removeFilter("~foo.example.com,example.com##foo");
+ testResult("foo.example.com", ["turnip", "bar"]);
+ testResult("example.com", ["bar"]);
+ testResult("com", ["bar"]);
+ testResult("", []);
+
+ removeFilter("com##bar");
+ testResult("foo.example.com", ["turnip"]);
+ testResult("example.com", []);
+ testResult("com", []);
+ testResult("", []);
+
+ removeFilter("foo.example.com##turnip");
+ testResult("foo.example.com", []);
+ testResult("example.com", []);
+ testResult("com", []);
+ testResult("", []);
+
+ addFilter("example.com##dupe");
+ addFilter("example.com##dupe");
+ testResult("example.com", ["dupe"]);
+ removeFilter("example.com##dupe");
+ testResult("example.com", []);
+ removeFilter("example.com##dupe");
+
+ addFilter("~foo.example.com,example.com##foo");
- let {code, selectors, exceptions} =
- ElemHide.generateStyleSheetForDomain(domain, specificOnly, true, true);
+ addFilter("##foo");
+ testResult("foo.example.com", ["foo"]);
+ testResult("example.com", ["foo"]);
+ testResult("com", ["foo"]);
+ testResult("", ["foo"]);
+ removeFilter("##foo");
+
+ addFilter("example.org##foo");
+ testResult("foo.example.com", []);
+ testResult("example.com", ["foo"]);
+ testResult("com", []);
+ testResult("", []);
+ removeFilter("example.org##foo");
+
+ addFilter("~example.com##foo");
+ testResult("foo.example.com", []);
+ testResult("example.com", ["foo"]);
+ testResult("com", ["foo"]);
+ testResult("", ["foo"]);
+ removeFilter("~example.com##foo");
+
+ removeFilter("~foo.example.com,example.com##foo");
+
+ // Test criteria
+ addFilter("##hello");
+ addFilter("~example.com##world");
+ addFilter("foo.com##specific");
+ testResult("foo.com", ["specific"], {specificOnly: true});
+ testResult("foo.com", ["hello", "specific", "world"]);
+ testResult("example.com", [], {specificOnly: true});
+ removeFilter("foo.com##specific");
+ removeFilter("~example.com##world");
+ removeFilter("##hello");
+ testResult("foo.com", []);
- test.deepEqual(normalizeSelectors(selectors), normalizedExpectedSelectors);
+ addFilter("##hello");
+ testResult("foo.com", [], {specificOnly: true});
+ testResult("foo.com", ["hello"]);
+ testResult("bar.com", [], {specificOnly: true});
+ testResult("bar.com", ["hello"]);
+ addException("foo.com#@#hello");
+ testResult("foo.com", [], {specificOnly: true});
+ testResult("foo.com", [], {expectedExceptions: ["foo.com#@#hello"]});
+ testResult("bar.com", [], {specificOnly: true});
+ testResult("bar.com", ["hello"]);
+ removeException("foo.com#@#hello");
+ testResult("foo.com", [], {specificOnly: true});
+ // Note: We don't take care to track conditional selectors which became
+ // unconditional when a filter was removed. This was too expensive.
+ testResult("foo.com", ["hello"]);
+ testResult("bar.com", [], {specificOnly: true});
+ testResult("bar.com", ["hello"]);
+ removeFilter("##hello");
+ testResult("foo.com", []);
+ testResult("bar.com", []);
+
+ addFilter("##hello");
+ addFilter("foo.com##hello");
+ testResult("foo.com", ["hello"]);
+ removeFilter("foo.com##hello");
+ testResult("foo.com", ["hello"]);
+ removeFilter("##hello");
+ testResult("foo.com", []);
+
+ addFilter("##hello");
+ addFilter("foo.com##hello");
+ testResult("foo.com", ["hello"]);
+ removeFilter("##hello");
+ testResult("foo.com", ["hello"]);
+ removeFilter("foo.com##hello");
+ testResult("foo.com", []);
+ });
- // Test for consistency in exception free case.
- test.deepEqual(ElemHide.generateStyleSheetForDomain(
- domain, specificOnly, true, false), {
- code,
- selectors,
- exceptions: null
+ it("Zero filter key", () =>
+ {
+ ElemHide.add(Filter.fromText("##test"));
+ ElemHideExceptions.add(Filter.fromText("foo.com#@#test"));
+ testResult("foo.com", [], {expectedExceptions: ["foo.com#@#test"]});
+ testResult("bar.com", ["test"]);
+ });
+
+ it("Filters by Domain", () =>
+ {
+ assert.equal(filtersByDomain.size, 0);
+
+ ElemHide.add(Filter.fromText("##test"));
+ assert.equal(filtersByDomain.size, 0);
+
+ ElemHide.add(Filter.fromText("example.com##test"));
+ assert.equal(filtersByDomain.size, 1);
+
+ ElemHide.add(Filter.fromText("example.com,~www.example.com##test"));
+ assert.equal(filtersByDomain.size, 2);
+
+ ElemHide.remove(Filter.fromText("example.com##test"));
+ assert.equal(filtersByDomain.size, 2);
+
+ ElemHide.remove(Filter.fromText("example.com,~www.example.com##test"));
+ assert.equal(filtersByDomain.size, 0);
+ });
+
+ describe("Creating Stylesheet", () =>
+ {
+ it("Basic creation", () =>
+ {
+ assert.equal(
+ createStyleSheet([
+ "html", "#foo", ".bar", "#foo .bar", "#foo > .bar",
+ "#foo[data-bar='bar']"
+ ]),
+ "html, #foo, .bar, #foo .bar, #foo > .bar, #foo[data-bar='bar'] " +
+ "{display: none !important;}\n",
+ "Style sheet creation should work"
+ );
});
- test.deepEqual(exceptions.map(({text}) => text), expectedExceptions);
-
- // Make sure each expected selector is in the actual CSS code.
- for (let selector of normalizedExpectedSelectors)
- {
- test.ok(code.includes(selector + ", ") ||
- code.includes(selector + " {display: none !important;}\n"));
- }
-}
-
-exports.testGenerateStyleSheetForDomain = function(test)
-{
- let addFilter = filterText => ElemHide.add(Filter.fromText(filterText));
- let removeFilter = filterText => ElemHide.remove(Filter.fromText(filterText));
- let addException =
- filterText => ElemHideExceptions.add(Filter.fromText(filterText));
- let removeException =
- filterText => ElemHideExceptions.remove(Filter.fromText(filterText));
-
- testResult(test, "", []);
-
- addFilter("~foo.example.com,example.com##foo");
- testResult(test, "barfoo.example.com", ["foo"]);
- testResult(test, "bar.foo.example.com", []);
- testResult(test, "foo.example.com", []);
- testResult(test, "example.com", ["foo"]);
- testResult(test, "com", []);
- testResult(test, "", []);
-
- addFilter("foo.example.com##turnip");
- testResult(test, "foo.example.com", ["turnip"]);
- testResult(test, "example.com", ["foo"]);
- testResult(test, "com", []);
- testResult(test, "", []);
-
- addException("example.com#@#foo");
- testResult(test, "foo.example.com", ["turnip"]);
- testResult(test, "example.com", [], {
- expectedExceptions: ["example.com#@#foo"]
- });
- testResult(test, "com", []);
- testResult(test, "", []);
-
- addFilter("com##bar");
- testResult(test, "foo.example.com", ["turnip", "bar"]);
- testResult(test, "example.com", ["bar"], {
- expectedExceptions: ["example.com#@#foo"]
- });
- testResult(test, "com", ["bar"]);
- testResult(test, "", []);
-
- addException("example.com#@#bar");
- testResult(test, "foo.example.com", ["turnip"], {
- expectedExceptions: ["example.com#@#bar"]
- });
- testResult(test, "example.com", [], {
- expectedExceptions: ["example.com#@#foo", "example.com#@#bar"]
- });
- testResult(test, "com", ["bar"]);
- testResult(test, "", []);
+ it("Splitting", () =>
+ {
+ let selectors = new Array(50000).fill().map((element, index) => ".s" + index);
- removeException("example.com#@#foo");
- testResult(test, "foo.example.com", ["turnip"], {
- expectedExceptions: ["example.com#@#bar"]
- });
- testResult(test, "example.com", ["foo"], {
- expectedExceptions: ["example.com#@#bar"]
- });
- testResult(test, "com", ["bar"]);
- testResult(test, "", []);
-
- removeException("example.com#@#bar");
- testResult(test, "foo.example.com", ["turnip", "bar"]);
- testResult(test, "example.com", ["foo", "bar"]);
- testResult(test, "com", ["bar"]);
- testResult(test, "", []);
-
- addFilter("##generic");
- testResult(test, "foo.example.com", ["turnip", "bar", "generic"]);
- testResult(test, "example.com", ["foo", "bar", "generic"]);
- testResult(test, "com", ["bar", "generic"]);
- testResult(test, "", ["generic"]);
- testResult(test, "foo.example.com", ["turnip", "bar"], {specificOnly: true});
- testResult(test, "example.com", ["foo", "bar"], {specificOnly: true});
- testResult(test, "com", ["bar"], {specificOnly: true});
- testResult(test, "", [], {specificOnly: true});
- removeFilter("##generic");
-
- addFilter("~adblockplus.org##example");
- testResult(test, "adblockplus.org", []);
- testResult(test, "", ["example"]);
- testResult(test, "foo.example.com", ["turnip", "bar", "example"]);
- testResult(test, "foo.example.com", ["turnip", "bar"], {specificOnly: true});
- removeFilter("~adblockplus.org##example");
-
- removeFilter("~foo.example.com,example.com##foo");
- testResult(test, "foo.example.com", ["turnip", "bar"]);
- testResult(test, "example.com", ["bar"]);
- testResult(test, "com", ["bar"]);
- testResult(test, "", []);
-
- removeFilter("com##bar");
- testResult(test, "foo.example.com", ["turnip"]);
- testResult(test, "example.com", []);
- testResult(test, "com", []);
- testResult(test, "", []);
-
- removeFilter("foo.example.com##turnip");
- testResult(test, "foo.example.com", []);
- testResult(test, "example.com", []);
- testResult(test, "com", []);
- testResult(test, "", []);
-
- addFilter("example.com##dupe");
- addFilter("example.com##dupe");
- testResult(test, "example.com", ["dupe"]);
- removeFilter("example.com##dupe");
- testResult(test, "example.com", []);
- removeFilter("example.com##dupe");
-
- addFilter("~foo.example.com,example.com##foo");
-
- addFilter("##foo");
- testResult(test, "foo.example.com", ["foo"]);
- testResult(test, "example.com", ["foo"]);
- testResult(test, "com", ["foo"]);
- testResult(test, "", ["foo"]);
- removeFilter("##foo");
-
- addFilter("example.org##foo");
- testResult(test, "foo.example.com", []);
- testResult(test, "example.com", ["foo"]);
- testResult(test, "com", []);
- testResult(test, "", []);
- removeFilter("example.org##foo");
+ assert.equal((createStyleSheet(selectors).match(/\n/g) || []).length,
+ Math.ceil(50000 / selectorGroupSize),
+ "Style sheet should be split up into rules with at most " +
+ selectorGroupSize + " selectors each");
+ });
- addFilter("~example.com##foo");
- testResult(test, "foo.example.com", []);
- testResult(test, "example.com", ["foo"]);
- testResult(test, "com", ["foo"]);
- testResult(test, "", ["foo"]);
- removeFilter("~example.com##foo");
-
- removeFilter("~foo.example.com,example.com##foo");
-
- // Test criteria
- addFilter("##hello");
- addFilter("~example.com##world");
- addFilter("foo.com##specific");
- testResult(test, "foo.com", ["specific"], {specificOnly: true});
- testResult(test, "foo.com", ["hello", "specific", "world"]);
- testResult(test, "example.com", [], {specificOnly: true});
- removeFilter("foo.com##specific");
- removeFilter("~example.com##world");
- removeFilter("##hello");
- testResult(test, "foo.com", []);
-
- addFilter("##hello");
- testResult(test, "foo.com", [], {specificOnly: true});
- testResult(test, "foo.com", ["hello"]);
- testResult(test, "bar.com", [], {specificOnly: true});
- testResult(test, "bar.com", ["hello"]);
- addException("foo.com#@#hello");
- testResult(test, "foo.com", [], {specificOnly: true});
- testResult(test, "foo.com", [], {expectedExceptions: ["foo.com#@#hello"]});
- testResult(test, "bar.com", [], {specificOnly: true});
- testResult(test, "bar.com", ["hello"]);
- removeException("foo.com#@#hello");
- testResult(test, "foo.com", [], {specificOnly: true});
- // Note: We don't take care to track conditional selectors which became
- // unconditional when a filter was removed. This was too expensive.
- testResult(test, "foo.com", ["hello"]);
- testResult(test, "bar.com", [], {specificOnly: true});
- testResult(test, "bar.com", ["hello"]);
- removeFilter("##hello");
- testResult(test, "foo.com", []);
- testResult(test, "bar.com", []);
-
- addFilter("##hello");
- addFilter("foo.com##hello");
- testResult(test, "foo.com", ["hello"]);
- removeFilter("foo.com##hello");
- testResult(test, "foo.com", ["hello"]);
- removeFilter("##hello");
- testResult(test, "foo.com", []);
-
- addFilter("##hello");
- addFilter("foo.com##hello");
- testResult(test, "foo.com", ["hello"]);
- removeFilter("##hello");
- testResult(test, "foo.com", ["hello"]);
- removeFilter("foo.com##hello");
- testResult(test, "foo.com", []);
-
- test.done();
-};
+ it("Escaping", () =>
+ {
+ assert.equal(
+ createStyleSheet([
+ "html", "#foo", ".bar", "#foo .bar", "#foo > .bar",
+ "#foo[data-bar='{foo: 1}']"
+ ]),
+ "html, #foo, .bar, #foo .bar, #foo > .bar, " +
+ "#foo[data-bar='\\7B foo: 1\\7D '] {display: none !important;}\n",
+ "Braces should be escaped"
+ );
+ });
+ });
-exports.testZeroFilterKey = function(test)
-{
- ElemHide.add(Filter.fromText("##test"));
- ElemHideExceptions.add(Filter.fromText("foo.com#@#test"));
- testResult(test, "foo.com", [], {expectedExceptions: ["foo.com#@#test"]});
- testResult(test, "bar.com", ["test"]);
- test.done();
-};
-
-exports.testFiltersByDomain = function(test)
-{
- test.equal(filtersByDomain.size, 0);
-
- ElemHide.add(Filter.fromText("##test"));
- test.equal(filtersByDomain.size, 0);
-
- ElemHide.add(Filter.fromText("example.com##test"));
- test.equal(filtersByDomain.size, 1);
-
- ElemHide.add(Filter.fromText("example.com,~www.example.com##test"));
- test.equal(filtersByDomain.size, 2);
-
- ElemHide.remove(Filter.fromText("example.com##test"));
- test.equal(filtersByDomain.size, 2);
-
- ElemHide.remove(Filter.fromText("example.com,~www.example.com##test"));
- test.equal(filtersByDomain.size, 0);
-
- test.done();
-};
+ it("Rules from StyleSheet", () =>
+ {
+ // Note: The rulesFromStyleSheet function assumes that each rule will be
+ // terminated with a newline character, including the last rule. If this is
+ // not the case, the function goes into an infinite loop. It should only be
+ // used with the return value of the createStyleSheet function.
-exports.testCreateStyleSheet = function(test)
-{
- test.equal(
- createStyleSheet([
- "html", "#foo", ".bar", "#foo .bar", "#foo > .bar",
- "#foo[data-bar='bar']"
- ]),
- "html, #foo, .bar, #foo .bar, #foo > .bar, #foo[data-bar='bar'] " +
- "{display: none !important;}\n",
- "Style sheet creation should work"
- );
-
- let selectors = new Array(50000).fill().map((element, index) => ".s" + index);
-
- test.equal((createStyleSheet(selectors).match(/\n/g) || []).length,
- Math.ceil(50000 / selectorGroupSize),
- "Style sheet should be split up into rules with at most " +
- selectorGroupSize + " selectors each");
-
- test.equal(
- createStyleSheet([
- "html", "#foo", ".bar", "#foo .bar", "#foo > .bar",
- "#foo[data-bar='{foo: 1}']"
- ]),
- "html, #foo, .bar, #foo .bar, #foo > .bar, " +
- "#foo[data-bar='\\7B foo: 1\\7D '] {display: none !important;}\n",
- "Braces should be escaped"
- );
-
- test.done();
-};
-
-exports.testRulesFromStyleSheet = function(test)
-{
- // Note: The rulesFromStyleSheet function assumes that each rule will be
- // terminated with a newline character, including the last rule. If this is
- // not the case, the function goes into an infinite loop. It should only be
- // used with the return value of the createStyleSheet function.
-
- test.deepEqual([...rulesFromStyleSheet("")], []);
- test.deepEqual([...rulesFromStyleSheet("#foo {}\n")], ["#foo {}"]);
- test.deepEqual([...rulesFromStyleSheet("#foo {}\n#bar {}\n")],
- ["#foo {}", "#bar {}"]);
-
- test.done();
-};
+ assert.deepEqual([...rulesFromStyleSheet("")], []);
+ assert.deepEqual([...rulesFromStyleSheet("#foo {}\n")], ["#foo {}"]);
+ assert.deepEqual([...rulesFromStyleSheet("#foo {}\n#bar {}\n")],
+ ["#foo {}", "#bar {}"]);
+ });
+});
« no previous file with comments | « test/domainRestrictions.js ('k') | test/filterClasses.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld