@amsterdam/design-system-react
Version:
All React components from the Amsterdam Design System. Use it to compose pages in your website or application.
102 lines (101 loc) • 5.64 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/**
* @license EUPL-1.2+
* Copyright Gemeente Amsterdam
*/
import { fireEvent, render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { createRef } from 'react';
import { describe, expect, it, vi } from 'vitest';
import { ProgressList, progressListHeadingLevels } from './ProgressList';
describe('ProgressList', () => {
it('renders', () => {
render(_jsx(ProgressList, { headingLevel: 3 }));
const list = screen.getByRole('list');
expect(list).toBeInTheDocument();
expect(list).toBeVisible();
expect(list.tagName).toBe('OL');
});
it('renders a design system BEM class name', () => {
render(_jsx(ProgressList, { headingLevel: 3 }));
const list = screen.getByRole('list');
expect(list).toHaveClass('ams-progress-list');
});
progressListHeadingLevels.forEach((level) => {
it(`adds the class for heading level ${level}`, () => {
render(_jsx(ProgressList, { headingLevel: level }));
const list = screen.getByRole('list');
expect(list).toHaveClass(`ams-progress-list--heading-${level}`);
});
it(`renders the heading with level ${level}`, () => {
render(_jsx(ProgressList, { headingLevel: level, children: _jsx(ProgressList.Step, { heading: `Heading ${level}` }) }));
const heading = screen.getByRole('heading', { level, name: `Heading ${level}` });
expect(heading).toBeInTheDocument();
});
});
it('renders an extra class name', () => {
render(_jsx(ProgressList, { className: "extra", headingLevel: 3 }));
const list = screen.getByRole('list');
expect(list).toHaveClass('ams-progress-list extra');
});
it('supports ForwardRef in React', () => {
const ref = createRef();
render(_jsx(ProgressList, { headingLevel: 3, ref: ref }));
const list = screen.getByRole('list');
expect(ref.current).toBe(list);
});
it('supports composition using subcomponents', () => {
render(_jsx(ProgressList, { headingLevel: 3, children: _jsx(ProgressList.Step, { hasSubsteps: true, heading: "Step", children: _jsx(ProgressList.Substeps, { children: _jsx(ProgressList.Substep, { children: "Substep" }) }) }) }));
const [mainList, subStepsList] = screen.getAllByRole('list');
expect(mainList).toHaveClass('ams-progress-list');
expect(subStepsList).toHaveClass('ams-progress-list-substeps');
// Main step is the only list item directly under the main list.
const [mainStep] = within(mainList).getAllByRole('listitem');
expect(mainStep).toHaveClass('ams-progress-list__step ams-progress-list__step--has-substeps');
// Substeps are listitems under the substeps list.
const [subStep] = within(subStepsList).getAllByRole('listitem');
expect(subStep).toHaveClass('ams-progress-list-substeps__step');
});
it('renders no buttons by default', () => {
render(_jsxs(ProgressList, { headingLevel: 3, children: [_jsx(ProgressList.Step, { heading: "one", children: "Content" }), _jsx(ProgressList.Step, { heading: "two", children: "Content" })] }));
expect(screen.queryByRole('button')).not.toBeInTheDocument();
});
it('does not handle keyboard navigation by default', () => {
render(_jsxs(ProgressList, { headingLevel: 3, children: [_jsx(ProgressList.Step, { heading: "one", children: "Content" }), _jsx(ProgressList.Step, { heading: "two", children: "Content" })] }));
const list = screen.getByRole('list');
const onKeyDown = vi.fn();
list.addEventListener('keydown', onKeyDown);
for (const key of ['ArrowDown', 'ArrowUp', 'Home', 'End']) {
fireEvent.keyDown(list, { key });
}
// Events fire on the element, but none are intercepted (no preventDefault called)
expect(onKeyDown).toHaveBeenCalledTimes(4);
for (const call of onKeyDown.mock.calls) {
expect(call[0].defaultPrevented).toBe(false);
}
});
it('passes additional props', () => {
render(_jsx(ProgressList, { "aria-hidden": "false", "data-test": "data-test", headingLevel: 2, id: "id" }));
const component = screen.getByRole('list');
expect(component).toHaveAttribute('aria-hidden', 'false');
expect(component).toHaveAttribute('id', 'id');
expect(component).toHaveAttribute('data-test', 'data-test');
});
describe('when collapsible', () => {
it('sets focus on step buttons when using arrow keys', async () => {
const user = userEvent.setup();
render(_jsxs(ProgressList, { collapsible: true, headingLevel: 3, children: [_jsx(ProgressList.Step, { heading: "one", children: "Content" }), _jsx(ProgressList.Step, { heading: "two", children: "Content" }), _jsx(ProgressList.Step, { heading: "three", children: "Content" })] }));
const firstButton = screen.getByRole('button', { name: /one/ });
const thirdButton = screen.getByRole('button', { name: /three/ });
await user.click(firstButton);
expect(firstButton).toHaveFocus();
await user.keyboard('{ArrowDown}');
await user.keyboard('{ArrowDown}');
expect(thirdButton).toHaveFocus();
expect(firstButton).not.toHaveFocus();
// Rotating: wraps from last to first
await user.keyboard('{ArrowDown}');
expect(firstButton).toHaveFocus();
});
});
});