UNPKG

orcs-design-system

Version:
329 lines (326 loc) 7.77 kB
/** * A11y audit: run axe on ORCS components that have Storybook stories. * Violations are logged as warnings only; accessibility violations alone do not fail these tests or block CI (other errors still can). * Add new entries to COMPONENTS when new stories are added. */ import React, { useState } from "react"; import { render } from "@testing-library/react"; import { axe } from "jest-axe"; import { MemoryRouter, Route } from "react-router-dom"; import SystemThemeProvider from "../SystemThemeProvider"; import { ActionsMenu, ActionsMenuItem, Avatar, Badge, Box, Breadcrumbs, Button, ButtonLink, Card, Checkbox, CodeBlock, DatePicker, Divider, Expandable, Flex, FlexItem, Grid, GridItem, Icon, Loading, Modal, Notification, P, Popover, ProgressBar, RadioButton, Range, Select, Spacer, StatusDot, StyledLink, Table, Tabs, Tag, TextArea, TextInput, Toggle } from "../index"; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; const renderWithTheme = ui => render(/*#__PURE__*/_jsx(SystemThemeProvider, { children: ui })); const renderWithRouter = ui => render(/*#__PURE__*/_jsx(SystemThemeProvider, { children: /*#__PURE__*/_jsx(MemoryRouter, { initialEntries: ["/"], children: ui }) })); function logViolations(componentName, violations) { if (violations.length === 0) return; console.warn("[a11y] ".concat(componentName, ": ").concat(violations.length, " violation(s) \u2013 fix these to improve accessibility:")); violations.forEach((v, i) => { console.warn(" ".concat(i + 1, ". ").concat(v.id, ": ").concat(v.help, " (impact: ").concat(v.impact, ")\n ").concat(v.nodes.length, " node(s). Help: ").concat(v.helpUrl)); }); } // DatePicker with local state (needs moment from react-dates) const DatePickerSingle = () => { const [date, setDate] = useState(null); const [focused, setFocused] = useState(false); return /*#__PURE__*/_jsx(DatePicker, { single: true, id: "a11y-datepicker", startDateId: "a11y-start", endDateId: "a11y-end", date: date, placeholder: "Date", focused: focused, onDateChange: setDate, onFocusChange: _ref => { let { focused: f } = _ref; return setFocused(f); }, numberOfMonths: 1, displayFormat: "DD/MM/YYYY" }); }; // Minimal table data for Table component const tableColumns = [{ accessorKey: "name", header: "Name" }, { accessorKey: "age", header: "Age" }]; const tableData = [{ name: "John", age: 30 }, { name: "Sara", age: 25 }]; const breadcrumbsConfig = [{ id: "1", label: "Home", to: "/" }, { id: "2", label: "Current" }]; const tabsConfig = [{ label: "Tab 1", path: "/tab1" }, { label: "Tab 2", path: "/tab2" }]; /** One default render per Storybook-backed component included in this growing allowlist. This is partial coverage; the coverage-report script highlights gaps vs. all stories. */ const COMPONENTS = [{ name: "ActionsMenu", jsx: /*#__PURE__*/_jsx(ActionsMenu, { children: /*#__PURE__*/_jsx(ActionsMenuItem, { onClick: () => {}, children: "Item" }) }) }, { name: "Avatar", jsx: /*#__PURE__*/_jsx(Avatar, { title: "Jane Doe", initials: "JD" }) }, { name: "Badge", jsx: /*#__PURE__*/_jsx(Badge, { children: "New" }) }, { name: "Box", jsx: /*#__PURE__*/_jsx(Box, { p: "r", children: "Content" }) }, { name: "Breadcrumbs", jsx: /*#__PURE__*/_jsx(Breadcrumbs, { config: breadcrumbsConfig }), useRouter: true }, { name: "Button", jsx: /*#__PURE__*/_jsx(Button, { children: "Submit" }) }, { name: "Button iconOnly", jsx: /*#__PURE__*/_jsx(Button, { iconOnly: true, ariaLabel: "Close", icon: "times" }) }, { name: "ButtonLink", jsx: /*#__PURE__*/_jsx(ButtonLink, { to: "/", children: "Link" }), useRouter: true }, { name: "Card", jsx: /*#__PURE__*/_jsx(Card, { title: "Title", subtitle: "Subtitle", children: /*#__PURE__*/_jsx(P, { children: "Body" }) }) }, { name: "Checkbox", jsx: /*#__PURE__*/_jsx(Checkbox, { id: "a11y-cb", label: "I agree" }) }, { name: "CodeBlock", jsx: /*#__PURE__*/_jsx(CodeBlock, { children: "const x = 1;" }) }, { name: "DatePicker", jsx: /*#__PURE__*/_jsx(DatePickerSingle, {}) }, { name: "Divider", jsx: /*#__PURE__*/_jsx(Divider, {}) }, { name: "Expandable", jsx: /*#__PURE__*/_jsx(Expandable, { title: "Details", children: /*#__PURE__*/_jsx(P, { children: "Content" }) }) }, { name: "Flex", jsx: /*#__PURE__*/_jsx(Flex, { children: /*#__PURE__*/_jsx(FlexItem, { children: "Item" }) }) }, { name: "Grid", jsx: /*#__PURE__*/_jsxs(Grid, { gridTemplateColumns: "1fr 1fr", children: [/*#__PURE__*/_jsx(GridItem, { children: "A" }), /*#__PURE__*/_jsx(GridItem, { children: "B" })] }) }, { name: "Icon", jsx: /*#__PURE__*/_jsx(Icon, { icon: ["fas", "plus"], title: "Plus" }) }, { name: "Loading", jsx: /*#__PURE__*/_jsx(Loading, {}) }, { name: "Modal", jsx: /*#__PURE__*/_jsx(Modal, { ariaLabel: "Test modal", visible: true, onClose: () => {}, handleOnConfirm: () => {}, children: /*#__PURE__*/_jsx(P, { children: "Content" }) }) }, { name: "Notification", jsx: /*#__PURE__*/_jsx(Notification, { icon: ["fas", "info-circle"], children: "Message" }) }, { name: "Popover", jsx: /*#__PURE__*/_jsx(Popover, { text: "Tooltip", children: /*#__PURE__*/_jsx(Button, { children: "Hover" }) }) }, { name: "ProgressBar", jsx: /*#__PURE__*/_jsx(ProgressBar, { ariaLabel: "Progress", containerWidth: 100, fillWidth: 50 }) }, { name: "RadioButton", jsx: /*#__PURE__*/_jsx(RadioButton, { name: "a11y-r", label: "Option" }) }, { name: "Range", jsx: /*#__PURE__*/_jsx(Range, { min: 0, max: 100, defaultValue: 50, ariaLabel: "Slider" }) }, { name: "Select", jsx: /*#__PURE__*/_jsx(Select, { inputId: "a11y-sel", label: "Choose", options: [{ value: "a", label: "A" }] }) }, { name: "Spacer", jsx: /*#__PURE__*/_jsx(Spacer, { mb: "r", children: /*#__PURE__*/_jsx(P, { children: "Text" }) }) }, { name: "StatusDot", jsx: /*#__PURE__*/_jsx(StatusDot, {}) }, { name: "StyledLink", jsx: /*#__PURE__*/_jsx(StyledLink, { href: "/", children: "Link" }), useRouter: true }, { name: "Table", jsx: /*#__PURE__*/_jsx(Table, { columns: tableColumns, data: tableData }) }, { name: "Tabs", jsx: /*#__PURE__*/_jsx(MemoryRouter, { initialEntries: ["/tab1"], children: /*#__PURE__*/_jsx(Route, { path: "/", children: /*#__PURE__*/_jsx(Tabs, { tabsList: tabsConfig }) }) }) }, { name: "Tag", jsx: /*#__PURE__*/_jsx(Tag, { ariaLabel: "Tag label", children: "Tag" }) }, { name: "TextArea", jsx: /*#__PURE__*/_jsx(TextArea, { id: "a11y-ta", label: "Notes" }) }, { name: "TextInput", jsx: /*#__PURE__*/_jsx(TextInput, { id: "a11y-ti", label: "Email", placeholder: "you@sample.teamform.co" }) }, { name: "Toggle", jsx: /*#__PURE__*/_jsx(Toggle, { id: "a11y-tog", label: "Enable" }) }]; describe("A11y warnings (informational only – does not fail the build)", () => { COMPONENTS.forEach(_ref2 => { let { name, jsx, useRouter } = _ref2; it("".concat(name, ": log a11y violations as warnings"), async () => { const { container } = useRouter ? renderWithRouter(jsx) : renderWithTheme(jsx); const results = await axe(container); logViolations(name, results.violations); expect(results).toBeDefined(); }); }); });