UNPKG

@octopusdeploy/design-system-components

Version:
264 lines (263 loc) • 15.4 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const jsx_runtime_1 = require("react/jsx-runtime"); const testing_library_1 = require("@octopusdeploy/testing-library"); const react_1 = require("@testing-library/react"); const user_event_1 = __importDefault(require("@testing-library/user-event")); const react_2 = require("react"); const vitest_1 = require("vitest"); const renderComponentTest_1 = require("../../../testing/renderComponentTest"); const Select_1 = require("../../Form/Select/Select"); const DialogBase_1 = require("../DialogBase"); const dialogAccessibleName = "Test Dialog"; (0, vitest_1.describe)("DialogBase", () => { (0, vitest_1.test)("renders the given content", () => { const dialogContent = "Dialog content"; const { assertHasDialogContent } = renderDialogBase({ open: true, content: dialogContent }); assertHasDialogContent(dialogContent); }); (0, vitest_1.test)("does not render when open is false", () => { renderDialogBase({ open: false, content: "Hidden content" }); testing_library_1.domQueries.queryDialog(dialogAccessibleName).assertIsNotInTheDocument(); }); (0, vitest_1.describe)("closing on escape", () => { (0, vitest_1.test)("escape closes the dialog", async () => { const { pressEscape, assertOnCloseCalled } = renderDialogBase({ open: true }); await pressEscape(); assertOnCloseCalled(); }); (0, vitest_1.test)("does not close on escape when closeOnEscape is false", async () => { const { pressEscape, assertOnCloseNotCalled } = renderDialogBase({ open: true, closeOnEscape: false }); await pressEscape(); assertOnCloseNotCalled(); }); (0, vitest_1.test)("escape closes an open Select dropdown without also closing the dialog", async () => { const { openSelect, assertSelectDropdownIsOpen, pressEscape, assertSelectDropdownIsClosed, assertOnCloseNotCalled } = renderDialogBase({ open: true, content: (0, jsx_runtime_1.jsx)(SelectContent, {}) }); await openSelect(); assertSelectDropdownIsOpen(); await pressEscape(); assertSelectDropdownIsClosed(); assertOnCloseNotCalled(); }); (0, vitest_1.test)("a further escape closes the dialog once the Select dropdown is closed", async () => { const { openSelect, pressEscape, assertOnCloseCalled } = renderDialogBase({ open: true, content: (0, jsx_runtime_1.jsx)(SelectContent, {}) }); await openSelect(); await pressEscape(); await pressEscape(); assertOnCloseCalled(); }); }); (0, vitest_1.describe)("aria attributes", () => { (0, vitest_1.test)("has role dialog", () => { renderDialogBase({ open: true }); const dialog = testing_library_1.domQueries.getDialog(dialogAccessibleName).innerElement; (0, vitest_1.expect)(dialog).toHaveAttribute("role", "dialog"); }); (0, vitest_1.test)("has aria-modal set to true", () => { renderDialogBase({ open: true }); const dialog = testing_library_1.domQueries.getDialog(dialogAccessibleName).innerElement; (0, vitest_1.expect)(dialog).toHaveAttribute("aria-modal", "true"); }); (0, vitest_1.test)("has aria-label matching the accessible name", () => { renderDialogBase({ open: true }); const dialog = testing_library_1.domQueries.getDialog(dialogAccessibleName).innerElement; (0, vitest_1.expect)(dialog).toHaveAttribute("aria-label", dialogAccessibleName); }); }); (0, vitest_1.describe)("focus functionality", () => { const firstButtonLabel = "First Button"; const secondButtonLabel = "Second Button"; const lastButtonLabel = "Last Button"; const focusableElementsContent = ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("button", { children: firstButtonLabel }), (0, jsx_runtime_1.jsx)("button", { children: secondButtonLabel }), (0, jsx_runtime_1.jsx)("button", { children: lastButtonLabel })] })); (0, vitest_1.describe)("when autoFocusFirstElement is true", () => { (0, vitest_1.test)("focuses the first focusable element when dialog opens", () => { const { assertButtonHasFocus } = renderDialogBase({ open: true, content: focusableElementsContent }); assertButtonHasFocus(firstButtonLabel); }); (0, vitest_1.test)("tab moves focus to next focusable element", async () => { const { assertButtonHasFocus, pressTab } = renderDialogBase({ open: true, content: focusableElementsContent }); assertButtonHasFocus(firstButtonLabel); await pressTab(); assertButtonHasFocus(secondButtonLabel); }); (0, vitest_1.test)("tab from last element wraps to first element", async () => { const { assertButtonHasFocus, pressTab } = renderDialogBase({ open: true, content: focusableElementsContent }); assertButtonHasFocus(firstButtonLabel); // Tab to last button await pressTab(); await pressTab(); assertButtonHasFocus(lastButtonLabel); // Tab from last wraps to first await pressTab(); assertButtonHasFocus(firstButtonLabel); }); (0, vitest_1.test)("shift+tab from first element wraps to last element", async () => { const { assertButtonHasFocus, pressShiftTab } = renderDialogBase({ open: true, content: focusableElementsContent }); assertButtonHasFocus(firstButtonLabel); await pressShiftTab(); assertButtonHasFocus(lastButtonLabel); }); }); (0, vitest_1.describe)("when autoFocusFirstElement is false", () => { (0, vitest_1.test)("focuses the dialog container instead of first focusable element when dialog opens", () => { const { assertDialogContainerHasFocus } = renderDialogBase({ open: true, autoFocusFirstElement: false, content: focusableElementsContent }); assertDialogContainerHasFocus(); }); (0, vitest_1.test)("tab moves focus from container to first focusable element", async () => { const { assertDialogContainerHasFocus, assertButtonHasFocus, pressTab } = renderDialogBase({ open: true, autoFocusFirstElement: false, content: focusableElementsContent }); assertDialogContainerHasFocus(); await pressTab(); assertButtonHasFocus(firstButtonLabel); }); (0, vitest_1.test)("shift+tab moves focus from container to last focusable element", async () => { const { assertDialogContainerHasFocus, assertButtonHasFocus, pressShiftTab } = renderDialogBase({ open: true, autoFocusFirstElement: false, content: focusableElementsContent }); assertDialogContainerHasFocus(); await pressShiftTab(); assertButtonHasFocus(lastButtonLabel); }); (0, vitest_1.test)("tab wraps from last to first element without returning to container", async () => { const { assertDialogContainerHasFocus, assertButtonHasFocus, pressTab, pressShiftTab } = renderDialogBase({ open: true, autoFocusFirstElement: false, content: focusableElementsContent }); assertDialogContainerHasFocus(); await pressShiftTab(); assertButtonHasFocus(lastButtonLabel); // Tab from last wraps to first, not back to container await pressTab(); assertButtonHasFocus(firstButtonLabel); }); (0, vitest_1.test)("shift+tab wraps from first to last element without returning to container", async () => { const { assertDialogContainerHasFocus, assertButtonHasFocus, pressTab, pressShiftTab } = renderDialogBase({ open: true, autoFocusFirstElement: false, content: focusableElementsContent }); assertDialogContainerHasFocus(); await pressTab(); assertButtonHasFocus(firstButtonLabel); // Shift+Tab from first wraps to last, not back to container await pressShiftTab(); assertButtonHasFocus(lastButtonLabel); }); (0, vitest_1.test)("keeps focus on a child that has autoFocus instead of focusing the container", () => { const autoFocusButtonLabel = "Autofocused Button"; const { assertButtonHasFocus } = renderDialogBase({ open: true, autoFocusFirstElement: false, content: ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("button", { children: firstButtonLabel }), (0, jsx_runtime_1.jsx)("button", { autoFocus: true, children: autoFocusButtonLabel })] })), }); assertButtonHasFocus(autoFocusButtonLabel); }); }); }); (0, vitest_1.describe)("returning focus on close", () => { (0, vitest_1.test)("returns focus to the trigger when the dialog closes", async () => { const { openDialogFromTrigger, pressEscape, assertTriggerHasFocus } = renderTriggeredDialog(); await openDialogFromTrigger(); await pressEscape(); assertTriggerHasFocus(); }); (0, vitest_1.test)("does not steal focus if it has since moved elsewhere", async () => { const { openDialogFromTrigger, focusElsewhere, pressEscape, assertElsewhereHasFocus } = renderTriggeredDialog(); await openDialogFromTrigger(); focusElsewhere(); await pressEscape(); assertElsewhereHasFocus(); }); // jsdom can't evaluate :focus-visible, so we assert the modality hint passed to focus(): // keyboard closes ask for the ring, pointer closes suppress it. (0, vitest_1.test)("restores focus with the ring when closed via keyboard", async () => { const { openDialogFromTrigger, spyOnTriggerFocus, pressEscape } = renderTriggeredDialog(); await openDialogFromTrigger(); const focusSpy = spyOnTriggerFocus(); await pressEscape(); (0, vitest_1.expect)(focusSpy).toHaveBeenLastCalledWith({ focusVisible: true }); }); (0, vitest_1.test)("restores focus without the ring when closed via pointer", async () => { const { openDialogFromTrigger, spyOnTriggerFocus, clickCloseButton } = renderTriggeredDialog(); await openDialogFromTrigger(); const focusSpy = spyOnTriggerFocus(); await clickCloseButton(); (0, vitest_1.expect)(focusSpy).toHaveBeenLastCalledWith({ focusVisible: false }); }); }); }); const selectLabel = "Fruit"; const selectItems = [ { id: "1", name: "First option" }, { id: "2", name: "Second option" }, ]; function SelectContent() { return (0, jsx_runtime_1.jsx)(Select_1.Select, { label: selectLabel, items: selectItems, getOption: (item) => ({ value: item.id, label: item.name }), value: undefined, onChange: vitest_1.vi.fn() }); } const triggerLabel = "Open dialog"; const elsewhereLabel = "Elsewhere"; const closeButtonLabel = "Close from inside"; function TriggeredDialogHarness() { const [open, setOpen] = (0, react_2.useState)(false); return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => setOpen(true), children: triggerLabel }), (0, jsx_runtime_1.jsx)("button", { children: elsewhereLabel }), (0, jsx_runtime_1.jsx)(DialogBase_1.DialogBase, { open: open, onClose: () => setOpen(false), accessibleName: dialogAccessibleName, children: (0, jsx_runtime_1.jsx)("button", { onClick: () => setOpen(false), children: closeButtonLabel }) })] })); } function renderTriggeredDialog() { (0, renderComponentTest_1.renderComponentTest)((0, jsx_runtime_1.jsx)(TriggeredDialogHarness, {})); return { openDialogFromTrigger: async () => { await testing_library_1.domQueries.getButton(triggerLabel).click(); }, focusElsewhere: () => { testing_library_1.domQueries.getButton(elsewhereLabel).focus(); }, pressEscape: async () => { await user_event_1.default.keyboard("{Escape}"); }, clickCloseButton: async () => { await testing_library_1.domQueries.getButton(closeButtonLabel).click(); }, spyOnTriggerFocus: () => vitest_1.vi.spyOn(testing_library_1.domQueries.getButton(triggerLabel).innerElement, "focus"), assertTriggerHasFocus: () => { testing_library_1.domQueries.getButton(triggerLabel).assertHasFocus(); }, assertElsewhereHasFocus: () => { testing_library_1.domQueries.getButton(elsewhereLabel).assertHasFocus(); }, }; } function renderDialogBase({ open, content, autoFocusFirstElement, closeOnEscape }) { const onClose = vitest_1.vi.fn(); (0, renderComponentTest_1.renderComponentTest)((0, jsx_runtime_1.jsx)(DialogBase_1.DialogBase, { open: open, onClose: onClose, accessibleName: dialogAccessibleName, autoFocusFirstElement: autoFocusFirstElement, closeOnEscape: closeOnEscape, children: content })); return getInteractions(onClose); } function getInteractions(onClose) { return { assertHasDialogContent: (content) => { testing_library_1.domQueries.getText(content).assertIsInTheDocument(); }, assertDialogContainerHasFocus: () => { const dialogContainer = testing_library_1.domQueries.getDialog(dialogAccessibleName).innerElement; (0, vitest_1.expect)(dialogContainer).toHaveFocus(); }, assertButtonHasFocus: (accessibleName) => { testing_library_1.domQueries.getButton(accessibleName).assertHasFocus(); }, pressTab: async () => { await user_event_1.default.keyboard("{Tab}"); }, pressShiftTab: async () => { await user_event_1.default.keyboard("{Shift>}{Tab}{/Shift}"); }, pressEscape: async () => { await user_event_1.default.keyboard("{Escape}"); }, openSelect: async () => { await user_event_1.default.click(react_1.screen.getByRole("combobox", { name: new RegExp(selectLabel) })); }, assertSelectDropdownIsOpen: () => { (0, vitest_1.expect)(react_1.screen.getByRole("listbox")).toBeInTheDocument(); }, assertSelectDropdownIsClosed: () => { (0, vitest_1.expect)(react_1.screen.queryByRole("listbox")).not.toBeInTheDocument(); }, assertOnCloseCalled: () => { (0, vitest_1.expect)(onClose).toHaveBeenCalled(); }, assertOnCloseNotCalled: () => { (0, vitest_1.expect)(onClose).not.toHaveBeenCalled(); }, }; }