import React from 'react'; import { render, screen } from '@testing-library/react'; import { Wizard, WizardStepFunctionType, WizardStep } from '../Wizard'; import { DrawerPanelContent, DrawerColorVariant, DrawerHead } from '../../Drawer'; import userEvent from '@testing-library/user-event'; describe('Wizard', () => { test('Wizard should match snapshot', () => { const steps: WizardStep[] = [ { name: 'A', id: 'step-A', component:

Step 1

}, { name: 'B', id: 'step-B', steps: [ { name: 'B-1', id: 'step-B-1', component:

Step 2

, enableNext: true }, { name: 'B-2', id: 'step-B-2', component:

Step 3

, enableNext: false } ] }, { name: 'C', id: 'step-C', component:

Step 4

}, { name: 'D', id: 'step-D', component:

Step 5

} ]; const onBack: WizardStepFunctionType = step => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const name = { step }; }; const { asFragment } = render( ); expect(asFragment()).toMatchSnapshot(); }); test('Expandable Nav Wizard should match snapshot', () => { const steps: WizardStep[] = [ { name: 'A', component:

Step 1

}, { name: 'B', steps: [ { name: 'B-1', component:

Step 2

, enableNext: true }, { name: 'B-2', component:

Step 3

, enableNext: false } ] }, { name: 'C', component:

Step 4

}, { name: 'D', component:

Step 5

} ]; const onBack: WizardStepFunctionType = step => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const name = { step }; }; const { asFragment } = render( ); expect(asFragment()).toMatchSnapshot(); }); test('bare wiz', () => { const steps: WizardStep[] = [{ name: 'A', component:

Step 1

}]; const { asFragment } = render( ); expect(asFragment()).toMatchSnapshot(); }); test('wiz with title', () => { const steps: WizardStep[] = [{ name: 'A', component:

Step 1

}]; render(); expect(screen.getByRole('heading', { name: 'Wizard' })).toBeInTheDocument(); }); test('wiz with drawer', () => { const wizDrawerPanelContent = ( This wizard has a drawer with drawer panel content ); const steps: WizardStep[] = [{ name: 'A', component:

Step 1

, drawerPanelContent: wizDrawerPanelContent }]; render(); expect(screen.getByRole('heading', { name: 'Wizard with drawer' })).toBeInTheDocument(); expect(screen.getByText('This wizard has a drawer with drawer panel content')).toBeInTheDocument(); }); test('wiz with title and navAriaLabel combination', () => { const steps: WizardStep[] = [{ name: 'A', component:

Step 1

}]; render(); const nav = screen.getByLabelText('Some label'); expect(screen.getByRole('heading', { name: 'Wizard' })).toBeInTheDocument(); expect(nav).toBeInTheDocument(); expect(nav).toHaveAttribute('aria-labelledby', 'pf-wizard-title-5'); }); test('wiz with title, navAriaLabel, and mainAriaLabel combination', () => { const steps: WizardStep[] = [{ name: 'A', component:

Step 1

}]; render( ); expect(screen.getByRole('heading', { name: 'Wizard' })).toBeInTheDocument(); expect(screen.getByLabelText('nav aria-label')).toBeInTheDocument(); expect(screen.getByLabelText('main aria-label')).toBeInTheDocument(); }); test('wiz with navAriaLabel and mainAriaLabel but without title', () => { const steps: WizardStep[] = [{ name: 'A', component:

Step 1

}]; render( ); expect(screen.getByLabelText('nav aria-label')).toBeInTheDocument(); expect(screen.getByLabelText('main aria-label')).toBeInTheDocument(); }); test('wiz with navAriaLabel and navAriaLabelledby and without title', () => { const steps: WizardStep[] = [{ name: 'A', component:

Step 1

}]; render( ); const nav = screen.getByLabelText('nav aria-label'); expect(nav).toBeInTheDocument(); expect(nav).toHaveAttribute('aria-labelledby', 'nav-aria-labelledby'); }); test('wiz with navAriaLabel and navAriaLabelledby and without title', () => { const steps: WizardStep[] = [{ name: 'A', component:

Step 1

}]; render( ); const main = screen.getByLabelText('main aria-label'); expect(main).toBeInTheDocument(); expect(main).toHaveAttribute('aria-labelledby', 'main-aria-labelledby'); }); test('wiz with title, navAriaLabelledBy, navAriaLabel, mainAriaLabel, and mainAriaLabelledby', () => { const steps: WizardStep[] = [{ name: 'A', component:

Step 1

}]; render( ); const nav = screen.getByLabelText('nav aria-label'); expect(nav).toBeInTheDocument(); expect(nav).toHaveAttribute('aria-labelledby', 'nav-aria-labelledby'); const main = screen.getByLabelText('main aria-label'); expect(main).toBeInTheDocument(); expect(main).toHaveAttribute('aria-labelledby', 'main-aria-labelledby'); }); test('wiz with onCurrentStepChanged setter', async () => { const stepA = { name: 'A', component:

Step 1

}; const stepB = { name: 'B', component:

Step 2

}; const stepC = { name: 'C', component:

Step 3

}; const steps: WizardStep[] = [ stepA, stepB, stepC ]; const setter = jest.fn(); const user = userEvent.setup(); render( ); expect(setter).toHaveBeenLastCalledWith(expect.objectContaining(stepA)); await user.click(screen.getByText(/next/i)); expect(setter).toHaveBeenLastCalledWith(expect.objectContaining(stepB)); await user.click(screen.getByText(/next/i)); expect(setter).toHaveBeenLastCalledWith(expect.objectContaining(stepC)); await user.click(screen.getByText('A')); expect(setter).toHaveBeenLastCalledWith(expect.objectContaining(stepA)); await user.click(screen.getByText(/next/i)); expect(setter).toHaveBeenLastCalledWith(expect.objectContaining(stepB)); await user.click(screen.getByText(/back/i)); expect(setter).toHaveBeenLastCalledWith(expect.objectContaining(stepA)); }); }); test('wiz with disabled steps', () => { const steps: WizardStep[] = [ { name: 'A', component:

Step 1

}, { name: 'B', component:

Step 2

, isDisabled: true }, { name: 'C', component:

Step 3

}, { name: 'E', component:

Step 4

, isDisabled: true }, { name: 'G', component:

Step 5

}, ]; render( ); expect(screen.getByRole('button',{ name: "B" })).toBeDisabled(); expect(screen.getByRole('button',{ name: "E" })).toBeDisabled(); }); test('wiz skip the step disabled when press the next/back button', async () => { const steps: WizardStep[] = [ { name: 'A', component:

Step 1

}, { name: 'B', component:

Step 2

, isDisabled: true }, { name: 'C', component:

Step 3

}, ]; const user = userEvent.setup(); render( ); await user.click(screen.getByRole('button', { name: 'Next' })); expect(screen.getByRole('button',{ name: "C" })).toHaveClass('pf-m-current') await user.click(screen.getByRole('button', { name: 'Back' })); expect(screen.getByRole('button',{ name: "A" })).toHaveClass('pf-m-current') }); test('wiz skip the step when click on the nav item disabled', async () => { const steps: WizardStep[] = [ { name: 'A', component:

Step 1

}, { name: 'B', component:

Step 2

, isDisabled: true }, { name: 'C', component:

Step 3

} ]; const user = userEvent.setup(); render( ); const navItemButton = screen.getByRole('button',{ name: "B" }) const navItemButtonSelected = screen.getByRole('button',{ name: "A" }) await user.click(navItemButton); expect(navItemButton).not.toHaveClass('pf-m-current') expect(navItemButtonSelected).toHaveClass('pf-m-current') }); test('wiz with disable sub step', () => { const steps: WizardStep[] = [ { name: 'A', steps: [ { name: 'A-1', component:

Substep A content

}, { name: 'A-2', component:

Substep B content

, isDisabled: true } ] }, ]; render( ); expect(screen.getByRole('button',{ name: "A-2" })).toBeDisabled(); }); test('startAtStep can be used to externally control the current step of the wizard', async () => { const WizardTest = () => { const [step, setStep] = React.useState(1); const incrementStep = () => { setStep(prevStep => prevStep + 1); }; const steps: WizardStep[] = [ { name: 'A', component:

Step 1

}, { name: 'B', component:

Step 2

}, { name: 'C', component:

Step 3

} ]; return ( <> ); }; const user = userEvent.setup(); render(); expect(screen.queryByText('Step 2')).not.toBeInTheDocument(); await user.click(screen.getByRole('button', { name: 'Increment step'})) expect(screen.getByText('Step 2')).toBeVisible(); });