import React from 'react'; import { render, screen } from '@testing-library/react'; import { Wizard, WizardStepFunctionType, WizardStep } from '../Wizard'; import { DrawerPanelContent, DrawerColorVariant, DrawerHead } from '../../../../../src/components/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 navAriaLabel and mainAriaLabel but without title', () => { const steps: WizardStep[] = [{ name: 'A', component:

Step 1

}]; render(); expect(screen.getByLabelText('nav 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 title, navAriaLabelledBy, and navAriaLabel', () => { 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('Does not render with mainAriaLabel or mainAriaLabelledby by default', () => { const steps: WizardStep[] = [{ name: 'A', component:

Step 1

}]; render( ); const main = screen.getByTestId('wizard-test-id'); expect(main).not.toHaveAttribute('aria-labelledby'); expect(main).not.toHaveAttribute('aria-label'); }); 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(); });