Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

<!doctype html>
<!-- Any copyright is dedicated to the Public Domain.
<html>
<head>
<meta charset="utf-8" />
<title>Test Panel List Access Key Conflicts</title>
<link
rel="stylesheet"
/>
</head>
<body>
<p id="display"></p>
<div id="content">
<button id="anchor">Anchor</button>
<panel-list id="distinct">
<panel-item accesskey="o">One</panel-item>
<panel-item accesskey="t">Two</panel-item>
</panel-list>
<panel-list id="none">
<panel-item>One</panel-item>
<panel-item>Two</panel-item>
</panel-list>
<panel-list id="duplicate">
<panel-item accesskey="t">Two</panel-item>
<panel-item accesskey="T">Three</panel-item>
<panel-item accesskey="f">Four</panel-item>
</panel-list>
<panel-list id="mixed">
<panel-item accesskey="o">One</panel-item>
<panel-item>Two</panel-item>
<panel-item>Three</panel-item>
</panel-list>
<panel-list id="hidden">
<panel-item accesskey="o">One</panel-item>
<panel-item hidden="">Two</panel-item>
</panel-list>
<panel-list id="disabled">
<panel-item accesskey="o">One</panel-item>
<panel-item disabled="">Two</panel-item>
<panel-item accesskey="o" disabled="">Four</panel-item>
</panel-list>
<panel-list id="tracked" accesskey-conflicts-bug="2073885">
<panel-item accesskey="o">One</panel-item>
<panel-item accesskey="o">Two</panel-item>
<panel-item>Three</panel-item>
</panel-list>
<panel-list id="intended">
<panel-item accesskey="o">One</panel-item>
<panel-item accesskey="o" intended-duplicate-accesskey=""
>Two</panel-item
>
<panel-item accesskey="o">Four</panel-item>
</panel-list>
<panel-list id="intended-only">
<panel-item accesskey="o">One</panel-item>
<panel-item accesskey="o" intended-duplicate-accesskey=""
>Two</panel-item
>
</panel-list>
<panel-list id="translated">
<panel-item accesskey="c">Close</panel-item>
<panel-item
id="translated-item"
data-l10n-attrs="accesskey"
></panel-item>
</panel-list>
<panel-list id="auto">
<panel-item accesskey="c">Copy</panel-item>
<panel-item auto-accesskey="">correct</panel-item>
<panel-item auto-accesskey="">🦊 Fox</panel-item>
</panel-list>
<panel-list id="auto-disabled-keyed">
<panel-item accesskey="p" disabled="">Paste</panel-item>
<panel-item>Manage</panel-item>
<panel-item auto-accesskey="">Run</panel-item>
</panel-list>
<panel-list id="auto-others-unkeyed">
<panel-item>Manage</panel-item>
<panel-item auto-accesskey="">Move</panel-item>
</panel-list>
</div>
<script class="testbody" type="application/javascript">
const { BrowserTestUtils } = ChromeUtils.importESModule(
);
const { Assert } = ChromeUtils.importESModule(
);
const assert = new Assert((err, message) =>
ok(!err, err ? err.message : message)
);
const { checkAccessKeys } = ChromeUtils.importESModule(
"chrome://global/content/elements/accesskey-check.mjs",
{ global: "current" }
);
async function openAndCollectErrors(id, whileOpen) {
let errors = [];
let sentinel = new Promise(resolve => {
SpecialPowers.registerConsoleListener(msg => {
if (msg.message == "SENTINEL") {
resolve();
} else if (
msg.errorMessage?.startsWith("AccessKeyConflictError:")
) {
errors.push(msg.errorMessage);
}
});
});
let panelList = document.getElementById(id);
let shown = BrowserTestUtils.waitForEvent(panelList, "shown");
panelList.show(null, document.getElementById("anchor"));
await shown;
await whileOpen?.(panelList);
let hidden = BrowserTestUtils.waitForEvent(panelList, "hidden");
panelList.hide(undefined, { force: true });
await hidden;
SpecialPowers.postConsoleSentinel();
await sentinel;
return errors;
}
add_setup(async function setup() {
await customElements.whenDefined("panel-list");
await customElements.whenDefined("panel-item");
L10nRegistry.getInstance().registerSources([
L10nFileSource.createMock(
"accesskey-test",
"app",
["en-US"],
"/localization/{locale}/",
[
{
path: "/localization/en-US/accesskey-test.ftl",
source: `
check-for-updates = Check for Updates
.accesskey = C
`,
},
]
),
]);
SimpleTest.registerCleanupFunction(() =>
L10nRegistry.getInstance().removeSources(["accesskey-test"])
);
let link = document.createElement("link");
link.rel = "localization";
link.href = "accesskey-test.ftl";
document.head.append(link);
});
add_task(async function testDistinctAccessKeys() {
is(
(await openAndCollectErrors("distinct")).length,
0,
"Distinct accesskeys on every item are fine"
);
});
add_task(async function testNoAccessKeys() {
is(
(await openAndCollectErrors("none")).length,
0,
"No accesskey on any item is fine"
);
});
add_task(async function testDuplicateAccessKey() {
let errors = await openAndCollectErrors("duplicate");
is(errors.length, 1, "A shared accesskey is reported once");
assert.stringContains(
errors[0],
`panel-list#duplicate: accesskey "t" is shared by "Two", "Three"`,
"Message names the key and both items"
);
assert.stringContains(
errors[0],
"Fix a shared accesskey",
"Message recommends remedies for the problem it found"
);
ok(
!errors[0].includes("Fix a missing accesskey"),
"Message recommends nothing for a problem it didn't find"
);
});
add_task(async function testIntendedDuplicate() {
let errors = await openAndCollectErrors("intended");
is(
errors.length,
1,
"Unmarked items sharing the key are still reported"
);
assert.stringContains(
errors[0],
`accesskey "o" is shared by "One", "Four"`,
"Unmarked items sharing the key are reported"
);
ok(
!errors[0].includes("Two"),
"An item with intended-duplicate-accesskey is left out"
);
is(
(await openAndCollectErrors("intended-only")).length,
0,
"A key shared only with a marked item is not a conflict"
);
});
add_task(async function testAutoAccessKeys() {
let items = [...document.querySelectorAll("#auto [auto-accesskey]")];
is(
(await openAndCollectErrors("auto")).length,
0,
"An item with auto-accesskey may share its accesskey"
);
assert.deepEqual(
items.map(item => item.label.accessKey),
["c", "F"],
"Each item gets its label's first typeable letter"
);
});
add_task(async function testAutoAccessKeysDisabledItem() {
await openAndCollectErrors("auto-disabled-keyed");
is(
document.querySelector("#auto-disabled-keyed [auto-accesskey]").label
.accessKey,
"R",
"A disabled item with an accesskey counts as another item with an accesskey"
);
});
add_task(async function testAutoAccessKeysOthersUnkeyed() {
let item = document.querySelector(
"#auto-others-unkeyed [auto-accesskey]"
);
is(
(await openAndCollectErrors("auto-others-unkeyed")).length,
0,
"A panel-list without accesskeys gets none for its auto-accesskey items"
);
ok(
!item.hasAttribute("accesskey"),
"The item doesn't take the first letter of another item's label"
);
});
add_task(async function testMixedAccessKeys() {
let errors = await openAndCollectErrors("mixed");
is(
errors.length,
1,
"Mixing items with and without an accesskey is reported once"
);
assert.stringContains(
errors[0],
`"Two", "Three" have no accesskey while "One" does`,
"Message names the items on both sides"
);
assert.stringContains(
errors[0],
"Fix a missing accesskey",
"Message recommends remedies for the problem it found"
);
ok(
!errors[0].includes("Fix a shared accesskey"),
"Message recommends nothing for a problem it didn't find"
);
});
add_task(async function testHiddenItemIgnored() {
is(
(await openAndCollectErrors("hidden")).length,
0,
"A hidden item doesn't count as an item without an accesskey"
);
});
add_task(async function testTrackedMenuSkipped() {
is(
(await openAndCollectErrors("tracked")).length,
0,
"A panel-list naming its accesskey-conflicts bug is skipped"
);
});
add_task(async function testDisabledItems() {
let errors = await openAndCollectErrors("disabled");
is(errors.length, 1, "Disabled items are checked like any other");
assert.stringContains(
errors[0],
`accesskey "o" is shared by "One", "Four"`,
"A disabled item counts for a shared accesskey"
);
assert.stringContains(
errors[0],
`"Two" has no accesskey`,
"A disabled item counts for a missing accesskey"
);
});
add_task(async function testPendingTranslation() {
let item = document.getElementById("translated-item");
let errors = await openAndCollectErrors("translated", panelList => {
document.l10n.setAttributes(item, "check-for-updates");
ok(document.hasPendingL10nMutations, "Translation is pending");
return checkAccessKeys(panelList);
});
is(
item.label.textContent,
"Check for Updates",
"The item got its translation"
);
is(errors.length, 1, "The check waits for the pending translation");
assert.stringContains(
errors[0],
`accesskey "c" is shared by "Close", "Check for Updates"`,
"The translated item is compared"
);
});
</script>
</body>
</html>