Files
lpt-fe/e2e/study.spec.ts
T

112 lines
3.7 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();
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 });
});
});