diff options
Diffstat (limited to 'toolkit/content/tests/chrome/test_named_deck.html')
-rw-r--r-- | toolkit/content/tests/chrome/test_named_deck.html | 249 |
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> |