fix: connect API to tracker.db via SQLite repository
Deploy / Deploy Staging (push) Failing after 9s
Deploy / Deploy Production (push) Has been skipped
Tests / test (push) Failing after 14s
Tests / lint (push) Failing after 15s

This commit is contained in:
Xiaoxia AI
2026-06-17 13:21:38 +08:00
parent 3bf90f8614
commit 2cda8dec39
67 changed files with 5737 additions and 123 deletions
@@ -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();
});
});
+64
View File
@@ -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');
});
});
+14
View File
@@ -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();
});