Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests for element/attribute name selectors in HTML #13738

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<!doctype html>
<meta charset=utf8>
<title>CSS attribute name selector case-sensitivity</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a <link rel=help> with the relevant spec-link?

<body>
<script>
const xhtmlns = "http://www.w3.org/1999/xhtml";
const svgns = "http://www.w3.org/2000/svg";
const fakens = "http://example.com/i.made.this.up";

const xhtml_doc = document.implementation.createDocument(xhtmlns, "html", null);
const svg_doc = document.implementation.createDocument(svgns, "svg", null);

function pretty_print_name(ns, ln) {
if (ns === xhtmlns)
return "xhtml:" + ln;
if (ns === svgns)
return "svg:" + ln;
if (ns === fakens)
return "fakens:" + ln;

return ns + ":" + ln;
}

function format_element(el) {
return pretty_print_name(el.namespaceURI, el.localName);
}

function get_strings(s) {
switch(s) {
case "lower":
return ["a", "tspan", "madeupelement", "a\u0301"];
case "upper":
return ["A", "TSPAN", "MADEUPELEMENT", "A\u0301"];
case "lower-nonascii":
return ["\u00e5", "\u00e9"];
case "upper-nonascii":
return ["\u00c5", "\u00c9"];
}
}

function get_test_pair(local, selector) {
let locals = get_strings(local);
let selectors = get_strings(selector);

let rv = [];
for (let i = 0; i < locals.length; i++)
rv.push([locals[i], selectors[i]]);

return rv;
}

for (let [doc, isHTML] of [[document, true], [xhtml_doc, false], [svg_doc, false]]) {
let doc_name = format_element(doc.documentElement) + " (" + (isHTML ? "HTML" : "XML") + ")";

let tests = [
{
local: "lower",
selector: "lower",
matches: true,
},
{
local: "lower",
selector: "upper",
matches: false,
matchesHTML: true,
},
{
local: "upper",
selector: "lower",
matches: false,
},
{
local: "upper",
selector: "upper",
matches: true,
matchesHTML: false,
},
{
local: "lower-nonascii",
selector: "lower-nonascii",
matches: true,
},
{
local: "lower-nonascii",
selector: "upper-nonascii",
matches: false,
},
{
local: "upper-nonascii",
selector: "lower-nonascii",
matches: false,
},
{
local: "upper-nonascii",
selector: "upper-nonascii",
matches: true,
},
];

for (let t of tests) {
for (let element_ns of [null, xhtmlns, svgns, fakens]) {
for (let ns of [null, xhtmlns, svgns, fakens]) {
for (let [local, attr_selector] of get_test_pair(t.local, t.selector)) {
selector = "span[" + attr_selector + "]";
test(function() {
let el = doc.createElementNS(element_ns, "span");
doc.documentElement.appendChild(el);
this.add_cleanup(function() { el.remove(); });
el.setAttributeNS(ns, local, "foobar");
let expect_match;
if (ns !== null)
expect_match = false;
else if (element_ns === xhtmlns)
expect_match = (isHTML && "matchesHTML" in t ? t.matchesHTML : t.matches);
else
expect_match = attr_selector === local;
assert_equals(doc.querySelector(selector), expect_match ? el : null);
}, "match " + selector + " with " + pretty_print_name(ns, local) + " attribute on " + pretty_print_name(element_ns, "span") + " element in " + doc_name);
}
}
}
}
}
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<!doctype html>
<meta charset=utf8>
<title>CSS element selector case-sensitivity</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a <link rel=help> with the relevant spec-link?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you don't know, for HTML you can always take the last path segment as a fragment (i.e., #case-sensitivity-of-selectors).

<body>
<script>
const xhtmlns = "http://www.w3.org/1999/xhtml";
const svgns = "http://www.w3.org/2000/svg";
const fakens = "http://example.com/i.made.this.up";

const xhtml_doc = document.implementation.createDocument(xhtmlns, "html", null);
const svg_doc = document.implementation.createDocument(svgns, "svg", null);

