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