import { describe, it, expect, vi, beforeEach } from 'vitest'; // Mock @tarojs/taro vi.mock('@tarojs/taro', () => ({ default: { request: vi.fn(), getStorageSync: vi.fn(() => ''), setStorageSync: vi.fn(), showToast: vi.fn(), reLaunch: vi.fn(), getCurrentPages: vi.fn(() => []), }, })); // Mock secure-storage to use simple values vi.mock('@/utils/secure-storage', () => ({ secureGet: vi.fn((key: string) => { const store: Record = { access_token: 'test-token', tenant_id: 'test-tenant' }; return store[key] || ''; }), secureSet: vi.fn(), secureRemove: vi.fn(), })); import Taro from '@tarojs/taro'; import { api, clearRequestCache } from '@/services/request'; describe('request module', () => { beforeEach(() => { vi.clearAllMocks(); clearRequestCache(); }); describe('api.get', () => { it('should call Taro.request with correct method and url', async () => { const mockData = { success: true, data: { items: [] } }; vi.mocked(Taro.request).mockResolvedValue({ statusCode: 200, data: mockData } as any); const result = await api.get('/health/patients', { page: 1 }); expect(Taro.request).toHaveBeenCalledWith( expect.objectContaining({ url: expect.stringContaining('/health/patients?page=1'), method: 'GET', }), ); }); it('should build query string from params', async () => { vi.mocked(Taro.request).mockResolvedValue({ statusCode: 200, data: { success: true, data: null } } as any); await api.get('/test', { foo: 'bar', baz: 42 }); const call = vi.mocked(Taro.request).mock.calls[0][0]; expect(call.url).toContain('foo=bar'); expect(call.url).toContain('baz=42'); }); it('should skip undefined and empty params', async () => { vi.mocked(Taro.request).mockResolvedValue({ statusCode: 200, data: { success: true, data: null } } as any); await api.get('/test', { foo: 'bar', empty: '', missing: undefined }); const call = vi.mocked(Taro.request).mock.calls[0][0]; expect(call.url).toContain('foo=bar'); expect(call.url).not.toContain('empty'); expect(call.url).not.toContain('missing'); }); it('should cache GET responses', async () => { vi.mocked(Taro.request).mockResolvedValue({ statusCode: 200, data: { success: true, data: { id: '1' } } } as any); const r1 = await api.get('/cached'); const r2 = await api.get('/cached'); expect(Taro.request).toHaveBeenCalledTimes(1); expect(r1).toEqual(r2); }); }); describe('api.post', () => { it('should send POST with body', async () => { vi.mocked(Taro.request).mockResolvedValue({ statusCode: 200, data: { success: true, data: { id: 'new' } } } as any); await api.post('/health/patients', { name: 'Test' }); expect(Taro.request).toHaveBeenCalledWith( expect.objectContaining({ method: 'POST', data: { name: 'Test' }, }), ); }); }); describe('api.put', () => { it('should send PUT with body', async () => { vi.mocked(Taro.request).mockResolvedValue({ statusCode: 200, data: { success: true, data: {} } } as any); await api.put('/health/patients/p1', { name: 'Updated', version: 1 }); expect(Taro.request).toHaveBeenCalledWith( expect.objectContaining({ method: 'PUT', data: { name: 'Updated', version: 1 }, }), ); }); }); describe('api.delete', () => { it('should send DELETE request', async () => { vi.mocked(Taro.request).mockResolvedValue({ statusCode: 200, data: { success: true, data: null } } as any); await api.delete('/health/patients/p1'); expect(Taro.request).toHaveBeenCalledWith( expect.objectContaining({ method: 'DELETE' }), ); }); }); describe('error handling', () => { it('should throw on 403 with permission error', async () => { vi.mocked(Taro.request).mockResolvedValue({ statusCode: 403, data: {} } as any); await expect(api.get('/forbidden')).rejects.toThrow('权限不足'); }); it('should throw on 500 with server error', async () => { vi.mocked(Taro.request).mockResolvedValue({ statusCode: 500, data: {} } as any); await expect(api.get('/error')).rejects.toThrow('服务器错误'); }); it('should throw on network error', async () => { vi.mocked(Taro.request).mockRejectedValue({ errMsg: 'request:fail timeout' }); await expect(api.get('/timeout')).rejects.toThrow('网络超时'); }); it('should throw on API failure with message', async () => { vi.mocked(Taro.request).mockResolvedValue({ statusCode: 200, data: { success: false, message: '参数错误' }, } as any); await expect(api.get('/bad-params')).rejects.toThrow('参数错误'); }); }); });