/** * ================================================================ * 场景:文章管理全流程 E2E 测试 * ================================================================ * 用户故事: * - 管理员:创建/发布/编辑/删除/精选文章 * - 用户:浏览文章列表,查看文章详情,获取每日贴士 * * 流程步骤: * 1. 管理员创建文章并发布 * 2. 管理员管理文章分类 * 3. 管理员设置精选文章 * 4. 用户浏览文章列表 * 5. 用户查看文章详情 * * 关键里程碑: * - [Milestone-1] 文章发布成功 * - [Milestone-2] 文章精选设置成功 * - [Milestone-3] 用户成功浏览文章 * ================================================================ * * 运行:npx playwright test tests/e2e/article-management.spec.js */ const { test, expect } = require('@playwright/test'); test.describe('【场景流程】文章管理全流程', () => { // ===== 场景1:管理员创建并发布文章 ===== test('[场景1] 管理员创建并发布文章 - 期望发布成功', async ({ page }) => { // ========== Given:管理员进入文章管理页面 ========== await page.goto('/#/pages/admin/article-list'); await page.waitForLoadState('networkidle'); // ========== When:创建并发布文章 ========== const createBtn = page.locator('.create-btn, .add-article-btn'); if (await createBtn.isVisible()) { await createBtn.click(); } else { await page.goto('/#/pages/admin/article-create'); await page.waitForLoadState('networkidle'); } await page.waitForSelector('.article-form, .create-form', { timeout: 5000 }); // 填写标题 const titleInput = page.locator('input[name="title"], .title-input'); if (await titleInput.isVisible()) { await titleInput.fill('测试文章_' + Date.now()); } // 填写摘要 const summaryInput = page.locator('textarea[name="summary"], .summary-input'); if (await summaryInput.isVisible()) { await summaryInput.fill('这是文章摘要内容,描述文章的核心要点。'); } // 填写内容 const contentInput = page.locator('textarea[name="content"], .content-input'); if (await contentInput.isVisible()) { await contentInput.fill('这是文章的正文内容,包含详细的信息和说明。'); } // 选择分类 const categorySelect = page.locator('.category-picker, select[name="category"]'); if (await categorySelect.isVisible()) { await categorySelect.click(); await page.waitForSelector('.option-item', { timeout: 3000 }); await page.locator('.option-item').first().click(); } // 发布文章 await page.click('.publish-btn, .submit-btn'); // ========== Then:Milestone-1 - 发布成功 ======== await page.waitForSelector('.success-tip, .publish-success, .toast-success', { timeout: 10000 }); const successTip = page.locator('.success-tip, .publish-success'); expect(await successTip.isVisible()).toBeTruthy(); }); // ===== 场景2:管理员管理文章分类 ===== test('[场景2] 管理员管理文章分类 - 期望分类创建成功', async ({ page }) => { // ========== Given:管理员进入分类管理页面 ========== await page.goto('/#/pages/admin/category-list'); await page.waitForLoadState('networkidle'); // ========== When:创建新分类 ========== const addBtn = page.locator('.add-btn, .create-category-btn'); if (await addBtn.isVisible()) { await addBtn.click(); } await page.waitForSelector('.category-form, .create-form', { timeout: 5000 }); const nameInput = page.locator('input[name="name"], .category-name-input'); if (await nameInput.isVisible()) { await nameInput.fill('测试分类_' + Date.now()); } await page.click('.submit-btn, .save-btn'); // ========== Then:分类创建成功 ======== await page.waitForSelector('.success-tip, .create-success', { timeout: 10000 }); const successTip = page.locator('.success-tip, .create-success'); expect(await successTip.isVisible()).toBeTruthy(); }); // ===== 场景3:管理员设置精选文章 ===== test('[场景3] 管理员设置精选文章 - 期望精选状态切换成功', async ({ page }) => { // ========== Given:管理员进入文章列表 ========== await page.goto('/#/pages/admin/article-list'); await page.waitForLoadState('networkidle'); // ========== When:设置精选 ========== await page.waitForSelector('.article-item', { timeout: 10000 }); const firstArticle = page.locator('.article-item').first(); const featuredBtn = firstArticle.locator('.featured-btn, .toggle-featured'); if (await featuredBtn.isVisible()) { await featuredBtn.click(); } // ========== Then:Milestone-2 - 精选设置成功 ======== await page.waitForTimeout(500); // 验证精选标识变化 const featuredTag = firstArticle.locator('.featured-tag, .is-featured'); const isFeatured = await featuredTag.isVisible(); expect(isFeatured).toBeTruthy(); }); // ===== 场景4:用户浏览文章列表 ===== test('[场景4] 用户浏览文章列表 - 期望返回已发布文章', async ({ page }) => { // ========== Given:用户进入文章列表页 ========== await page.goto('/#/pages/mind/articles'); await page.waitForLoadState('networkidle'); // ========== When:浏览文章列表 ========== await page.waitForSelector('.article-list, .article-item', { timeout: 10000 }); // ========== Then:Milestone-3 - 返回文章列表 ======== const articleItems = page.locator('.article-item, .article-card'); const count = await articleItems.count(); expect(count).toBeGreaterThan(0); // 验证文章包含标题 const firstArticle = articleItems.first(); const title = firstArticle.locator('.article-title, .title'); if (await title.isVisible()) { const titleText = await title.textContent(); expect(titleText.length).toBeGreaterThan(0); } }); // ===== 场景5:用户查看文章详情 ===== test('[场景5] 用户查看文章详情 - 期望返回完整文章内容', async ({ page }) => { // ========== Given:用户进入文章详情页 ========== await page.goto('/#/pages/mind/articles'); await page.waitForLoadState('networkidle'); // ========== When:点击文章查看详情 ========== await page.waitForSelector('.article-item', { timeout: 10000 }); await page.locator('.article-item').first().click(); // ========== Then:返回完整文章详情 ======== await page.waitForSelector('.article-detail, .detail-content, .article-content', { timeout: 10000 }); const detailContent = page.locator('.article-detail, .detail-content'); expect(await detailContent.isVisible()).toBeTruthy(); // 验证包含正文内容 const articleBody = page.locator('.article-body, .content'); if (await articleBody.isVisible()) { const bodyText = await articleBody.textContent(); expect(bodyText.length).toBeGreaterThan(0); } }); });