491 lines
16 KiB
HTML
491 lines
16 KiB
HTML
<!doctype html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<title>MozVisualPicker Tests</title>
|
|
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
|
<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
|
<link rel="stylesheet" href="chrome://global/skin/in-content/common.css" />
|
|
<link
|
|
rel="stylesheet"
|
|
href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
|
/>
|
|
<script
|
|
type="module"
|
|
src="chrome://global/content/elements/moz-visual-picker.mjs"
|
|
></script>
|
|
<script src="lit-test-helpers.js"></script>
|
|
<style>
|
|
.slotted {
|
|
height: 72px;
|
|
width: 72px;
|
|
border-radius: var(--border-radius-medium);
|
|
background-color: var(--background-color-box);
|
|
padding: var(--space-medium);
|
|
}
|
|
</style>
|
|
<script>
|
|
let html;
|
|
let defaultTemplate;
|
|
let testHelpers = new InputTestHelpers();
|
|
|
|
add_setup(async function setup() {
|
|
({ html } = await testHelpers.setupLit());
|
|
let templateFn = attrs => html`
|
|
<moz-visual-picker ${attrs}>
|
|
<moz-visual-picker-item checked value="first">
|
|
<div class="slotted">In the slot</div>
|
|
</moz-visual-picker-item>
|
|
<moz-visual-picker-item value="second">
|
|
<div class="slotted">In the slot</div>
|
|
</moz-visual-picker-item>
|
|
<moz-visual-picker-item value="third">
|
|
<div class="slotted">In the slot</div>
|
|
</moz-visual-picker-item>
|
|
</moz-visual-picker>
|
|
`;
|
|
defaultTemplate = templateFn(
|
|
testHelpers.spread({ label: "Visual picker label" })
|
|
);
|
|
testHelpers.setupTests({ templateFn });
|
|
});
|
|
|
|
add_task(async function testVisualPickerProperties() {
|
|
const TEST_LABEL = "Testing...";
|
|
const TEST_DESCRIPTION = "Testing description..";
|
|
const TEST_SUPPORT_PAGE = "Testing support page..";
|
|
let renderTarget = await testHelpers.renderTemplate(defaultTemplate);
|
|
let picker = renderTarget.querySelector("moz-visual-picker");
|
|
|
|
is(
|
|
picker.fieldset.label,
|
|
"Visual picker label",
|
|
"Visual picker supports a label."
|
|
);
|
|
picker.label = TEST_LABEL;
|
|
picker.description = TEST_DESCRIPTION;
|
|
picker.supportPage = TEST_SUPPORT_PAGE;
|
|
await picker.updateComplete;
|
|
is(
|
|
picker.fieldset.label,
|
|
TEST_LABEL,
|
|
"Visual picker label is updated."
|
|
);
|
|
is(
|
|
picker.fieldset.description,
|
|
TEST_DESCRIPTION,
|
|
"Visual picker description text is set."
|
|
);
|
|
is(
|
|
picker.fieldset.supportPage,
|
|
TEST_SUPPORT_PAGE,
|
|
"Visual picker support page is set."
|
|
);
|
|
});
|
|
|
|
add_task(async function testChangingPickerValue() {
|
|
let renderTarget = await testHelpers.renderTemplate(defaultTemplate);
|
|
let picker = renderTarget.querySelector("moz-visual-picker");
|
|
let items = [
|
|
...renderTarget.querySelectorAll("moz-visual-picker-item"),
|
|
];
|
|
let [firstItem, secondItem, thirdItem] = items;
|
|
|
|
function verifySelectedPickerItem(selectedItem, setsFocus) {
|
|
ok(selectedItem.checked, "The selected picker item is checked.");
|
|
is(
|
|
selectedItem.itemEl.getAttribute("aria-checked"),
|
|
"true",
|
|
"The checked item has the correct aria-checked value."
|
|
);
|
|
is(
|
|
selectedItem.itemEl.tabIndex,
|
|
0,
|
|
"The selected picker item is focusable."
|
|
);
|
|
if (setsFocus) {
|
|
is(
|
|
document.activeElement,
|
|
selectedItem,
|
|
"The selected picker item is focused."
|
|
);
|
|
}
|
|
items
|
|
.filter(item => item !== selectedItem)
|
|
.forEach(item => {
|
|
ok(!item.checked, "All other picker items are unchecked.");
|
|
is(
|
|
item.itemEl.getAttribute("aria-checked"),
|
|
"false",
|
|
"All other items have the correct aria-checked value."
|
|
);
|
|
is(
|
|
item.itemEl.tabIndex,
|
|
-1,
|
|
"All other items are not focusable."
|
|
);
|
|
});
|
|
is(
|
|
picker.value,
|
|
selectedItem.value,
|
|
"Picker value matches the value of the checked item."
|
|
);
|
|
}
|
|
|
|
// Verify the initial state.
|
|
verifySelectedPickerItem(firstItem);
|
|
|
|
// Verify changing the checked property directly.
|
|
secondItem.checked = true;
|
|
await picker.updateComplete;
|
|
verifySelectedPickerItem(secondItem);
|
|
|
|
// Verify clicking on a picker item to change checked state.
|
|
synthesizeMouseAtCenter(thirdItem, {});
|
|
await picker.updateComplete;
|
|
verifySelectedPickerItem(thirdItem, true);
|
|
|
|
// Verify changing the picker value sets the selected state of child items.
|
|
picker.value = "first";
|
|
await picker.updateComplete;
|
|
verifySelectedPickerItem(firstItem);
|
|
});
|
|
|
|
// Verify that settings a value on the group works as expected creating
|
|
// the elements programmatically via document.createElement. We ran into
|
|
// issues with this in moz-visual-picker-item-group.
|
|
add_task(async function testProgrammaticVisualPickerCreation() {
|
|
let visualPicker = document.createElement("moz-visual-picker");
|
|
visualPicker.label = "Created with document.createElement";
|
|
visualPicker.value = "second";
|
|
|
|
let firstItem = document.createElement("moz-visual-picker-item");
|
|
firstItem.value = "first";
|
|
firstItem.label = "first";
|
|
|
|
let secondItem = document.createElement("moz-visual-picker-item");
|
|
secondItem.value = "second";
|
|
secondItem.label = "second";
|
|
|
|
visualPicker.append(firstItem, secondItem);
|
|
testHelpers.render(html``, testHelpers.renderTarget);
|
|
testHelpers.renderTarget.append(visualPicker);
|
|
await visualPicker.updateComplete;
|
|
|
|
ok(!firstItem.checked, "The first item is not checked.");
|
|
ok(secondItem.checked, "The second item is checked.");
|
|
|
|
visualPicker.value = "first";
|
|
await visualPicker.updateComplete;
|
|
|
|
ok(firstItem.checked, "The first item is checked.");
|
|
ok(!secondItem.checked, "The second item is no longer checked.");
|
|
});
|
|
|
|
// Verify that keyboard navigation works as expected.
|
|
add_task(async function testKeyboardNavigation() {
|
|
let renderTarget = await testHelpers.renderTemplate(defaultTemplate);
|
|
let picker = renderTarget.querySelector("moz-visual-picker");
|
|
let [firstItem, secondItem, thirdItem] = renderTarget.querySelectorAll(
|
|
"moz-visual-picker-item"
|
|
);
|
|
|
|
async function keyboardNavigate(direction) {
|
|
let keyCode = `KEY_Arrow${
|
|
direction.charAt(0).toUpperCase() + direction.slice(1)
|
|
}`;
|
|
synthesizeKey(keyCode);
|
|
await picker.updateComplete;
|
|
}
|
|
|
|
function validateActiveElement(item) {
|
|
is(
|
|
document.activeElement,
|
|
item,
|
|
"Focus moves to the expected picker item."
|
|
);
|
|
is(picker.value, item.value, "Visual picker value is updated.");
|
|
}
|
|
|
|
synthesizeMouseAtCenter(firstItem, {});
|
|
await picker.updateComplete;
|
|
|
|
await keyboardNavigate("down");
|
|
validateActiveElement(secondItem);
|
|
|
|
await keyboardNavigate("down");
|
|
validateActiveElement(thirdItem);
|
|
|
|
await keyboardNavigate("down");
|
|
validateActiveElement(firstItem);
|
|
|
|
await keyboardNavigate("up");
|
|
validateActiveElement(thirdItem);
|
|
|
|
await keyboardNavigate("up");
|
|
validateActiveElement(secondItem);
|
|
|
|
await keyboardNavigate("right");
|
|
validateActiveElement(thirdItem);
|
|
|
|
await keyboardNavigate("right");
|
|
validateActiveElement(firstItem);
|
|
|
|
await keyboardNavigate("left");
|
|
validateActiveElement(thirdItem);
|
|
|
|
await keyboardNavigate("left");
|
|
validateActiveElement(secondItem);
|
|
|
|
// Validate that disabled items get skipped over.
|
|
thirdItem.disabled = true;
|
|
await picker.updateComplete;
|
|
|
|
await keyboardNavigate("down");
|
|
validateActiveElement(firstItem);
|
|
|
|
await keyboardNavigate("up");
|
|
validateActiveElement(secondItem);
|
|
|
|
thirdItem.disabled = false;
|
|
await picker.updateComplete;
|
|
|
|
// Validate left/right keys have opposite effect for RTL locales.
|
|
await SpecialPowers.pushPrefEnv({
|
|
set: [["intl.l10n.pseudo", "bidi"]],
|
|
});
|
|
|
|
await keyboardNavigate("left");
|
|
validateActiveElement(thirdItem);
|
|
|
|
await keyboardNavigate("left");
|
|
validateActiveElement(firstItem);
|
|
|
|
await keyboardNavigate("right");
|
|
validateActiveElement(thirdItem);
|
|
|
|
await keyboardNavigate("right");
|
|
validateActiveElement(secondItem);
|
|
|
|
secondItem.click();
|
|
await picker.updateComplete;
|
|
validateActiveElement(secondItem);
|
|
|
|
await SpecialPowers.popPrefEnv();
|
|
});
|
|
|
|
// Validate behavior when the picker has no value/no item is selected by default.
|
|
add_task(async function testNoItemSelected() {
|
|
let template = html`
|
|
<button tabindex="0">Before picker</button>
|
|
<moz-visual-picker name="test-name" label="No item selected">
|
|
<moz-visual-picker-item value="first">
|
|
<div class="slotted">In the slot</div>
|
|
</moz-visual-picker-item>
|
|
<moz-visual-picker-item value="second">
|
|
<div class="slotted">In the slot</div>
|
|
</moz-visual-picker-item>
|
|
<moz-visual-picker-item value="third">
|
|
<div class="slotted">In the slot</div>
|
|
</moz-visual-picker-item>
|
|
</moz-visual-picker>
|
|
<button tabindex="0" id="after">After picker item></button>
|
|
`;
|
|
let renderTarget = await testHelpers.renderTemplate(template);
|
|
let picker = renderTarget.querySelector("moz-visual-picker");
|
|
let items = [
|
|
...renderTarget.querySelectorAll("moz-visual-picker-item"),
|
|
];
|
|
let [firstItem, secondItem, thirdItem] = renderTarget.querySelectorAll(
|
|
"moz-visual-picker-item"
|
|
);
|
|
let [beforeButton, afterButton] =
|
|
renderTarget.querySelectorAll("button");
|
|
|
|
ok(!picker.value, "Visual picker does not have a value.");
|
|
items.forEach(item =>
|
|
ok(!item.checked, "All picker items are unselected.")
|
|
);
|
|
|
|
beforeButton.focus();
|
|
synthesizeKey("KEY_Tab", {});
|
|
is(
|
|
document.activeElement,
|
|
firstItem,
|
|
"First picker item is tab focusable when all items un-checked."
|
|
);
|
|
[secondItem, thirdItem].forEach(item =>
|
|
is(
|
|
item.itemEl.getAttribute("tabindex"),
|
|
"-1",
|
|
"All other items are not tab focusable."
|
|
)
|
|
);
|
|
|
|
synthesizeKey("KEY_Tab", {});
|
|
is(
|
|
document.activeElement,
|
|
afterButton,
|
|
"Tab moves focus out of the visual picker."
|
|
);
|
|
|
|
synthesizeKey("KEY_Tab", { shiftKey: true });
|
|
is(
|
|
document.activeElement,
|
|
firstItem,
|
|
"Focus moves back to the first picker item."
|
|
);
|
|
|
|
synthesizeKey("KEY_ArrowDown", {});
|
|
is(
|
|
document.activeElement,
|
|
secondItem,
|
|
"Focus moves to the second picker item with down arrow keypress."
|
|
);
|
|
is(
|
|
picker.value,
|
|
secondItem.value,
|
|
"Picker value updates to second picker item value."
|
|
);
|
|
|
|
secondItem.checked = false;
|
|
await picker.updateComplete;
|
|
|
|
synthesizeKey("KEY_Tab", { shiftKey: true });
|
|
ok(
|
|
!picker.value,
|
|
"Picker value is un-set when all picker items un-checked programmatically."
|
|
);
|
|
is(
|
|
document.activeElement,
|
|
firstItem,
|
|
"First picker item becomes focusable again."
|
|
);
|
|
|
|
synthesizeKey(" ");
|
|
is(
|
|
picker.value,
|
|
firstItem.value,
|
|
"Hitting space selects the focused item."
|
|
);
|
|
|
|
synthesizeKey("KEY_Tab", { shiftKey: true });
|
|
firstItem.disabled = true;
|
|
secondItem.disabled = true;
|
|
await picker.updateComplete;
|
|
|
|
synthesizeKey("KEY_Tab");
|
|
is(
|
|
document.activeElement,
|
|
thirdItem,
|
|
"First non-disabled picker item is focusable when all items are un-checked."
|
|
);
|
|
});
|
|
|
|
// Verify expected events emitted in the correct order.
|
|
add_task(async function testPickerEvents() {
|
|
let renderTarget = await testHelpers.renderTemplate(defaultTemplate);
|
|
let picker = renderTarget.querySelector("moz-visual-picker");
|
|
let items = renderTarget.querySelectorAll("moz-visual-picker-item");
|
|
let [firstItem, secondItem, thirdItem] = items;
|
|
let { trackEvent, verifyEvents } = testHelpers.getInputEventHelpers();
|
|
|
|
items.forEach(item => {
|
|
item.addEventListener("click", trackEvent);
|
|
item.addEventListener("input", trackEvent);
|
|
item.addEventListener("change", trackEvent);
|
|
});
|
|
picker.addEventListener("change", trackEvent);
|
|
picker.addEventListener("input", trackEvent);
|
|
|
|
// Verify that clicking on a item emits the right events in the correct order.
|
|
synthesizeMouseAtCenter(thirdItem.itemEl, {});
|
|
await TestUtils.waitForTick();
|
|
|
|
verifyEvents([
|
|
{
|
|
type: "click",
|
|
value: "third",
|
|
localName: "moz-visual-picker-item",
|
|
checked: true,
|
|
},
|
|
{
|
|
type: "input",
|
|
value: "third",
|
|
localName: "moz-visual-picker-item",
|
|
checked: true,
|
|
},
|
|
{ type: "input", value: "third", localName: "moz-visual-picker" },
|
|
{
|
|
type: "change",
|
|
value: "third",
|
|
localName: "moz-visual-picker-item",
|
|
checked: true,
|
|
},
|
|
{ type: "change", value: "third", localName: "moz-visual-picker" },
|
|
]);
|
|
|
|
// Verify that keyboard navigation emits the right events in the correct order.
|
|
synthesizeKey("KEY_ArrowUp", {});
|
|
await picker.updateComplete;
|
|
is(picker.value, secondItem.value, "picker value is updated.");
|
|
await TestUtils.waitForTick();
|
|
|
|
verifyEvents([
|
|
{ type: "input", value: "second", localName: "moz-visual-picker" },
|
|
{ type: "change", value: "second", localName: "moz-visual-picker" },
|
|
]);
|
|
|
|
// Verify that changing the group's value directly doesn't emit any events.
|
|
picker.value = firstItem.value;
|
|
await picker.updateComplete;
|
|
ok(firstItem.checked, "Expected item is checked.");
|
|
await TestUtils.waitForTick();
|
|
verifyEvents([]);
|
|
|
|
// Verify that changing a item's checked state directly doesn't emit any events.
|
|
secondItem.checked = true;
|
|
await picker.updateComplete;
|
|
is(picker.value, secondItem.value, "Picker value is updated.");
|
|
await TestUtils.waitForTick();
|
|
verifyEvents([]);
|
|
|
|
// Verify activating item with space emits proper events.
|
|
picker.value = "";
|
|
await picker.updateComplete;
|
|
|
|
ok(!firstItem.checked, "The first item is not selected.");
|
|
firstItem.focus();
|
|
synthesizeKey(" ");
|
|
await TestUtils.waitForTick();
|
|
verifyEvents([
|
|
{
|
|
type: "click",
|
|
value: "first",
|
|
localName: "moz-visual-picker-item",
|
|
checked: true,
|
|
},
|
|
{
|
|
type: "input",
|
|
value: "first",
|
|
localName: "moz-visual-picker-item",
|
|
checked: true,
|
|
},
|
|
{ type: "input", value: "first", localName: "moz-visual-picker" },
|
|
{
|
|
type: "change",
|
|
value: "first",
|
|
localName: "moz-visual-picker-item",
|
|
checked: true,
|
|
},
|
|
{ type: "change", value: "first", localName: "moz-visual-picker" },
|
|
]);
|
|
});
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<p id="display"></p>
|
|
<div id="content" style="display: none"></div>
|
|
<pre id="test"></pre>
|
|
</body>
|
|
</html>
|