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');
});
});