fix(spec): keep a tag selector valid beside another key

a multi-key object selector concatenates its parts into one compound,
and a type selector is valid only at the head of one, so {id, tag} built
'[id="amount"]input' and querySelectorAll threw. whether a spec got an
exception or an element depended on the order its author wrote the keys
in.
This commit is contained in:
pj committed 2026-08-18 20:43:20 +05:30
1 parent f7135b81d8
commit d177726c4e
2 files changed
+18 -1

No files matched your search

+7 -1
View File
@@ -199,9 +199,15 @@ const TAG_NAME = /^[a-zA-Z][a-zA-Z0-9-]*$/;
// pseudo-class like `*:hover`, a comma, whitespace) would inject CSS into the
// surrounding selector. Returning a never-matching selector rather than
// throwing keeps the spec running while making the typo visible in logs.
//
// Wrapped in `:is()` because a multi-key selector concatenates the parts into
// one compound, where a type selector is valid only at the head: `{id, tag}`
// built `[id="amount"]input`, which is a parse error, so querySelectorAll threw
// rather than answering with nothing, and which of the two a spec got depended
// on the order its author wrote the keys in.
function tagSelector(value: string): string {
if (!TAG_NAME.test(value)) return ":not(*)";
return value;
return `:is(${value})`;
}
// SELECTOR_KEYS is every key an object selector may use, held identical to the
+11
View File
@@ -523,6 +523,17 @@ test("selectorFromObject composes testTag with a second key", () => {
});
});
// A type selector is valid only at the HEAD of a compound, so `tag` written
// after any other key built `[id="amount"]input` and querySelectorAll threw a
// SyntaxError: what the spec sees is an exception out of the extractor rather
// than an element, and which of the two it gets depends on the order the author
// happened to write the keys in.
test("selectorFromObject composes tag with a second key", () => {
assert.deepEqual(selectorFromObject({ id: "amount", tag: "input" }), {
css: `[id="amount"]:is(input)`,
});
});
// A list whose rows are named <role>_<record id> is only reachable by the role
// half. internal/driver/chrome/translate.go builds the same CSS for the same
// selector, and internal/hierarchy resolves it against the dump of this page.