1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
|
<!DOCTYPE HTML>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<html>
<head>
<meta charset="utf-8">
<title><!-- Shadow Parts issue with xul/xbl domparser --></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://mochikit/content/tests/SimpleTest/test.css"/>
<script>
const { BrowserTestUtils } = ChromeUtils.importESModule(
"resource://testing-common/BrowserTestUtils.sys.mjs"
);
const DEFAULT_SECTION_NAMES = ["one", "two", "three"];
function makeButton({ name, deckId }) {
let button = document.createElement("button", { is: "named-deck-button" });
button.setAttribute("name", name);
button.deckId = deckId;
button.textContent = name.toUpperCase();
return button;
}
function makeSection({ name }) {
let view = document.createElement("section");
view.setAttribute("name", name);
view.textContent = name + name;
return view;
}
function addSection({ name, deck, buttons }) {
let button = makeButton({ name, deckId: deck.id });
buttons.appendChild(button);
let view = makeSection({ name });
deck.appendChild(view);
return { button, view };
}
async function runTests({ deck, buttons }) {
const selectedSlot = deck.shadowRoot.querySelector('slot[name="selected"]');
const getButtonByName = name => buttons.querySelector(`[name="${name}"]`);
function checkState(name, count, empty = false) {
// Check that the right view is selected.
is(deck.selectedViewName, name, "The right view is selected");
// Verify there's one element in the slot.
let slottedEls = selectedSlot.assignedElements();
if (empty) {
is(slottedEls.length, 0, "The deck is empty");
} else {
is(slottedEls.length, 1, "There's one visible view");
is(
slottedEls[0].getAttribute("name"),
name,
"The correct view is in the slot"
);
}
// Check that the hidden properties are set.
let sections = deck.querySelectorAll("section");
is(sections.length, count, "There are the right number of sections");
for (let section of sections) {
let sectionName = section.getAttribute("name");
if (sectionName == name) {
is(section.slot, "selected", `${sectionName} is visible`);
} else {
is(section.slot, "", `${sectionName} is hidden`);
}
}
// Check the right button is selected.
is(buttons.children.length, count, "There are the right number of buttons");
for (let button of buttons.children) {
let buttonName = button.getAttribute("name");
let selected = buttonName == name;
is(
button.hasAttribute("selected"),
selected,
`${buttonName} is ${selected ? "selected" : "not selected"}`
);
}
}
// Check that the first view is selected by default.
checkState("one", 3);
// Switch to the third view.
info("Switch to section three");
getButtonByName("three").click();
checkState("three", 3);
// Add a new section, nothing changes.
info("Add section last");
let last = addSection({ name: "last", deck, buttons });
checkState("three", 4);
// We can switch to the new section.
last.button.click();
info("Switch to section last");
checkState("last", 4);
info("Switch view with selectedViewName");
let shown = BrowserTestUtils.waitForEvent(deck, "view-changed");
deck.selectedViewName = "two";
await shown;
checkState("two", 4);
info("Switch back to the last view to test removing selected view");
shown = BrowserTestUtils.waitForEvent(deck, "view-changed");
deck.setAttribute("selected-view", "last");
await shown;
checkState("last", 4);
// Removing the selected section leaves the selected slot empty.
info("Remove section last");
last.button.remove();
last.view.remove();
info("Should not have any selected views");
checkState("last", 3, true);
// Setting a missing view will give a "view-changed" event.
info("Set view to a missing name");
let hidden = BrowserTestUtils.waitForEvent(deck, "view-changed");
deck.selectedViewName = "missing";
await hidden;
checkState("missing", 3, true);
// Adding the view won't trigger "view-changed", but the view will slotted.
info("Add the missing view, it should be shown");
shown = BrowserTestUtils.waitForEvent(selectedSlot, "slotchange");
let viewChangedEvent = false;
let viewChangedFn = () => {
viewChangedEvent = true;
};
deck.addEventListener("view-changed", viewChangedFn);
addSection({ name: "missing", deck, buttons });
await shown;
deck.removeEventListener("view-changed", viewChangedFn);
ok(!viewChangedEvent, "The view-changed event didn't fire");
checkState("missing", 4);
}
async function setup({ beAsync, first, deckId }) {
// Make the deck and buttons.
const deck = document.createElement("named-deck");
deck.id = deckId;
for (let name of DEFAULT_SECTION_NAMES) {
deck.appendChild(makeSection({ name }));
}
const buttons = document.createElement("button-group");
for (let name of DEFAULT_SECTION_NAMES) {
buttons.appendChild(makeButton({ name, deckId }));
}
let ordered;
if (first == "deck") {
ordered = [deck, buttons];
} else if (first == "buttons") {
ordered = [buttons, deck];
} else {
throw new Error("Invalid order");
}
// Insert them in the specified order, possibly async.
document.body.appendChild(ordered.shift());
if (beAsync) {
await new Promise(resolve => requestAnimationFrame(resolve));
}
document.body.appendChild(ordered.shift());
return { deck, buttons };
}
add_task(async function testNamedDeckAndButtons() {
// Check adding the deck first.
dump("Running deck first tests synchronously");
await runTests(await setup({ beAsync: false, first: "deck", deckId: "deck-sync" }));
dump("Running deck first tests asynchronously");
await runTests(await setup({ beAsync: true, first: "deck", deckId: "deck-async" }));
// Check adding the buttons first.
dump("Running buttons first tests synchronously");
await runTests(await setup({ beAsync: false, first: "buttons", deckId: "buttons-sync" }));
dump("Running buttons first tests asynchronously");
await runTests(await setup({ beAsync: true, first: "buttons", deckId: "buttons-async" }));
});
add_task(async function testFocusAndClickMixing() {
const waitForAnimationFrame = () =>
new Promise(r => requestAnimationFrame(r));
const sendTab = (e = {}) => {
synthesizeKey("VK_TAB", e);
return waitForAnimationFrame();
};
const firstButton = document.createElement("button");
document.body.append(firstButton);
const { deck, buttons: buttonGroup } = await setup({
beAsync: false,
first: "buttons",
deckId: "focus-click-mixing",
});
const buttons = buttonGroup.children;
firstButton.focus();
const secondButton = document.createElement("button");
document.body.append(secondButton);
await sendTab();
is(document.activeElement, buttons[0], "first deck button is focused");
is(deck.selectedViewName, "one", "first view is shown");
await sendTab();
is(document.activeElement, secondButton, "focus moves out of group");
await sendTab({ shiftKey: true });
is(document.activeElement, buttons[0], "focus moves back to first button");
// Click on another tab button, this should make it the focusable button.
synthesizeMouseAtCenter(buttons[1], {});
await waitForAnimationFrame();
is(deck.selectedViewName, "two", "second view is shown");
if (document.activeElement != buttons[1]) {
// On Mac the button isn't focused on click, but it is on Windows/Linux.
await sendTab();
}
is(document.activeElement, buttons[1], "second deck button is focusable");
await sendTab();
is(document.activeElement, secondButton, "focus moved to second plain button");
await sendTab({ shiftKey: true });
is(document.activeElement, buttons[1], "second deck button is focusable");
await sendTab({ shiftKey: true });
is(
document.activeElement,
firstButton,
"next shift-tab moves out of button group"
);
});
</script>
</head>
<body>
</body>
</html>
|