UserTable.test.tsx
4.85 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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// REQ-USR-003: UserTable 表格单测(BR1/BR6/BR11/BR12/BR14/D8)
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { renderShell } from './renderShell';
import UserTable from '../../src/pages/usr/UserList/UserTable';
import type { UserVO } from '../../src/api/types';
function makeUser(id: number, over?: Partial<UserVO>): UserVO {
return {
id,
sUserName: `user${id}`,
employeeName: `员工${id}`,
sUserNo: `U00${id}`,
departmentName: `部门${id}`,
sUserType: '普通用户',
sLanguage: '中文',
iIsVoid: 0,
tLastLoginDate: '2024-02-01T10:00:00',
sCreator: 'admin',
tCreateDate: '2024-01-01T00:00:00',
...over,
};
}
interface Props {
rows?: UserVO[];
loading?: boolean;
total?: number;
pageNum?: number;
pageSize?: number;
}
function setup(props?: Props) {
const onChangePage = vi.fn();
const onRowDoubleClick = vi.fn();
const onSelectRow = vi.fn();
renderShell(
<UserTable
rows={props?.rows ?? [makeUser(1), makeUser(2)]}
loading={props?.loading ?? false}
total={props?.total ?? 2}
pageNum={props?.pageNum ?? 1}
pageSize={props?.pageSize ?? 10}
onChangePage={onChangePage}
onRowDoubleClick={onRowDoubleClick}
onSelectRow={onSelectRow}
/>,
{ preloadedAuth: { token: 't', user: { id: 1, sUserName: 'a', sUserType: 'x', sLanguage: '中文' } } },
);
return { onChangePage, onRowDoubleClick, onSelectRow };
}
const HEADERS = [
'序号',
'用户名',
'员工名',
'用户号',
'部门',
'用户类型',
'语言',
'作废',
'登录日期',
'制单人',
'制单日期',
];
describe('UserTable', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('renders 11 column headers in order', () => {
setup();
const headerCells = screen.getAllByRole('columnheader');
const texts = headerCells.map((c) => c.textContent ?? '');
for (const h of HEADERS) {
expect(texts.some((t) => t.includes(h))).toBe(true);
}
// 业务列(序号..制单日期)顺序一致(排除首个 radio 选择列空表头)
const businessTexts = texts.filter((t) => HEADERS.some((h) => t.includes(h)));
const orderIdx = HEADERS.map((h) => businessTexts.findIndex((t) => t.includes(h)));
const sorted = [...orderIdx].sort((a, b) => a - b);
expect(orderIdx).toEqual(sorted);
});
it('serial number is page-aware (BR1)', () => {
setup({ pageNum: 2, pageSize: 10, rows: [makeUser(11), makeUser(12)], total: 30 });
// 第 2 页首行序号 = (2-1)*10 + 0 + 1 = 11
expect(screen.getByText('11')).toBeInTheDocument();
expect(screen.getByText('12')).toBeInTheDocument();
});
it('作废 column renders 否/是 read-only (BR6)', async () => {
const user = userEvent.setup();
const { onSelectRow } = setup({
rows: [makeUser(1, { iIsVoid: 0 }), makeUser(2, { iIsVoid: 1 })],
total: 2,
});
expect(screen.getByText('否')).toBeInTheDocument();
expect(screen.getByText('是')).toBeInTheDocument();
// 点击「作废」单元不触发任何选择 / 写动作
await user.click(screen.getByText('是'));
expect(onSelectRow).not.toHaveBeenCalled();
});
it('double click row navigates via onRowDoubleClick (BR12)', async () => {
const user = userEvent.setup();
const { onRowDoubleClick } = setup({ rows: [makeUser(7)], total: 1 });
await user.dblClick(screen.getByText('user7'));
expect(onRowDoubleClick).toHaveBeenCalledTimes(1);
expect(onRowDoubleClick.mock.calls[0][0]).toMatchObject({ id: 7 });
});
it('controlled pagination reflects current/pageSize/total + showTotal (BR11)', async () => {
const user = userEvent.setup();
const { onChangePage } = setup({
rows: [makeUser(1)],
total: 37,
pageNum: 1,
pageSize: 10,
});
expect(screen.getByText('共 37 条记录')).toBeInTheDocument();
// 点下一页 → onChangePage 收到 pageNum=2(renderShell 注入 zhCN locale,标题为「下一页」)
await user.click(screen.getByTitle('下一页'));
expect(onChangePage).toHaveBeenCalled();
expect(onChangePage.mock.calls[0][0]).toBe(2);
expect(onChangePage.mock.calls[0][1]).toBe(10);
});
it('empty rows shows Empty 暂无匹配的用户 (BR14)', () => {
setup({ rows: [], total: 0 });
expect(screen.getByText('暂无匹配的用户')).toBeInTheDocument();
});
it('radio rowSelection single-select reports key without query (D8)', async () => {
const user = userEvent.setup();
const { onSelectRow, onChangePage } = setup({ rows: [makeUser(5)], total: 1 });
const radio = screen.getByRole('radio');
await user.click(radio);
expect(onSelectRow).toHaveBeenCalledWith(5);
// 选择不触发取数 / 翻页
expect(onChangePage).not.toHaveBeenCalled();
});
});