function pretty_print_name(ns, ln) {
if (ns === xhtmlns)
return "xhtml:" + ln;
if (ns === svgns)
return "svg:" + ln;
if (ns === fakens)
return "fakens:" + ln;

return ns + ":" + ln;
}

function format_element(el) {
return pretty_print_name(el.namespaceURI, el.localName);
}

function get_strings(s) {
switch(s) {
case "lower":
return ["a", "tspan", "madeupelement", "a\u0301"];
case "upper":
return ["A", "TSPAN", "MADEUPELEMENT", "A\u0301"];
case "lower-nonascii":
return ["\u00e5", "\u00e9"];
case "upper-nonascii":
return ["\u00c5", "\u00c9"];
}
}

function get_test_pair(local, selector) {
let locals = get_strings(local);
let selectors = get_strings(selector);

let rv = [];
for (let i = 0; i < locals.length; i++)
rv.push([locals[i], selectors[i]]);

return rv;
}

for (let [doc, isHTML] of [[document, true], [xhtml_doc, false], [svg_doc, false]]) {
let doc_name = format_element(doc.documentElement) + " (" + (isHTML ? "HTML" : "XML") + ")";

let tests = [
{
local: "lower",
selector: "lower",
matches: true,
},
{
local: "lower",
selector: "upper",
matches: false,
matchesHTML: true,
},
{
local: "upper",
selector: "lower",
matches: false,
},
{
local: "upper",
selector: "upper",
matches: true,
matchesHTML: false,
},
{
local: "lower-nonascii",
selector: "lower-nonascii",
matches: true,
},
{
local: "lower-nonascii",
selector: "upper-nonascii",
matches: false,
},
{
local: "upper-nonascii",
selector: "lower-nonascii",
matches: false,
},
{
local: "upper-nonascii",
selector: "upper-nonascii",
matches: true,
},
];

for (let t of tests) {
for (let ns of [null, xhtmlns, svgns, fakens]) {
for (let [local, selector] of get_test_pair(t.local, t.selector)) {
test(function() {
let el = doc.createElementNS(ns, local);
doc.documentElement.appendChild(el);
this.add_cleanup(function() { el.remove(); });
let expect_match = (isHTML && ns === xhtmlns && "matchesHTML" in t ? t.matchesHTML : t.matches);
assert_equals(doc.querySelector(selector), expect_match ? el : null);
}, "match " + selector + " with " + pretty_print_name(ns, local) + " in " + doc_name);
}
}
}
}
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!doctype html>
<title>Test whether namespace prefixes are lowercased</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this test really belong in css/css-namespaces[1], and isn't this already covered by css/css-namespaces/prefix-001.xml ?

[1] https://drafts.csswg.org/css-namespaces-3/#prefixes

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is testing:

When comparing a CSS element type selector to the names of HTML elements in HTML documents, the CSS element type selector must first be converted to ASCII lowercase. The same selector when compared to other elements must be compared according to its original case. In both cases, the comparison is case-sensitive.

Specifically because of whatwg/html#4155, and whether the whole CSS Qualified Name is lowercased or whether it's just the local part.

Therefore it's different to css/css-namespaces/prefix-001.xml because it's an HTML element in an HTML document.

Let me add a comment to clarify this.

<style>
@namespace xhtml "http://www.w3.org/1999/xhtml";

xhtml|span {
color: rgb(0, 128, 128);
}

XHTML|span {
color: rgb(255, 165, 0);
}
</style>
<span></span>
<div></div>
<!--

This is specifically testing whether the namespace prefix gets lowercased when
comparing element type selectors on HTML elements in HTML documents.

i.e., whether the entire CSS qualified name is lowercased, or whether it's just
the local part (see element-selectors.html for tests about case-sensitivity of
the local part)

-->
<script>
test(function() {
let span = document.querySelector("span");
let cs = window.getComputedStyle(span);
assert_equals(cs.color, "rgb(0, 128, 128)");
}, "element selector");
</script>