fix: connect API to tracker.db via SQLite repository
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Login 组件单元测试
|
||||
*/
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import Login from '@/pages/auth/Login';
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: { retry: false },
|
||||
mutations: { retry: false },
|
||||
},
|
||||
});
|
||||
|
||||
const renderLogin = () => {
|
||||
return render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<BrowserRouter>
|
||||
<Login />
|
||||
</BrowserRouter>
|
||||
</QueryClientProvider>
|
||||
);
|
||||
};
|
||||
|
||||
describe('Login Component', () => {
|
||||
it('should render login form', () => {
|
||||
renderLogin();
|
||||
|
||||
expect(screen.getByPlaceholderText('邮箱')).toBeInTheDocument();
|
||||
expect(screen.getByPlaceholderText('密码')).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '登录' })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should show validation errors for empty fields', async () => {
|
||||
renderLogin();
|
||||
|
||||
const submitButton = screen.getByRole('button', { name: '登录' });
|
||||
fireEvent.click(submitButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('请输入邮箱')).toBeInTheDocument();
|
||||
expect(screen.getByText('请输入密码')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should navigate to register page', () => {
|
||||
renderLogin();
|
||||
|
||||
const registerLink = screen.getByText('立即注册');
|
||||
expect(registerLink).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* WorkspaceList 组件单元测试
|
||||
*/
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import WorkspaceList from '@/pages/workspace/WorkspaceList';
|
||||
import * as workspaceApi from '@/api/workspace';
|
||||
|
||||
vi.mock('@/api/workspace');
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: { retry: false },
|
||||
},
|
||||
});
|
||||
|
||||
const renderWorkspaceList = () => {
|
||||
return render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<BrowserRouter>
|
||||
<WorkspaceList />
|
||||
</BrowserRouter>
|
||||
</QueryClientProvider>
|
||||
);
|
||||
};
|
||||
|
||||
describe('WorkspaceList', () => {
|
||||
it('should render workspace list', async () => {
|
||||
const mockWorkspaces = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'Test Workspace',
|
||||
subscription_plan: 'free',
|
||||
subscription_status: 'active',
|
||||
created_at: '2024-01-01',
|
||||
},
|
||||
];
|
||||
|
||||
vi.mocked(workspaceApi.getWorkspaces).mockResolvedValue({
|
||||
items: mockWorkspaces,
|
||||
total: 1,
|
||||
page: 1,
|
||||
page_size: 10,
|
||||
});
|
||||
|
||||
renderWorkspaceList();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Test Workspace')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should show create workspace button', () => {
|
||||
renderWorkspaceList();
|
||||
|
||||
expect(screen.getByText('创建工作空间')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* useAuth Hook 单元测试
|
||||
*/
|
||||
import { renderHook, act } from '@testing-library/react';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { useAuth } from '@/hooks/useAuth';
|
||||
import * as authApi from '@/api/auth';
|
||||
|
||||
// Mock API
|
||||
vi.mock('@/api/auth');
|
||||
|
||||
describe('useAuth', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
localStorage.clear();
|
||||
});
|
||||
|
||||
it('should login successfully', async () => {
|
||||
const mockUser = {
|
||||
id: '1',
|
||||
username: 'testuser',
|
||||
email: 'test@example.com',
|
||||
};
|
||||
|
||||
const mockToken = 'mock-token';
|
||||
|
||||
vi.mocked(authApi.login).mockResolvedValue({
|
||||
user: mockUser,
|
||||
access_token: mockToken,
|
||||
refresh_token: 'refresh-token',
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useAuth());
|
||||
|
||||
await act(async () => {
|
||||
await result.current.login('test@example.com', 'password123');
|
||||
});
|
||||
|
||||
expect(authApi.login).toHaveBeenCalledWith('test@example.com', 'password123');
|
||||
expect(localStorage.getItem('token')).toBe(mockToken);
|
||||
});
|
||||
|
||||
it('should logout successfully', async () => {
|
||||
localStorage.setItem('token', 'mock-token');
|
||||
|
||||
const { result } = renderHook(() => useAuth());
|
||||
|
||||
act(() => {
|
||||
result.current.logout();
|
||||
});
|
||||
|
||||
expect(localStorage.getItem('token')).toBeNull();
|
||||
});
|
||||
|
||||
it('should handle login error', async () => {
|
||||
vi.mocked(authApi.login).mockRejectedValue(new Error('Invalid credentials'));
|
||||
|
||||
const { result } = renderHook(() => useAuth());
|
||||
|
||||
await expect(
|
||||
result.current.login('test@example.com', 'wrong-password')
|
||||
).rejects.toThrow('Invalid credentials');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* 测试环境设置
|
||||
*/
|
||||
import { expect, afterEach } from 'vitest';
|
||||
import { cleanup } from '@testing-library/react';
|
||||
import matchers from '@testing-library/jest-dom/matchers';
|
||||
|
||||
// 扩展 Vitest 的 expect
|
||||
expect.extend(matchers);
|
||||
|
||||
// 每次测试后清理
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
Reference in New Issue
Block a user