import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { screen, act, fireEvent } from '@testing-library/react'; import { AuthProvider, useAuth } from '../../src/hooks/AuthProvider'; import React from 'react'; import { renderWithProviders } from '../test-utils'; // Mock axios vi.mock('axios', () => ({ default: { defaults: { headers: { common: {}, }, }, }, })); // Mock auth client vi.mock('../../src/api/authClient', () => ({ authClient: { login: { $post: vi.fn(), }, logout: { $post: vi.fn(), }, me: { $get: vi.fn(), }, }, })); // Mock localStorage const localStorageMock = { getItem: vi.fn(), setItem: vi.fn(), removeItem: vi.fn(), clear: vi.fn(), }; Object.defineProperty(window, 'localStorage', { value: localStorageMock, }); // Test component that uses useAuth const TestComponent = () => { const auth = useAuth(); return (
{auth.user ? 'authenticated' : 'unauthenticated'}
{auth.isAuthenticated ? 'true' : 'false'}
{auth.isLoading ? 'true' : 'false'}
); }; describe('AuthProvider', () => { beforeEach(() => { vi.clearAllMocks(); localStorageMock.getItem.mockReturnValue(null); }); afterEach(() => { vi.restoreAllMocks(); }); it('应该提供认证上下文', () => { renderWithProviders( ); expect(screen.getByTestId('user')).toHaveTextContent('unauthenticated'); expect(screen.getByTestId('isAuthenticated')).toHaveTextContent('false'); }); it('应该在没有AuthProvider时抛出错误', () => { // 抑制控制台错误输出 const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {}); expect(() => { renderWithProviders(); }).toThrow('useAuth必须在AuthProvider内部使用'); consoleError.mockRestore(); }); it('应该处理登录成功', async () => { const mockLoginResponse = { status: 200, json: vi.fn().mockResolvedValue({ token: 'test-token', user: { id: 1, username: 'test', email: 'test@example.com' }, }), }; const { authClient } = await import('../../src/api/authClient'); (authClient.login.$post as any).mockResolvedValue(mockLoginResponse); renderWithProviders( ); const loginButton = screen.getByText('Login'); await act(async () => { fireEvent.click(loginButton); }); expect(authClient.login.$post).toHaveBeenCalledWith({ json: { username: 'test', password: 'password', }, }); }); it('应该处理登录失败', async () => { const mockLoginResponse = { status: 401, json: vi.fn().mockResolvedValue({ message: 'Invalid credentials', }), }; const { authClient } = await import('../../src/api/authClient'); (authClient.login.$post as any).mockResolvedValue(mockLoginResponse); renderWithProviders( ); const loginButton = screen.getByText('Login'); await act(async () => { fireEvent.click(loginButton); }); expect(authClient.login.$post).toHaveBeenCalledWith({ json: { username: 'test', password: 'password', }, }); }); it('应该处理登出', async () => { const { authClient } = await import('../../src/api/authClient'); (authClient.logout.$post as any).mockResolvedValue({}); localStorageMock.getItem.mockReturnValue('test-token'); renderWithProviders( ); const logoutButton = screen.getByText('Logout'); await act(async () => { fireEvent.click(logoutButton); }); expect(authClient.logout.$post).toHaveBeenCalled(); expect(localStorageMock.removeItem).toHaveBeenCalledWith('token'); }); });