- 添加 matchMedia + ResizeObserver mock (Ant Design 依赖) - renderWithProviders 注入 auth state + localStorage token - 修复 fixture 批量生成自动分配唯一 id - PatientList 5 测试 / AlertList 3 测试 / DoctorList 4 测试
89 lines
2.6 KiB
TypeScript
89 lines
2.6 KiB
TypeScript
import { ReactElement } from 'react';
|
||
import { render, RenderOptions } from '@testing-library/react';
|
||
import { MemoryRouter } from 'react-router-dom';
|
||
import { ConfigProvider } from 'antd';
|
||
import zhCN from 'antd/locale/zh_CN';
|
||
import { useAuthStore } from '../../stores/auth';
|
||
import { clearApiCache } from '../../api/client';
|
||
|
||
interface CustomRenderOptions extends Omit<RenderOptions, 'wrapper'> {
|
||
route?: string;
|
||
/** 初始化 auth store 状态(默认已认证 + 全权限) */
|
||
authState?: Partial<{
|
||
user: { id: string; username: string; tenant_id: string };
|
||
isAuthenticated: boolean;
|
||
permissions: string[];
|
||
}>;
|
||
}
|
||
|
||
const ALL_HEALTH_PERMISSIONS = [
|
||
'health.patient.manage',
|
||
'health.patient.list',
|
||
'health.doctor.manage',
|
||
'health.doctor.list',
|
||
'health.appointment.manage',
|
||
'health.appointment.list',
|
||
'health.alerts.manage',
|
||
'health.alerts.list',
|
||
'health.follow-up.manage',
|
||
'health.follow-up.list',
|
||
'health.follow-up-templates.manage',
|
||
'health.follow-up-templates.list',
|
||
'health.consultation.manage',
|
||
'health.consultation.list',
|
||
'health.dialysis.manage',
|
||
'health.dialysis.list',
|
||
'health.articles.manage',
|
||
'health.articles.list',
|
||
'health.articles.review',
|
||
'health.points.manage',
|
||
'health.points.list',
|
||
'health.health-data.manage',
|
||
'health.health-data.list',
|
||
'ai.analysis.manage',
|
||
'ai.analysis.list',
|
||
'ai.prompt.manage',
|
||
'ai.prompt.list',
|
||
];
|
||
|
||
const DEFAULT_AUTH = {
|
||
user: { id: 'test-user-id', username: 'admin', tenant_id: 'test-tenant-id' },
|
||
isAuthenticated: true,
|
||
permissions: ALL_HEALTH_PERMISSIONS,
|
||
};
|
||
|
||
// 简单 JWT payload — 不会过期
|
||
const MOCK_TOKEN = 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0LXVzZXItaWQiLCJleHAiOjk5OTk5OTk5OTl9.mock';
|
||
|
||
export function renderWithProviders(ui: ReactElement, options: CustomRenderOptions = {}) {
|
||
const { route = '/', authState, ...renderOptions } = options;
|
||
|
||
// 初始化 localStorage token(API client 依赖)
|
||
localStorage.setItem('access_token', MOCK_TOKEN);
|
||
localStorage.setItem('refresh_token', MOCK_TOKEN);
|
||
|
||
// 初始化 Zustand auth store
|
||
const auth = { ...DEFAULT_AUTH, ...authState };
|
||
useAuthStore.setState({
|
||
user: auth.user ?? null,
|
||
isAuthenticated: auth.isAuthenticated ?? true,
|
||
permissions: auth.permissions ?? ['*'],
|
||
loading: false,
|
||
} as any);
|
||
|
||
// 清除 API 缓存
|
||
clearApiCache();
|
||
|
||
function Wrapper({ children }: { children: React.ReactNode }) {
|
||
return (
|
||
<MemoryRouter initialEntries={[route]}>
|
||
<ConfigProvider locale={zhCN}>{children}</ConfigProvider>
|
||
</MemoryRouter>
|
||
);
|
||
}
|
||
|
||
return render(ui, { wrapper: Wrapper, ...renderOptions });
|
||
}
|
||
|
||
export * from '@testing-library/react';
|