-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMobileBottomNav.test.tsx
More file actions
114 lines (93 loc) · 3.28 KB
/
Copy pathMobileBottomNav.test.tsx
File metadata and controls
114 lines (93 loc) · 3.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import { act, render, screen } from '@testing-library/react';
import type { ReactNode } from 'react';
import { describe, expect, it, vi } from 'vitest';
import MobileBottomNav from './MobileBottomNav';
const mockTrackEvent = vi.fn();
vi.mock('next/link', () => ({
default: ({
href,
children,
...props
}: {
href: string;
children: ReactNode;
}) => (
<a href={href} {...props}>
{children}
</a>
),
}));
vi.mock('@/shared/analytics/lib/analytics', () => {
return {
AnalyticsEvents: {
click: 'click',
theme: 'theme',
view: 'view',
},
trackEvent: (...args: unknown[]) => mockTrackEvent(...args),
};
});
describe('MobileBottomNav', () => {
it('renders drawer links when open', () => {
render(<MobileBottomNav pathname="/" visible open />);
expect(screen.getByRole('link', { name: /Home/ })).toBeInTheDocument();
expect(screen.getByRole('link', { name: /Tech/ })).toBeInTheDocument();
expect(screen.getByRole('link', { name: /Life/ })).toBeInTheDocument();
expect(screen.getByRole('link', { name: /Resume/ })).toBeInTheDocument();
});
it('marks active item based on exact home path', async () => {
render(<MobileBottomNav pathname="/" visible open />);
const home = await screen.findByRole('link', { name: /Home/ });
expect(home).toHaveAttribute('aria-current', 'page');
const tech = await screen.findByRole('link', { name: /Tech/ });
expect(tech).not.toHaveAttribute('aria-current');
});
it('marks active item for nested engineering path', async () => {
render(
<MobileBottomNav pathname="/engineering/how-to-test" visible open />
);
const tech = await screen.findByRole('link', { name: /Tech/ });
expect(tech).toHaveAttribute('aria-current', 'page');
});
it('renders drawer shell when open', () => {
render(<MobileBottomNav pathname="/" visible open />);
expect(screen.getByLabelText('모바일 네비게이션')).toBeInTheDocument();
expect(screen.getByText('블로그 섹션과 외부 링크')).toBeInTheDocument();
});
it('calls close handler when backdrop is clicked', () => {
const handleOpenChange = vi.fn();
render(
<MobileBottomNav
pathname="/"
visible
open
onOpenChange={handleOpenChange}
/>
);
screen.getAllByRole('button', { name: '메뉴 닫기' })[0].click();
expect(handleOpenChange).toHaveBeenCalledWith(false);
});
it('tracks analytics on tab click', async () => {
mockTrackEvent.mockClear();
await act(async () => {
render(<MobileBottomNav pathname="/engineering" visible open />);
await Promise.resolve();
});
const resume = screen.getByRole('link', { name: /Resume/ });
await act(async () => {
await Promise.resolve();
resume.dispatchEvent(new MouseEvent('click', { bubbles: true }));
});
expect(mockTrackEvent).toHaveBeenCalledWith('click', {
target: 'mobile_nav_drawer',
destination: '/resume',
});
});
it('hides pointer events when closed', () => {
render(<MobileBottomNav pathname="/" visible open={false} />);
const drawerRoot =
screen.getAllByRole('button', { name: '메뉴 닫기', hidden: true })[0]
.parentElement;
expect(drawerRoot).toHaveClass('pointer-events-none');
});
});