Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modal: add more unit tests #54569

Merged
merged 3 commits into from
Sep 19, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 10 additions & 18 deletions packages/components/src/confirm-dialog/test/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
/**
* External dependencies
*/
import {
render,
screen,
fireEvent,
waitForElementToBeRemoved,
waitFor,
} from '@testing-library/react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

/**
Expand Down Expand Up @@ -137,6 +131,7 @@ describe( 'Confirm', () => {
} );

it( 'should not render if dialog is closed by clicking the overlay, and the `onCancel` callback should be called', async () => {
const user = userEvent.setup();
const onCancel = jest.fn().mockName( 'onCancel()' );

render(
Expand All @@ -147,11 +142,9 @@ describe( 'Confirm', () => {

const confirmDialog = screen.getByRole( 'dialog' );

//The overlay click is handled by detecting an onBlur from the modal frame.
// TODO: replace with `@testing-library/user-event`
fireEvent.blur( confirmDialog );

await waitForElementToBeRemoved( confirmDialog );
// Disable reason: Semantic queries can’t reach the overlay.
// eslint-disable-next-line testing-library/no-node-access
await user.click( confirmDialog.parentElement );

expect( confirmDialog ).not.toBeInTheDocument();
expect( onCancel ).toHaveBeenCalled();
Expand Down Expand Up @@ -315,6 +308,7 @@ describe( 'Confirm', () => {
} );

it( 'should call the `onCancel` callback if the overlay is clicked', async () => {
const user = userEvent.setup();
const onCancel = jest.fn().mockName( 'onCancel()' );

render(
Expand All @@ -329,13 +323,11 @@ describe( 'Confirm', () => {

const confirmDialog = screen.getByRole( 'dialog' );

//The overlay click is handled by detecting an onBlur from the modal frame.
// TODO: replace with `@testing-library/user-event`
fireEvent.blur( confirmDialog );
// Disable reason: Semantic queries can’t reach the overlay.
// eslint-disable-next-line testing-library/no-node-access
await user.click( confirmDialog.parentElement );

// Wait for a DOM side effect here, so that the `queueBlurCheck` in the
// `useFocusOutside` hook properly executes its timeout task.
await waitFor( () => expect( onCancel ).toHaveBeenCalled() );
expect( onCancel ).toHaveBeenCalled();
} );

it( 'should call the `onCancel` callback if the `Escape` key is pressed', async () => {
Expand Down
107 changes: 107 additions & 0 deletions packages/components/src/modal/test/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,113 @@ describe( 'Modal', () => {
expect( opener ).toHaveFocus();
} );

it( 'should request closing of any non nested modal when opened', async () => {
const user = userEvent.setup();
const onRequestClose = jest.fn();

const DismissAdjacent = () => {
const [ isShown, setIsShown ] = useState( false );
return (
<>
<Modal onRequestClose={ onRequestClose }>
<button onClick={ () => setIsShown( true ) }>💥</button>
</Modal>
{ isShown && (
<Modal onRequestClose={ () => setIsShown( false ) }>
<p>Adjacent modal content</p>
</Modal>
) }
</>
);
};
render( <DismissAdjacent /> );

await user.click( screen.getByRole( 'button', { name: '💥' } ) );
expect( onRequestClose ).toHaveBeenCalled();
} );

it( 'should support nested modals', async () => {
const user = userEvent.setup();
const onRequestClose = jest.fn();

const NestSupport = () => {
const [ isShown, setIsShown ] = useState( false );
return (
<>
<Modal onRequestClose={ onRequestClose }>
<button onClick={ () => setIsShown( true ) }>🪆</button>
{ isShown && (
<Modal onRequestClose={ () => setIsShown( false ) }>
<p>Nested modal content</p>
</Modal>
) }
</Modal>
</>
);
};
render( <NestSupport /> );

await user.click( screen.getByRole( 'button', { name: '🪆' } ) );
expect( onRequestClose ).not.toHaveBeenCalled();
} );

// TODO enable once nested modals hide outer modals.
it.skip( 'should accessibly hide and show siblings including outer modals', async () => {
const user = userEvent.setup();

const AriaDemo = () => {
const [ isOuterShown, setIsOuterShown ] = useState( false );
const [ isInnerShown, setIsInnerShown ] = useState( false );
return (
<>
<button onClick={ () => setIsOuterShown( true ) }>
Start
</button>
{ isOuterShown && (
<Modal
onRequestClose={ () => setIsOuterShown( false ) }
>
<button onClick={ () => setIsInnerShown( true ) }>
Nest
</button>
{ isInnerShown && (
<Modal
onRequestClose={ () =>
setIsInnerShown( false )
}
>
<p>Nested modal content</p>
</Modal>
) }
</Modal>
) }
</>
);
};
const { container } = render( <AriaDemo /> );

// Opens outer modal > hides container.
await user.click( screen.getByRole( 'button', { name: 'Start' } ) );
expect( container ).toHaveAttribute( 'aria-hidden', 'true' );

// Disable reason: No semantic query can reach the overlay.
// eslint-disable-next-line testing-library/no-node-access
const outer = screen.getByRole( 'dialog' ).parentElement!;

// Opens inner modal > hides outer modal.
await user.click( screen.getByRole( 'button', { name: 'Nest' } ) );
expect( outer ).toHaveAttribute( 'aria-hidden', 'true' );

// Closes inner modal > Unhides outer modal and container stays hidden.
await user.keyboard( '[Escape]' );
expect( outer ).not.toHaveAttribute( 'aria-hidden' );
expect( container ).toHaveAttribute( 'aria-hidden', 'true' );

// Closes outer modal > Unhides container.
await user.keyboard( '[Escape]' );
expect( container ).not.toHaveAttribute( 'aria-hidden' );
} );

it( 'should render `headerActions` React nodes', async () => {
render(
<Modal
Expand Down