@octopusdeploy/design-system-components
Version:
The design systems component library.
264 lines (263 loc) • 15.4 kB
JavaScript
"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();
},
};
}