test(web): 添加 createListPageTests 工厂 — 6 类标准测试用例自动生成
This commit is contained in:
8
apps/web/src/test/factories/listPageTests.test.tsx
Normal file
8
apps/web/src/test/factories/listPageTests.test.tsx
Normal file
@@ -0,0 +1,8 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { createListPageTests } from './listPageTests';
|
||||
|
||||
describe('createListPageTests', () => {
|
||||
it('is a function that returns a describe block', () => {
|
||||
expect(typeof createListPageTests).toBe('function');
|
||||
});
|
||||
});
|
||||
128
apps/web/src/test/factories/listPageTests.tsx
Normal file
128
apps/web/src/test/factories/listPageTests.tsx
Normal file
@@ -0,0 +1,128 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { screen, waitFor } from '@testing-library/react';
|
||||
import { http, HttpResponse } from 'msw';
|
||||
import { server } from '../mocks/server';
|
||||
import type { ComponentType } from 'react';
|
||||
import { renderWithProviders } from '../utils/renderWithProviders';
|
||||
|
||||
export interface ListPageTestConfig {
|
||||
/** 页面组件 */
|
||||
Component: ComponentType;
|
||||
/** 列表 API 路径(如 '/api/v1/health/patients') */
|
||||
apiPath: string;
|
||||
/** 表格列名数组 — 用于验证表头 */
|
||||
columns: string[];
|
||||
/** 第一条 mock 数据中会被渲染到表格的文本 */
|
||||
firstRowTexts: string[];
|
||||
/** mock 数据总条数 */
|
||||
totalItems: number;
|
||||
/** 是否有「新建」按钮 */
|
||||
hasCreateButton?: boolean;
|
||||
/** 新建按钮文本(默认 "新建") */
|
||||
createButtonText?: string;
|
||||
/** 是否有搜索/筛选 */
|
||||
hasSearch?: boolean;
|
||||
/** 是否有分页(默认 true) */
|
||||
hasPagination?: boolean;
|
||||
/** 自定义路由(默认 '/') */
|
||||
route?: string;
|
||||
/** 自定义 mock 数据(默认使用空数组 + totalItems) */
|
||||
mockItems?: Record<string, unknown>[];
|
||||
/** 额外测试用例 */
|
||||
extraTests?: () => void;
|
||||
}
|
||||
|
||||
export function createListPageTests(config: ListPageTestConfig) {
|
||||
const {
|
||||
Component,
|
||||
apiPath,
|
||||
columns,
|
||||
totalItems,
|
||||
hasCreateButton = true,
|
||||
createButtonText = '新建',
|
||||
hasSearch = true,
|
||||
hasPagination = true,
|
||||
route = '/',
|
||||
extraTests,
|
||||
} = config;
|
||||
|
||||
describe(`${Component.displayName || Component.name || 'ListPage'}`, () => {
|
||||
function setupMock(items?: Record<string, unknown>[], total?: number) {
|
||||
const mockData = items ?? config.mockItems ?? [];
|
||||
const mockTotal = total ?? totalItems;
|
||||
server.use(
|
||||
http.get(apiPath, () =>
|
||||
HttpResponse.json({
|
||||
success: true,
|
||||
data: { data: mockData, total: mockTotal, page: 1, page_size: 20, total_pages: Math.ceil(mockTotal / 20) },
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
it('渲染加载状态并显示数据', async () => {
|
||||
setupMock(config.mockItems);
|
||||
renderWithProviders(<Component />, { route });
|
||||
|
||||
await waitFor(() => {
|
||||
const table = document.querySelector('.ant-table');
|
||||
expect(table).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('表格包含正确的列名', async () => {
|
||||
setupMock(config.mockItems);
|
||||
renderWithProviders(<Component />, { route });
|
||||
|
||||
await waitFor(() => {
|
||||
const headers = document.querySelectorAll('th');
|
||||
const headerTexts = Array.from(headers).map((h) => h.textContent?.trim());
|
||||
for (const col of columns) {
|
||||
expect(headerTexts.some((t) => t?.includes(col))).toBe(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (hasPagination && totalItems > 20) {
|
||||
it('分页器显示正确的总数', async () => {
|
||||
setupMock(config.mockItems, totalItems);
|
||||
renderWithProviders(<Component />, { route });
|
||||
|
||||
await waitFor(() => {
|
||||
const pagination = document.querySelector('.ant-pagination');
|
||||
expect(pagination).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (hasCreateButton) {
|
||||
it('显示新建按钮', async () => {
|
||||
setupMock(config.mockItems);
|
||||
renderWithProviders(<Component />, { route });
|
||||
|
||||
await waitFor(() => {
|
||||
const btn = screen.getByRole('button', { name: new RegExp(createButtonText) });
|
||||
expect(btn).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (hasSearch) {
|
||||
it('搜索/筛选区域存在', async () => {
|
||||
setupMock(config.mockItems);
|
||||
renderWithProviders(<Component />, { route });
|
||||
|
||||
await waitFor(() => {
|
||||
const table = document.querySelector('.ant-table');
|
||||
expect(table).toBeInTheDocument();
|
||||
});
|
||||
const inputs = document.querySelectorAll('input, .ant-select, .ant-picker');
|
||||
expect(inputs.length).toBeGreaterThan(0);
|
||||
});
|
||||
}
|
||||
|
||||
if (extraTests) {
|
||||
extraTests();
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user