UNPKG

@amsterdam/design-system-react

Version:

All React components from the Amsterdam Design System. Use it to compose pages in your website or application.

212 lines (211 loc) 14.8 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; /** * @license EUPL-1.2+ * Copyright Gemeente Amsterdam */ import { fireEvent, render, screen } from '@testing-library/react'; import { createRef } from 'react'; import { describe, expect, it, vi } from 'vitest'; import { ProgressList } from './ProgressList'; describe('ProgressListStep', () => { it('renders', () => { render(_jsx(ProgressList, { headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "Test Step", children: "Content" }) })); const step = screen.getByRole('listitem'); expect(step).toBeInTheDocument(); expect(step).toBeVisible(); }); it('renders a design system BEM class name', () => { render(_jsx(ProgressList, { headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "Test Step", children: "Content" }) })); const step = screen.getByRole('listitem'); expect(step).toHaveClass('ams-progress-list__step'); }); it('renders the marker', () => { const { container } = render(_jsx(ProgressList, { headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "Test Step", children: "Content" }) })); const marker = container.querySelector('.ams-progress-list__marker'); expect(marker).toBeInTheDocument(); }); it('renders the connector', () => { const { container } = render(_jsx(ProgressList, { headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "Test Step", children: "Content" }) })); const connector = container.querySelector('.ams-progress-list__connector'); expect(connector).toBeInTheDocument(); }); it('renders the heading', () => { render(_jsx(ProgressList, { headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "My Step Heading", children: "Content" }) })); const heading = screen.getByRole('heading', { level: 3, name: 'My Step Heading' }); expect(heading).toBeInTheDocument(); expect(heading).toHaveClass('ams-progress-list__heading'); }); it('renders an extra class name', () => { render(_jsx(ProgressList, { headingLevel: 3, children: _jsx(ProgressList.Step, { className: "extra", heading: "Test Step", children: "Content" }) })); const step = screen.getByRole('listitem'); expect(step).toHaveClass('ams-progress-list__step extra'); }); it('sets aria-current and current class when status is current', () => { render(_jsx(ProgressList, { headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "Test Step", status: "current", children: "Content" }) })); const step = screen.getByRole('listitem'); expect(step).toHaveAttribute('aria-current', 'step'); expect(step).toHaveClass('ams-progress-list__step--current'); }); it('adds completed class and does not set aria-current when status is completed', () => { render(_jsx(ProgressList, { headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "Test Step", status: "completed", children: "Content" }) })); const step = screen.getByRole('listitem'); expect(step).toHaveClass('ams-progress-list__step--completed'); expect(step).not.toHaveAttribute('aria-current'); }); it('adds has-substeps class when hasSubsteps is true', () => { render(_jsx(ProgressList, { headingLevel: 3, children: _jsx(ProgressList.Step, { hasSubsteps: true, heading: "Test Step", children: "Content" }) })); const step = screen.getByRole('listitem'); expect(step).toHaveClass('ams-progress-list__step--has-substeps'); }); it('does not add has-substeps modifier when hasSubsteps is not set', () => { render(_jsx(ProgressList, { headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "Test Step", children: "Content" }) })); const step = screen.getByRole('listitem'); expect(step).not.toHaveClass('ams-progress-list__step--has-substeps'); }); it('renders children inside the panel', () => { const { container, getByText } = render(_jsx(ProgressList, { headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "Test Step", children: _jsx("span", { children: "Inner child" }) }) })); const panel = container.querySelector('.ams-progress-list__panel'); expect(panel).toBeInTheDocument(); expect(panel).toContainElement(getByText('Inner child')); }); it('renders the arrow icon only when status is current', () => { const { container: currentContainer } = render(_jsx(ProgressList, { headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "Current", status: "current", children: "Content" }) })); const currentMarkerShape = currentContainer.querySelector('.ams-progress-list__marker-shape'); expect(currentMarkerShape?.querySelector('svg')).toBeInTheDocument(); const { container: nonCurrentContainer } = render(_jsx(ProgressList, { headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "Not current", children: "Content" }) })); const nonCurrentMarkerShape = nonCurrentContainer.querySelector('.ams-progress-list__marker-shape'); expect(nonCurrentMarkerShape?.querySelector('svg')).not.toBeInTheDocument(); }); it('renders substep markers inside the panel', () => { const { container } = render(_jsx(ProgressList, { headingLevel: 3, children: _jsx(ProgressList.Step, { hasSubsteps: true, heading: "Test Step", status: "current", children: _jsxs(ProgressList.Substeps, { children: [_jsx(ProgressList.Substep, { children: "Substep one" }), _jsx(ProgressList.Substep, { children: "Substep two" })] }) }) })); const step = container.querySelector('.ams-progress-list__step'); const substepMarkers = container.querySelectorAll('.ams-progress-list-substeps__marker'); expect(step).not.toHaveClass('ams-progress-list__step--collapsed'); expect(substepMarkers).toHaveLength(2); substepMarkers.forEach((marker) => expect(marker).toBeInTheDocument()); }); it('supports ForwardRef in React', () => { const ref = createRef(); render(_jsx(ProgressList, { headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "Test Step", ref: ref, children: "Content" }) })); const step = screen.getByRole('listitem'); expect(ref.current).toBe(step); }); it('does not render a button by default', () => { render(_jsx(ProgressList, { headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "Test Step", children: "Content" }) })); expect(screen.queryByRole('button')).not.toBeInTheDocument(); expect(screen.getByRole('heading', { level: 3, name: 'Test Step' })).toBeInTheDocument(); }); it('does not render the chevron icon by default', () => { const { container } = render(_jsx(ProgressList, { headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "Test Step", children: "Content" }) })); const heading = screen.getByRole('heading', { name: /Test Step/i }); expect(heading).toBeInTheDocument(); const icon = container.querySelector('.ams-progress-list__heading .ams-progress-list__icon'); expect(icon).not.toBeInTheDocument(); }); it('always shows content by default, even for completed steps', () => { render(_jsx(ProgressList, { headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "Test Step", status: "completed", children: "Content" }) })); const step = screen.getByRole('listitem'); expect(step).not.toHaveClass('ams-progress-list__step--collapsed'); }); it('ignores defaultCollapsed by default', () => { render(_jsx(ProgressList, { headingLevel: 3, children: _jsx(ProgressList.Step, { defaultCollapsed: true, heading: "Test Step", children: "Content" }) })); const step = screen.getByRole('listitem'); expect(step).not.toHaveClass('ams-progress-list__step--collapsed'); }); it('passes additional props', () => { render(_jsx(ProgressList.Step, { "aria-hidden": "false", "data-test": "data-test", heading: "test step", id: "id" })); const component = screen.getByRole('listitem'); expect(component).toHaveAttribute('aria-hidden', 'false'); expect(component).toHaveAttribute('id', 'id'); expect(component).toHaveAttribute('data-test', 'data-test'); }); describe('when collapsible', () => { it('renders a button inside the heading', () => { render(_jsx(ProgressList, { collapsible: true, headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "Test Step", children: "Content" }) })); const button = screen.getByRole('button', { name: /Test Step/ }); expect(button).toBeInTheDocument(); expect(button).toHaveClass('ams-progress-list__button'); }); it('renders the chevron icon inside the button', () => { render(_jsx(ProgressList, { collapsible: true, headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "Test Step", children: "Content" }) })); const button = screen.getByRole('button', { name: /Test Step/ }); const icon = button.querySelector('svg'); expect(icon).toBeInTheDocument(); }); it('adds the collapsed class when the step is collapsed', () => { render(_jsx(ProgressList, { collapsible: true, headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "Test Step", status: "completed", children: "Content" }) })); const step = screen.getByRole('listitem'); expect(step).toHaveClass('ams-progress-list__step--collapsed'); }); it('does not add the collapsed class when the step is expanded', () => { render(_jsx(ProgressList, { collapsible: true, headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "Test Step", children: "Content" }) })); const step = screen.getByRole('listitem'); expect(step).not.toHaveClass('ams-progress-list__step--collapsed'); }); it('does not collapse when status is current', () => { render(_jsx(ProgressList, { collapsible: true, headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "Test Step", status: "current", children: "Content" }) })); const step = screen.getByRole('listitem'); expect(step).not.toHaveClass('ams-progress-list__step--collapsed'); }); it('expands a completed step when defaultCollapsed is false', () => { render(_jsx(ProgressList, { collapsible: true, headingLevel: 3, children: _jsx(ProgressList.Step, { defaultCollapsed: false, heading: "Test Step", status: "completed", children: "Content" }) })); const step = screen.getByRole('listitem'); expect(step).not.toHaveClass('ams-progress-list__step--collapsed'); }); it('collapses when defaultCollapsed is true', () => { render(_jsx(ProgressList, { collapsible: true, headingLevel: 3, children: _jsx(ProgressList.Step, { defaultCollapsed: true, heading: "Test Step", children: "Content" }) })); const step = screen.getByRole('listitem'); expect(step).toHaveClass('ams-progress-list__step--collapsed'); }); it('removes the collapsed class when the button is clicked', () => { render(_jsx(ProgressList, { collapsible: true, headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "Test Step", status: "completed", children: "Content" }) })); const step = screen.getByRole('listitem'); const button = screen.getByRole('button', { name: /Test Step/ }); expect(step).toHaveClass('ams-progress-list__step--collapsed'); fireEvent.click(button); expect(step).not.toHaveClass('ams-progress-list__step--collapsed'); }); it('toggles collapsed state when the button is clicked', () => { render(_jsx(ProgressList, { collapsible: true, headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "Test Step", status: "completed", children: "Content" }) })); const step = screen.getByRole('listitem'); const button = screen.getByRole('button', { name: /Test Step/ }); expect(step).toHaveClass('ams-progress-list__step--collapsed'); fireEvent.click(button); expect(step).not.toHaveClass('ams-progress-list__step--collapsed'); fireEvent.click(button); expect(step).toHaveClass('ams-progress-list__step--collapsed'); }); it('sets aria-expanded on the button', () => { render(_jsx(ProgressList, { collapsible: true, headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "Test Step", status: "completed", children: "Content" }) })); const button = screen.getByRole('button', { name: /Test Step/ }); expect(button).toHaveAttribute('aria-expanded', 'false'); fireEvent.click(button); expect(button).toHaveAttribute('aria-expanded', 'true'); }); it('links the button to the panel via aria-controls', () => { const { container } = render(_jsx(ProgressList, { collapsible: true, headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "Test Step", children: "Content" }) })); const button = screen.getByRole('button', { name: /Test Step/ }); const panelId = button.getAttribute('aria-controls'); const panel = container.querySelector(`[id="${panelId}"]`); expect(panelId).toBeTruthy(); expect(panel).toBeInTheDocument(); expect(panel).toHaveClass('ams-progress-list__panel'); }); it('calls onToggle with the new expanded state when the button is clicked', () => { const onToggle = vi.fn(); render(_jsx(ProgressList, { collapsible: true, headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "Test Step", onToggle: onToggle, status: "completed", children: "Content" }) })); const button = screen.getByRole('button', { name: /Test Step/ }); fireEvent.click(button); expect(onToggle).toHaveBeenCalledTimes(1); expect(onToggle).toHaveBeenCalledWith(true); fireEvent.click(button); expect(onToggle).toHaveBeenCalledTimes(2); expect(onToggle).toHaveBeenLastCalledWith(false); }); it('does not throw when onToggle is not provided', () => { render(_jsx(ProgressList, { collapsible: true, headingLevel: 3, children: _jsx(ProgressList.Step, { heading: "Test Step", children: "Content" }) })); const button = screen.getByRole('button', { name: /Test Step/ }); expect(() => fireEvent.click(button)).not.toThrow(); }); }); });