| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- 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 react-query
- vi.mock('@tanstack/react-query', () => ({
- useQuery: vi.fn().mockReturnValue({
- isLoading: false,
- data: null,
- error: null,
- }),
- useQueryClient: () => ({
- clear: vi.fn(),
- }),
- }));
- // 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 (
- <div>
- <div data-testid="user">{auth.user ? 'authenticated' : 'unauthenticated'}</div>
- <div data-testid="isAuthenticated">{auth.isAuthenticated ? 'true' : 'false'}</div>
- <div data-testid="isLoading">{auth.isLoading ? 'true' : 'false'}</div>
- <button onClick={() => auth.login('test', 'password')}>Login</button>
- <button onClick={() => auth.logout()}>Logout</button>
- </div>
- );
- };
- describe('AuthProvider', () => {
- beforeEach(() => {
- vi.clearAllMocks();
- localStorageMock.getItem.mockReturnValue(null);
- });
- afterEach(() => {
- vi.restoreAllMocks();
- });
- it('应该提供认证上下文', () => {
- renderWithProviders(
- <AuthProvider>
- <TestComponent />
- </AuthProvider>
- );
- expect(screen.getByTestId('user')).toHaveTextContent('unauthenticated');
- expect(screen.getByTestId('isAuthenticated')).toHaveTextContent('false');
- });
- it('应该在没有AuthProvider时抛出错误', () => {
- // 抑制控制台错误输出
- const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {});
- expect(() => {
- renderWithProviders(<TestComponent />);
- }).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(
- <AuthProvider>
- <TestComponent />
- </AuthProvider>
- );
- 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(
- <AuthProvider>
- <TestComponent />
- </AuthProvider>
- );
- 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(
- <AuthProvider>
- <TestComponent />
- </AuthProvider>
- );
- const logoutButton = screen.getByText('Logout');
- await act(async () => {
- fireEvent.click(logoutButton);
- });
- expect(authClient.logout.$post).toHaveBeenCalled();
- expect(localStorageMock.removeItem).toHaveBeenCalledWith('token');
- });
- });
- // Helper function to fire events
- function fireEvent(element: HTMLElement, event: string) {
- element.dispatchEvent(new Event(event, { bubbles: true }));
- }
|