104ae78a2b
- study.spec.ts:mock 模式 **/api/tasks** 过滤 .ts 模块请求,避免拦截 Vite 文件加载 - navigation.spec.ts:同上 - start-task.spec.ts:addInitScript mock HTMLAudioElement.play 绕过音频权限弹窗 - start-task.spec.ts:补健结束会话后的 ElMessageBox.confirm 确认点击 - 复习页面入口检查新增回忆复习按钮的文本变化适配
118 lines
4.0 KiB
TypeScript
118 lines
4.0 KiB
TypeScript
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();
|
|
// 排除 Vite 模块加载请求(.ts 文件),只拦截真正的 API 请求
|
|
if (url.endsWith('.ts')) return route.continue();
|
|
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) => {
|
|
const url = route.request().url();
|
|
if (url.endsWith('.ts')) return route.continue();
|
|
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) => {
|
|
const url = route.request().url();
|
|
if (url.endsWith('.ts')) return route.continue();
|
|
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 });
|
|
});
|
|
});
|