UNPKG

@kadconsulting/dry

Version:
237 lines 9.11 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { render, screen, waitFor, fireEvent } from '@testing-library/react'; import { act } from 'react-dom/test-utils'; import Wizard from './Wizard'; const MockStepComponent = ({ stepState, onStepChange, }) => (_jsxs("div", { children: [_jsx("span", { children: "Step Content" }), _jsx("button", { onClick: () => onStepChange && onStepChange({ test: 'state' }), children: "Update Step State" }), stepState && _jsxs("span", { children: ["Step State: ", JSON.stringify(stepState)] })] })); const mockSteps = [ { title: 'Step 1', text: 'Step 1 Text', component: _jsx(MockStepComponent, {}), }, { title: 'Step 2', text: 'Step 2 Text', component: _jsx(MockStepComponent, {}), }, { title: 'Step 3', text: 'Step 3 Text', component: _jsx(MockStepComponent, {}), }, ]; describe('Wizard', () => { beforeAll(() => { window.scrollTo = jest.fn(); }); it('renders with a wizard className', () => { // ARRANGE const { container } = render(_jsx(Wizard, { steps: mockSteps })); // ASSERT expect(container.firstChild).toHaveClass('wizard'); }); it('renders the first step by default', () => { // ARRANGE & ACT render(_jsx(Wizard, { steps: mockSteps })); // ASSERT expect(screen.getByText('Step 1 Text')).toBeInTheDocument(); }); it('navigates to the next step when clicking the next button', async () => { // ARRANGE render(_jsx(Wizard, { steps: mockSteps })); // ACT await act(async () => { fireEvent.click(screen.getByText('Next')); }); // ASSERT expect(screen.getByText('Step 2 Text')).toBeInTheDocument(); }); it('navigates to the previous step when clicking the previous button', async () => { // ARRANGE render(_jsx(Wizard, { steps: mockSteps, currentStep: 1 })); // ACT await act(async () => { fireEvent.click(screen.getByText('Previous')); }); // ASSERT expect(screen.getByText('Step 1 Text')).toBeInTheDocument(); }); it('disables the previous button on the first step', () => { // ARRANGE & ACT render(_jsx(Wizard, { steps: mockSteps })); // ASSERT expect(screen.getByText('Previous').closest('button')).toBeDisabled(); }); it('disables the next button on the last step', () => { // ARRANGE & ACT render(_jsx(Wizard, { steps: mockSteps, currentStep: 2 })); // ASSERT expect(screen.getByText('Next').closest('button')).toBeDisabled(); }); it('calls onStepChange when navigating', async () => { // ARRANGE const onStepChange = jest.fn(); render(_jsx(Wizard, { steps: mockSteps, onStepChange: onStepChange })); // ACT await act(async () => { fireEvent.click(screen.getByText('Next')); }); // ASSERT await waitFor(() => { expect(onStepChange).toHaveBeenCalledWith(1); }); }); it('displays error message when provided', () => { // ARRANGE & ACT render(_jsx(Wizard, { steps: mockSteps, error: 'Test error message' })); // ASSERT expect(screen.getByText('Test error message')).toBeInTheDocument(); }); it('uses custom button labels when provided', () => { // ARRANGE & ACT render(_jsx(Wizard, { steps: mockSteps, nextButtonLabel: 'Continue', previousButtonLabel: 'Back' })); // ASSERT expect(screen.getByText('Continue')).toBeInTheDocument(); expect(screen.getByText('Back')).toBeInTheDocument(); }); it('hides progress bar when hideProgressBar is true', () => { // ARRANGE & ACT const { container } = render(_jsx(Wizard, { steps: mockSteps, hideProgressBar: true })); // ASSERT expect(container.querySelector('.progress-steps')).not.toBeInTheDocument(); }); it('calls onStepChanging before changing steps', async () => { // ARRANGE const onStepChanging = jest.fn().mockResolvedValue(true); render(_jsx(Wizard, { steps: mockSteps, onStepChanging: onStepChanging })); // ACT await act(async () => { fireEvent.click(screen.getByText('Next')); }); // ASSERT await waitFor(() => { expect(onStepChanging).toHaveBeenCalledWith(1); }); }); it('prevents step change when validate function returns false', async () => { // ARRANGE const validateMock = jest.fn().mockReturnValue(false); const customSteps = [ { ...mockSteps[0], validate: validateMock }, ...mockSteps.slice(1), ]; render(_jsx(Wizard, { steps: customSteps })); // ACT await act(async () => { fireEvent.click(screen.getByText('Next')); }); // ASSERT await waitFor(() => { expect(validateMock).toHaveBeenCalled(); expect(screen.getByText('Step 1 Text')).toBeInTheDocument(); }); }); it('calls onNext and onPrevious functions when provided', async () => { // ARRANGE const onNextMock = jest.fn().mockResolvedValue(undefined); const onPreviousMock = jest.fn().mockResolvedValue(undefined); const customSteps = [ { ...mockSteps[0], onNext: onNextMock }, { ...mockSteps[1], onPrevious: onPreviousMock }, mockSteps[2], ]; render(_jsx(Wizard, { steps: customSteps })); // ACT & ASSERT for onNext await act(async () => { fireEvent.click(screen.getByText('Next')); }); await waitFor(() => { expect(onNextMock).toHaveBeenCalled(); }); // ACT & ASSERT for onPrevious await act(async () => { fireEvent.click(screen.getByText('Previous')); }); await waitFor(() => { expect(onPreviousMock).toHaveBeenCalled(); }); }); it('renders loading state when isLoading is true', () => { // ARRANGE & ACT render(_jsx(Wizard, { steps: mockSteps, loading: true })); // ASSERT expect(screen.getByLabelText('Loading')).toBeInTheDocument(); }); it('handles steps with noNextButton property', () => { // ARRANGE const customSteps = [ { ...mockSteps[0], noNextButton: true }, ...mockSteps.slice(1), ]; // ACT render(_jsx(Wizard, { steps: customSteps })); // ASSERT expect(screen.queryByText('Next')).not.toBeInTheDocument(); }); it('handles steps with removeButtons property', () => { // ARRANGE const customSteps = [ { ...mockSteps[0], removeButtons: true }, ...mockSteps.slice(1), ]; // ACT render(_jsx(Wizard, { steps: customSteps })); // ASSERT expect(screen.queryByText('Next')).not.toBeInTheDocument(); expect(screen.queryByText('Previous')).not.toBeInTheDocument(); }); it('handles stepState and onStepChange', async () => { // ARRANGE render(_jsx(Wizard, { steps: mockSteps })); // ACT await act(async () => { fireEvent.click(screen.getByText('Update Step State')); }); // ASSERT // This test doesn't actually assert anything, but it ensures that // the component doesn't throw an error when stepState is updated }); it('handles undefined externalCurrentStep', () => { // ARRANGE const { rerender } = render(_jsx(Wizard, { steps: mockSteps })); // ACT rerender(_jsx(Wizard, { steps: mockSteps, currentStep: undefined })); // ASSERT expect(screen.getByText('Step 1 Text')).toBeInTheDocument(); }); it('handles step validation', async () => { // ARRANGE const validateMock = jest.fn().mockReturnValue(true); const customSteps = [ { ...mockSteps[0], validate: validateMock }, ...mockSteps.slice(1), ]; render(_jsx(Wizard, { steps: customSteps })); // ACT await act(async () => { fireEvent.click(screen.getByText('Next')); }); // ASSERT expect(validateMock).toHaveBeenCalled(); expect(screen.getByText('Step 2 Text')).toBeInTheDocument(); }); it('handles steps without onNext or onPrevious', async () => { // ARRANGE render(_jsx(Wizard, { steps: mockSteps })); // ACT & ASSERT await act(async () => { fireEvent.click(screen.getByText('Next')); }); expect(screen.getByText('Step 2 Text')).toBeInTheDocument(); await act(async () => { fireEvent.click(screen.getByText('Previous')); }); expect(screen.getByText('Step 1 Text')).toBeInTheDocument(); }); }); //# sourceMappingURL=Wizard.test.js.map