feat(mp): Phase 1 测试覆盖 + UX 无障碍 — 106 tests PASS + ARIA + focus ring
测试: - secure-storage: 26 tests (AES 加解密/明文 fallback/迁移/Base64 边界) - request.ts: 16 tests (扩展 ResponseCache/patientId 隔离/requestUnlimited) - mock-api: 修复 getCachedPatientId 缺失导致 health 测试失败 UX 无障碍 (10 组件): - SegmentTabs/DoctorTabBar: role=tablist/tab + aria-selected - PrimaryButton/SecondaryButton: role=button + aria-disabled/aria-busy - Loading/LoadingCard: role=status + aria-live=polite - EmptyState: role=status + aria-live=polite - ErrorState: role=alert + aria-live=assertive - TrendChart tooltip: role=tooltip + aria-live=polite - FormInput: aria-invalid + aria-label 焦点管理: - 新增 _focus-ring.scss mixin (focus + focus-visible) - 5 组件 SCSS 应用 focus-ring
This commit is contained in:
@@ -23,7 +23,7 @@ vi.mock('@/utils/secure-storage', () => ({
|
||||
}));
|
||||
|
||||
import Taro from '@tarojs/taro';
|
||||
import { api, clearRequestCache, resetForTesting } from '@/services/request';
|
||||
import { api, clearRequestCache, resetForTesting, setCachedPatientId } from '@/services/request';
|
||||
|
||||
describe('request module', () => {
|
||||
beforeEach(() => {
|
||||
@@ -148,4 +148,61 @@ describe('request module', () => {
|
||||
await expect(api.get('/bad-params')).rejects.toThrow('参数错误');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ResponseCache', () => {
|
||||
it('should cache GET responses and return cached on second call', async () => {
|
||||
vi.mocked(Taro.request).mockResolvedValue({ statusCode: 200, data: { success: true, data: { id: '1' } } } as any);
|
||||
|
||||
await api.get('/cached-test');
|
||||
await api.get('/cached-test');
|
||||
|
||||
expect(Taro.request).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should not cache POST requests', async () => {
|
||||
vi.mocked(Taro.request).mockResolvedValue({ statusCode: 200, data: { success: true, data: {} } } as any);
|
||||
|
||||
await api.post('/no-cache', { a: 1 });
|
||||
await api.post('/no-cache', { a: 1 });
|
||||
|
||||
expect(Taro.request).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('clearRequestCache should clear cached entries', async () => {
|
||||
vi.mocked(Taro.request).mockResolvedValue({ statusCode: 200, data: { success: true, data: { v: 1 } } } as any);
|
||||
|
||||
await api.get('/clear-test');
|
||||
clearRequestCache();
|
||||
await api.get('/clear-test');
|
||||
|
||||
expect(Taro.request).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setCachedPatientId', () => {
|
||||
it('should isolate cache entries by patient ID', async () => {
|
||||
vi.mocked(Taro.request).mockResolvedValue({ statusCode: 200, data: { success: true, data: { v: 1 } } } as any);
|
||||
setCachedPatientId('patient-A');
|
||||
await api.get('/health/data');
|
||||
|
||||
setCachedPatientId('patient-B');
|
||||
await api.get('/health/data');
|
||||
|
||||
// 不同 patient ID 应各自发请求(缓存隔离)
|
||||
expect(Taro.request).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('requestUnlimited', () => {
|
||||
it('should bypass concurrency limiter', async () => {
|
||||
vi.mocked(Taro.request).mockResolvedValue({ statusCode: 200, data: { success: true, data: 'ok' } } as any);
|
||||
|
||||
const { requestUnlimited } = await import('@/services/request');
|
||||
await requestUnlimited('GET', '/health/test');
|
||||
|
||||
expect(Taro.request).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ method: 'GET' }),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user