summaryrefslogtreecommitdiffstats
path: root/toolkit/content/tests/chrome/test_named_deck.html
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/content/tests/chrome/test_named_deck.html')
-rw-r--r--toolkit/content/tests/chrome/test_named_deck.html249
1 files changed, 249 insertions, 0 deletions
diff --git a/toolkit/content/tests/chrome/test_named_deck.html b/toolkit/content/tests/chrome/test_named_deck.html
new file mode 100644
index 0000000000..4f1ba2272f
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_named_deck.html
@@ -0,0 +1,249 @@
+<!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.import("resource://testing-common/BrowserTestUtils.jsm");
+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>