|
1 |
| -import { describe, it, expect, beforeEach } from 'vitest'; |
| 1 | +import { describe, it, expect, vi } from 'vitest'; |
2 | 2 | import { render, screen, within } from '@testing-library/svelte';
|
3 | 3 | import userEvent from '@testing-library/user-event';
|
| 4 | +import type { ComponentProps } from 'svelte'; |
4 | 5 | import Modal from '../modal.svelte';
|
5 |
| -import { writable, get } from 'svelte/store'; |
6 | 6 |
|
7 | 7 | describe('Modal', () => {
|
8 |
| - let isOpen = writable(true); |
| 8 | + const onClose = vi.fn(); |
9 | 9 |
|
10 |
| - beforeEach(() => { |
11 |
| - isOpen = writable(true); |
| 10 | + const renderSubject = (props: ComponentProps<Modal>) => { |
| 11 | + const { component } = render(Modal, props); |
| 12 | + component.$on('close', onClose); |
| 13 | + }; |
| 14 | + |
| 15 | + it('should be visible if open is true ', () => { |
| 16 | + renderSubject({ isOpen: true }); |
| 17 | + |
| 18 | + const modal = screen.queryByRole('dialog'); |
| 19 | + |
| 20 | + expect(modal).toBeInTheDocument(); |
| 21 | + expect(modal).toHaveAttribute('aria-modal', 'true'); |
| 22 | + expect(onClose).not.toHaveBeenCalled(); |
| 23 | + }); |
| 24 | + |
| 25 | + it('should not be visible if open is false', () => { |
| 26 | + renderSubject({ isOpen: false }); |
| 27 | + |
| 28 | + const modal = screen.queryByRole('dialog'); |
| 29 | + |
| 30 | + expect(modal).not.toBeInTheDocument(); |
| 31 | + expect(onClose).not.toHaveBeenCalled(); |
12 | 32 | });
|
13 | 33 |
|
14 | 34 | it('should close modal when close icon button is clicked', async () => {
|
15 |
| - render(Modal, { isOpen }); |
16 | 35 | const user = userEvent.setup();
|
| 36 | + renderSubject({ isOpen: true }); |
17 | 37 |
|
18 | 38 | const modal = screen.getByRole('dialog');
|
19 | 39 | const closeButton = within(modal).getByRole('button', { name: /close/iu });
|
20 | 40 |
|
21 | 41 | await user.click(closeButton);
|
22 |
| - |
23 |
| - expect(get(isOpen)).toBe(false); |
| 42 | + expect(onClose).toHaveBeenCalledOnce(); |
24 | 43 | });
|
25 | 44 |
|
26 | 45 | it('should close modal when clicked outside the modal', async () => {
|
27 |
| - render(Modal, { isOpen }); |
28 | 46 | const user = userEvent.setup();
|
| 47 | + renderSubject({ isOpen: true }); |
29 | 48 |
|
30 | 49 | const modal = screen.getByRole('dialog');
|
31 | 50 | await user.click(modal.parentElement!);
|
32 | 51 |
|
33 |
| - expect(get(isOpen)).toBe(false); |
| 52 | + expect(onClose).toHaveBeenCalledOnce(); |
34 | 53 | });
|
35 | 54 |
|
36 |
| - it('if open is true, modal should be visible', () => { |
37 |
| - render(Modal, { isOpen }); |
38 |
| - const modal = screen.queryByRole('dialog'); |
39 |
| - expect(modal).toBeInTheDocument(); |
40 |
| - expect(modal).toHaveAttribute('aria-modal', 'true'); |
41 |
| - }); |
| 55 | + it('should close modal when escape key is pressed', async () => { |
| 56 | + const user = userEvent.setup(); |
| 57 | + renderSubject({ isOpen: true }); |
42 | 58 |
|
43 |
| - it('if open is false, modal should not be visible', () => { |
44 |
| - isOpen.set(false); |
45 |
| - render(Modal, { isOpen }); |
46 |
| - const modal = screen.queryByRole('dialog'); |
47 |
| - expect(modal).not.toBeInTheDocument(); |
| 59 | + await user.keyboard('{Escape}'); |
| 60 | + |
| 61 | + expect(onClose).toHaveBeenCalledOnce(); |
48 | 62 | });
|
49 | 63 |
|
50 |
| - it('should close modal when escape key is pressed', async () => { |
51 |
| - render(Modal, { isOpen }); |
| 64 | + it('should not emit close events on escape if the modal is closed', async () => { |
52 | 65 | const user = userEvent.setup();
|
| 66 | + renderSubject({ isOpen: false }); |
| 67 | + |
53 | 68 | await user.keyboard('{Escape}');
|
54 |
| - expect(get(isOpen)).toBe(false); |
| 69 | + |
| 70 | + expect(onClose).not.toHaveBeenCalled(); |
55 | 71 | });
|
56 | 72 |
|
57 | 73 | it('should focus on heading element on mount', () => {
|
58 |
| - render(Modal, { isOpen }); |
| 74 | + render(Modal, { isOpen: true }); |
| 75 | + |
59 | 76 | const modal = screen.getByRole('dialog');
|
60 | 77 | const heading = within(modal).getByRole('heading');
|
| 78 | + |
61 | 79 | expect(heading).toHaveFocus();
|
62 | 80 | });
|
63 | 81 | });
|
0 commit comments