import { test, expect } from '@playwright/test'; const mockTasks = { code: 200, data: { records: [ { id: 1, taskNum: 'T001', taskName: '学习 Vue3 组合式 API', taskDescription: '掌握 Composition API 的核心概念', taskPriority: 5, materialUrl: 'https://vuejs.org/guide', lastLearningStatus: '进行中', }, { id: 2, taskNum: 'T002', taskName: 'TypeScript 类型体操', taskDescription: '练习 TypeScript 高级类型', taskPriority: 3, materialUrl: '', lastLearningStatus: '未开始', }, ], }, }; const mockTasksEmpty = { code: 200, data: { records: [] } }; const mockFeed = { code: 200, data: [] }; const authAndNavigate = async (page: any) => { await page.goto('/login'); await page.evaluate(() => localStorage.setItem('isLoggedIn', 'true')); }; test.describe('Study page', () => { test.beforeEach(async ({ page }) => { await page.route('**/api/tasks**', (route) => { const url = route.request().url(); if (url.includes('/tasks') && !url.includes('/tasks/')) { return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(mockTasks), }); } return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ code: 200, data: {} }), }); }); await page.route('**/api/review/feed**', (route) => route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(mockFeed) }), ); await authAndNavigate(page); await page.goto('/study'); await page.waitForSelector('.study-page', { timeout: 10_000 }); }); test('displays task list with names and priorities', async ({ page }) => { const taskItems = page.locator('.task-list-item'); await expect(taskItems).toHaveCount(2); await expect(taskItems.first().locator('.task-name')).toContainText('学习 Vue3 组合式 API'); await expect(taskItems.nth(1).locator('.task-name')).toContainText('TypeScript 类型体操'); }); test('selecting a task shows its details', async ({ page }) => { const taskItems = page.locator('.task-list-item'); await taskItems.nth(1).click(); await expect(page.locator('.detail-head h3')).toContainText('TypeScript 类型体操'); }); test('clicking add navigates to add-task form', async ({ page }) => { await page.locator('.action-card').locator('button', { hasText: '添加任务' }).click(); await expect(page).toHaveURL(/\/add-task/); }); test('clicking update navigates to update-task form', async ({ page }) => { await page.locator('.action-card').locator('button', { hasText: '更新任务' }).click(); await expect(page).toHaveURL(/\/update-task/); }); test('delete task removes it from the list', async ({ page }) => { await page.route('**/api/tasks/1', (route) => route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ code: 200, message: '删除成功' }), }), ); await page.locator('.action-card').locator('button', { hasText: '删除任务' }).click(); await expect(page.locator('.task-list-item')).toHaveCount(1, { timeout: 5000 }); }); test('shows empty state when no tasks', async ({ page }) => { await page.route('**/api/tasks**', (route) => route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(mockTasksEmpty), }), ); await page.goto('/study'); await page.waitForSelector('.study-page', { timeout: 10_000 }); await expect(page.locator('.el-empty')).toBeVisible({ timeout: 5000 }); }); });