AppLayout.shell.test.tsx
3.69 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
// REQ-USR-003: AppLayout 外壳装配 + 标签↔路由同步(ready / navOverlayOpen / tabOpen 态)
import { describe, it, expect } from 'vitest';
import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Routes, Route, useLocation } from 'react-router-dom';
import { renderShell } from './renderShell';
import AppLayout from '../../src/layouts/AppLayout/AppLayout';
import type { AuthUser } from '../../src/api/types';
const ADMIN: AuthUser = { id: 1, sUserName: '朱子纯', sUserType: '超级管理员', sLanguage: '中文' };
function LocProbe() {
const loc = useLocation();
return <div data-testid="loc">{loc.pathname}</div>;
}
function renderLayout(initialEntries: string[]) {
return renderShell(
<Routes>
<Route element={<AppLayout />}>
<Route
path="/"
element={
<>
<LocProbe />
<div data-testid="home-outlet">home-outlet</div>
</>
}
/>
<Route
path="/usr/users"
element={
<>
<LocProbe />
<div data-testid="users-outlet">users-outlet</div>
</>
}
/>
</Route>
</Routes>,
{ initialEntries, preloadedAuth: { token: 't', user: ADMIN } },
);
}
describe('AppLayout shell', () => {
it('renders TopBar + Outlet when ready', () => {
renderLayout(['/']);
// 顶栏(全部导航 + 当前用户)
expect(screen.getByRole('button', { name: '全部导航' })).toBeInTheDocument();
expect(screen.getByText('朱子纯(超级管理员)')).toBeInTheDocument();
// Outlet 子内容
expect(screen.getByTestId('home-outlet')).toBeInTheDocument();
});
it('toggle 全部导航 opens/closes overlay', async () => {
renderLayout(['/']);
expect(screen.queryByTestId('nav-overlay')).not.toBeInTheDocument();
await userEvent.click(screen.getByRole('button', { name: '全部导航' }));
expect(screen.getByTestId('nav-overlay')).toBeInTheDocument();
// 点遮罩关闭
await userEvent.click(screen.getByTestId('nav-overlay-mask'));
expect(screen.queryByTestId('nav-overlay')).not.toBeInTheDocument();
});
it('nav overlay 用户列表 navigates and opens tab', async () => {
renderLayout(['/']);
await userEvent.click(screen.getByRole('button', { name: '全部导航' }));
await userEvent.click(screen.getByRole('button', { name: /用户列表/ }));
// overlay 关闭
expect(screen.queryByTestId('nav-overlay')).not.toBeInTheDocument();
// URL 到 /usr/users
expect(screen.getByTestId('loc').textContent).toBe('/usr/users');
// 顶栏出现「用户列表」标签并激活
const tab = screen.getByTestId('tab-userlist');
expect(tab).toHaveTextContent('用户列表');
expect(tab.getAttribute('aria-pressed')).toBe('true');
});
it('clicking home tab navigates back to /', async () => {
renderLayout(['/']);
// 先打开用户列表标签
await userEvent.click(screen.getByRole('button', { name: '全部导航' }));
await userEvent.click(screen.getByRole('button', { name: /用户列表/ }));
expect(screen.getByTestId('loc').textContent).toBe('/usr/users');
// 点主页标签回 /
await userEvent.click(screen.getByTestId('tab-home'));
expect(screen.getByTestId('loc').textContent).toBe('/');
expect(screen.getByTestId('tab-home').getAttribute('aria-pressed')).toBe('true');
});
it('active tab syncs with current route', () => {
renderLayout(['/usr/users']);
// 直接进 /usr/users,用户列表标签应存在且激活
const tab = screen.getByTestId('tab-userlist');
expect(tab.getAttribute('aria-pressed')).toBe('true');
});
});