MUI DialogをReact Testing Libraryでテストする方法を解説します。
開閉制御、ESCキー・バックドロップクリックでの閉じる動作など、実務で必要なパターンを網羅しています。
動作環境
- @mui/material v6
- @testing-library/react v16
- @testing-library/user-event v14
- vitest v3
基本的なテスト
Dialogの取得
MUI Dialogはdialogロールを持ちます。getByRole('dialog')で取得できます。
import Dialog from '@mui/material/Dialog';
import DialogTitle from '@mui/material/DialogTitle';
import DialogContent from '@mui/material/DialogContent';
import DialogActions from '@mui/material/DialogActions';
import Button from '@mui/material/Button';
import {render, screen} from '@testing-library/react';
const BasicDialog = ({open, onClose}: {open: boolean; onClose: () => void}) => {
return (
<Dialog open={open} onClose={onClose}>
<DialogTitle>タイトル</DialogTitle>
<DialogContent>コンテンツ</DialogContent>
<DialogActions>
<Button onClick={onClose}>閉じる</Button>
</DialogActions>
</Dialog>
);
};
test('Dialogが表示される', () => {
render(<BasicDialog open={true} onClose={vi.fn()} />);
const dialog = screen.getByRole('dialog');
expect(dialog).toBeInTheDocument();
});開閉制御(open prop)
test('open=false の場合、Dialogが表示されない', () => {
render(<BasicDialog open={false} onClose={vi.fn()} />);
const dialog = screen.queryByRole('dialog');
expect(dialog).not.toBeInTheDocument();
});
test('open=true の場合、Dialogが表示される', () => {
render(<BasicDialog open={true} onClose={vi.fn()} />);
const dialog = screen.getByRole('dialog');
expect(dialog).toBeInTheDocument();
});rerenderで開閉をテスト
MUIのDialogはアニメーションがあるため、閉じる際はwaitForで待機します。
import {waitFor} from '@testing-library/react';
test('openをfalseに変更するとDialogが閉じる', async () => {
const onClose = vi.fn();
const {rerender} = render(<BasicDialog open={true} onClose={onClose} />);
// 最初は表示されている
expect(screen.getByRole('dialog')).toBeInTheDocument();
// openをfalseに変更
rerender(<BasicDialog open={false} onClose={onClose} />);
// アニメーション完了を待つ
await waitFor(() => {
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
});
});タイトル・コンテンツの確認
test('タイトルが表示される', () => {
render(<BasicDialog open={true} onClose={vi.fn()} />);
expect(screen.getByText('タイトル')).toBeInTheDocument();
});
test('コンテンツが表示される', () => {
render(<BasicDialog open={true} onClose={vi.fn()} />);
expect(screen.getByText('コンテンツ')).toBeInTheDocument();
});閉じる操作のテスト
ボタンクリックで閉じる
import userEvent from '@testing-library/user-event';
test('閉じるボタンをクリックするとonCloseが呼ばれる', async () => {
const user = userEvent.setup();
const onClose = vi.fn();
render(<BasicDialog open={true} onClose={onClose} />);
await user.click(screen.getByRole('button', {name: '閉じる'}));
expect(onClose).toHaveBeenCalledTimes(1);
});ESCキーで閉じる
test('ESCキーを押すとonCloseが呼ばれる', async () => {
const user = userEvent.setup();
const onClose = vi.fn();
render(<BasicDialog open={true} onClose={onClose} />);
await user.keyboard('{Escape}');
expect(onClose).toHaveBeenCalledTimes(1);
});バックドロップクリックで閉じる
test('バックドロップをクリックするとonCloseが呼ばれる', async () => {
const user = userEvent.setup();
const onClose = vi.fn();
render(<BasicDialog open={true} onClose={onClose} />);
const backdrop = document.querySelector('.MuiBackdrop-root');
expect(backdrop).toBeInTheDocument();
if (backdrop) {
await user.click(backdrop);
}
expect(onClose).toHaveBeenCalledTimes(1);
});
test('Dialog内をクリックしてもonCloseは呼ばれない', async () => {
const user = userEvent.setup();
const onClose = vi.fn();
render(<BasicDialog open={true} onClose={onClose} />);
await user.click(screen.getByText('コンテンツ'));
expect(onClose).not.toHaveBeenCalled();
});disableEscapeKeyDownの動作
ESCキーでの閉じる動作を無効化できます。
const DialogWithEscapeDisabled = ({
open,
onClose,
disableEscapeKeyDown,
}: {
open: boolean;
onClose: () => void;
disableEscapeKeyDown: boolean;
}) => {
return (
<Dialog open={open} onClose={onClose} disableEscapeKeyDown={disableEscapeKeyDown}>
<DialogTitle>タイトル</DialogTitle>
<DialogContent>コンテンツ</DialogContent>
</Dialog>
);
};
test('disableEscapeKeyDown=true の場合、ESCキーでonCloseが呼ばれない', async () => {
const user = userEvent.setup();
const onClose = vi.fn();
render(
<DialogWithEscapeDisabled
open={true}
onClose={onClose}
disableEscapeKeyDown={true}
/>
);
await user.keyboard('{Escape}');
expect(onClose).not.toHaveBeenCalled();
});
test('disableEscapeKeyDown=false の場合、ESCキーでonCloseが呼ばれる', async () => {
const user = userEvent.setup();
const onClose = vi.fn();
render(
<DialogWithEscapeDisabled
open={true}
onClose={onClose}
disableEscapeKeyDown={false}
/>
);
await user.keyboard('{Escape}');
expect(onClose).toHaveBeenCalledTimes(1);
});まとめ
この記事では、MUI DialogをReact Testing Libraryでテストする方法を解説しました。
テストパターン一覧
| パターン | 使用するクエリ/マッチャー |
|---|---|
| Dialogの取得 | getByRole('dialog') |
| 非表示の確認 | queryByRole('dialog') + not.toBeInTheDocument() |
| ボタンクリック | userEvent.click() |
| ESCキー | userEvent.keyboard('{Escape}') |
| バックドロップ | document.querySelector('.MuiBackdrop-root') |
| アニメーション待機 | waitFor() |
ポイント
- Dialogは
getByRole('dialog')で取得、非表示確認はqueryByRoleを使う - MUIのアニメーションがあるため、閉じる際は
waitForで待機 - ESCキーは
userEvent.keyboard('{Escape}')でテスト - バックドロップは
document.querySelector('.MuiBackdrop-root')で取得

コメント