202 lines
4.9 KiB
JavaScript
202 lines
4.9 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
"use strict";
|
|
|
|
const {
|
|
parsePseudoClassesAndAttributes,
|
|
SELECTOR_ATTRIBUTE,
|
|
SELECTOR_ELEMENT,
|
|
SELECTOR_PSEUDO_CLASS,
|
|
} = require("resource://devtools/shared/css/parsing-utils.js");
|
|
|
|
const TEST_DATA = [
|
|
// Test that a null input throws an exception
|
|
{
|
|
input: null,
|
|
throws: true,
|
|
},
|
|
// Test that a undefined input throws an exception
|
|
{
|
|
input: undefined,
|
|
throws: true,
|
|
},
|
|
{
|
|
input: ":root",
|
|
expected: [{ value: ":root", type: SELECTOR_PSEUDO_CLASS }],
|
|
},
|
|
{
|
|
input: ".testclass",
|
|
expected: [{ value: ".testclass", type: SELECTOR_ELEMENT }],
|
|
},
|
|
{
|
|
input: "div p",
|
|
expected: [{ value: "div p", type: SELECTOR_ELEMENT }],
|
|
},
|
|
{
|
|
input: "div > p",
|
|
expected: [{ value: "div > p", type: SELECTOR_ELEMENT }],
|
|
},
|
|
{
|
|
input: "a[hidden]",
|
|
expected: [
|
|
{ value: "a", type: SELECTOR_ELEMENT },
|
|
{ value: "[hidden]", type: SELECTOR_ATTRIBUTE },
|
|
],
|
|
},
|
|
{
|
|
input: "a[hidden=true]",
|
|
expected: [
|
|
{ value: "a", type: SELECTOR_ELEMENT },
|
|
{ value: "[hidden=true]", type: SELECTOR_ATTRIBUTE },
|
|
],
|
|
},
|
|
{
|
|
input: "a[hidden=true] p:hover",
|
|
expected: [
|
|
{ value: "a", type: SELECTOR_ELEMENT },
|
|
{ value: "[hidden=true]", type: SELECTOR_ATTRIBUTE },
|
|
{ value: " p", type: SELECTOR_ELEMENT },
|
|
{ value: ":hover", type: SELECTOR_PSEUDO_CLASS },
|
|
],
|
|
},
|
|
{
|
|
input: 'a[checked="true"]',
|
|
expected: [
|
|
{ value: "a", type: SELECTOR_ELEMENT },
|
|
{ value: '[checked="true"]', type: SELECTOR_ATTRIBUTE },
|
|
],
|
|
},
|
|
{
|
|
input: "a[title~=test]",
|
|
expected: [
|
|
{ value: "a", type: SELECTOR_ELEMENT },
|
|
{ value: "[title~=test]", type: SELECTOR_ATTRIBUTE },
|
|
],
|
|
},
|
|
{
|
|
input: 'h1[hidden="true"][title^="Important"]',
|
|
expected: [
|
|
{ value: "h1", type: SELECTOR_ELEMENT },
|
|
{ value: '[hidden="true"]', type: SELECTOR_ATTRIBUTE },
|
|
{ value: '[title^="Important"]', type: SELECTOR_ATTRIBUTE },
|
|
],
|
|
},
|
|
{
|
|
input: "p:hover",
|
|
expected: [
|
|
{ value: "p", type: SELECTOR_ELEMENT },
|
|
{ value: ":hover", type: SELECTOR_PSEUDO_CLASS },
|
|
],
|
|
},
|
|
{
|
|
input: "p + .testclass:hover",
|
|
expected: [
|
|
{ value: "p + .testclass", type: SELECTOR_ELEMENT },
|
|
{ value: ":hover", type: SELECTOR_PSEUDO_CLASS },
|
|
],
|
|
},
|
|
{
|
|
input: "p::before",
|
|
expected: [
|
|
{ value: "p", type: SELECTOR_ELEMENT },
|
|
{ value: "::before", type: SELECTOR_PSEUDO_CLASS },
|
|
],
|
|
},
|
|
{
|
|
input: "p:nth-child(2)",
|
|
expected: [
|
|
{ value: "p", type: SELECTOR_ELEMENT },
|
|
{ value: ":nth-child(2)", type: SELECTOR_PSEUDO_CLASS },
|
|
],
|
|
},
|
|
{
|
|
input: 'p:not([title="test"]) .testclass',
|
|
expected: [
|
|
{ value: "p", type: SELECTOR_ELEMENT },
|
|
{ value: ':not([title="test"])', type: SELECTOR_PSEUDO_CLASS },
|
|
{ value: " .testclass", type: SELECTOR_ELEMENT },
|
|
],
|
|
},
|
|
{
|
|
input: "a\\:hover",
|
|
expected: [{ value: "a\\:hover", type: SELECTOR_ELEMENT }],
|
|
},
|
|
{
|
|
input: ":not(:lang(it))",
|
|
expected: [{ value: ":not(:lang(it))", type: SELECTOR_PSEUDO_CLASS }],
|
|
},
|
|
{
|
|
input: "p:not(:lang(it))",
|
|
expected: [
|
|
{ value: "p", type: SELECTOR_ELEMENT },
|
|
{ value: ":not(:lang(it))", type: SELECTOR_PSEUDO_CLASS },
|
|
],
|
|
},
|
|
{
|
|
input: "p:not(p:lang(it))",
|
|
expected: [
|
|
{ value: "p", type: SELECTOR_ELEMENT },
|
|
{ value: ":not(p:lang(it))", type: SELECTOR_PSEUDO_CLASS },
|
|
],
|
|
},
|
|
{
|
|
input: ":not(:lang(it)",
|
|
expected: [{ value: ":not(:lang(it)", type: SELECTOR_ELEMENT }],
|
|
},
|
|
{
|
|
input: ":not(:lang(it)))",
|
|
expected: [
|
|
{ value: ":not(:lang(it))", type: SELECTOR_PSEUDO_CLASS },
|
|
{ value: ")", type: SELECTOR_ELEMENT },
|
|
],
|
|
},
|
|
];
|
|
|
|
function run_test() {
|
|
for (const test of TEST_DATA) {
|
|
dump("Test input string " + test.input + "\n");
|
|
let output;
|
|
|
|
try {
|
|
output = parsePseudoClassesAndAttributes(test.input);
|
|
} catch (e) {
|
|
dump(
|
|
"parsePseudoClassesAndAttributes threw an exception with the " +
|
|
"given input string\n"
|
|
);
|
|
if (test.throws) {
|
|
ok(true, "Exception expected");
|
|
} else {
|
|
dump();
|
|
ok(false, "Exception unexpected\n" + e);
|
|
}
|
|
}
|
|
|
|
if (output) {
|
|
assertOutput(output, test.expected);
|
|
}
|
|
}
|
|
}
|
|
|
|
function assertOutput(actual, expected) {
|
|
if (actual.length === expected.length) {
|
|
for (let i = 0; i < expected.length; i++) {
|
|
dump("Check that the output item has the expected value and type\n");
|
|
ok(!!actual[i]);
|
|
equal(expected[i].value, actual[i].value);
|
|
equal(expected[i].type, actual[i].type);
|
|
}
|
|
} else {
|
|
for (const prop of actual) {
|
|
dump(
|
|
"Actual output contained: {value: " +
|
|
prop.value +
|
|
", type: " +
|
|
prop.type +
|
|
"}\n"
|
|
);
|
|
}
|
|
equal(actual.length, expected.length);
|
|
}
|
|
}
|