From 31962dd8cd5ebd0fe31103c254ef9452fb3ec7f6 Mon Sep 17 00:00:00 2001 From: zhangxiang Date: Sun, 12 Apr 2026 08:55:10 +0800 Subject: [PATCH] =?UTF-8?q?fix(content-crud):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=86=85=E5=AE=B9=E5=88=97=E8=A1=A8=E6=9F=A5=E6=89=BE=E9=80=BB?= =?UTF-8?q?=E8=BE=91=20-=20=E5=A2=9E=E5=8A=A0=E6=90=9C=E7=B4=A2=E5=92=8C?= =?UTF-8?q?=E5=88=B7=E6=96=B0=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题: - 内容创建后在列表中找不到 - 可能存在分页或缓存延迟 修复: 1. 增加搜索功能:如果第一页找不到,使用搜索框查找 2. 增加刷新机制:搜索后仍未找到则刷新页面 3. 增强日志:显示更多列表内容用于调试 测试结果: - Chromium: ✓ 创建新闻内容通过 - Chromium: ✓ 创建产品内容通过 - Firefox: ✓ 创建新闻内容通过 - Firefox: ✓ 创建产品内容通过 --- e2e/pages/AdminContentPage.ts | 171 ++++++++++++++++++++++++++++------ 1 file changed, 145 insertions(+), 26 deletions(-) diff --git a/e2e/pages/AdminContentPage.ts b/e2e/pages/AdminContentPage.ts index dabb64f..8dfccc7 100644 --- a/e2e/pages/AdminContentPage.ts +++ b/e2e/pages/AdminContentPage.ts @@ -12,69 +12,188 @@ export interface ContentData { } export class AdminContentPage { - constructor(private page: Page) {} + constructor(private page: Page) { } async goto() { - await this.page.goto('/admin/content'); - await this.page.waitForLoadState('networkidle'); + try { + await this.page.goto('/admin/content', { waitUntil: 'domcontentloaded', timeout: 30000 }); + } catch (error) { + console.log('导航失败,尝试重新加载:', error); + try { + await this.page.reload({ waitUntil: 'domcontentloaded', timeout: 30000 }); + } catch (reloadError) { + console.log('重新加载失败:', reloadError); + } + } + await this.page.waitForLoadState('domcontentloaded'); + await this.page.waitForSelector('table', { timeout: 10000, state: 'visible' }); + await this.page.waitForTimeout(1000); } async gotoCreate() { - await this.page.goto('/admin/content/new'); + try { + await this.page.goto('/admin/content/new', { waitUntil: 'domcontentloaded', timeout: 30000 }); + } catch (error) { + console.log('导航到创建页面失败,尝试重新加载:', error); + await this.page.reload({ waitUntil: 'domcontentloaded', timeout: 30000 }); + } await this.page.waitForLoadState('domcontentloaded'); - await this.page.waitForSelector('input[placeholder="请输入标题"]', { timeout: 60000 }); + await this.page.waitForSelector('input[placeholder="请输入标题"]', { timeout: 10000, state: 'visible' }); } async createContent(data: ContentData): Promise { await this.gotoCreate(); - + await this.page.fill('input[placeholder="请输入标题"]', data.title); await this.page.fill('input[placeholder="url-slug"]', data.slug); - + if (data.excerpt) { await this.page.fill('textarea', data.excerpt); } - + if (data.type) { await this.page.locator('select').first().selectOption(data.type); } - + if (data.status) { await this.page.locator('select').nth(1).selectOption(data.status); } - + if (data.category) { await this.page.fill('input[placeholder="分类名称"]', data.category); } - + await this.page.click('button:has-text("发布")'); - - await this.page.waitForURL(/\/admin\/content\/[a-zA-Z0-9]+/, { timeout: 15000 }); - + + try { + await this.page.waitForURL(/\/admin\/content\/[a-zA-Z0-9]+/, { timeout: 15000 }); + } catch { + console.log('等待URL跳转失败,当前URL:', this.page.url()); + + await this.page.waitForTimeout(2000); + + const currentUrl = this.page.url(); + if (currentUrl.includes('/admin/content/')) { + console.log('URL已跳转到内容详情页:', currentUrl); + } else { + console.log('URL未跳转,可能创建失败'); + } + } + + await this.page.waitForLoadState('domcontentloaded'); + await this.page.waitForTimeout(1000); + const url = this.page.url(); + console.log('最终URL:', url); + const match = url.match(/\/admin\/content\/([a-zA-Z0-9]+)/); - return match ? match[1] : null; + const contentId = match ? match[1] : null; + + if (!contentId) { + console.log('无法从URL提取contentId:', url); + } + + return contentId; } async deleteContent(contentId: string) { await this.goto(); + const row = this.page.locator(`tr:has-text("${contentId}")`); - - if (await row.count() > 0) { - await row.locator('button:has-text("删除")').click(); - await this.page.locator('button:has-text("确认"), button:has-text("确定")').click(); - await this.page.waitForResponse(resp => - resp.url().includes('/api/admin/content') && - resp.request().method() === 'DELETE', - { timeout: 10000 } - ); + + try { + if (await row.count() > 0) { + await row.first().locator('button:has-text("删除")').click({ timeout: 5000 }); + await this.page.waitForTimeout(500); + const confirmButton = this.page.locator('button:has-text("确认"), button:has-text("确定"), button:has-text("删除")').first(); + await confirmButton.click({ timeout: 5000 }); + await this.page.waitForResponse(resp => + resp.url().includes('/api/admin/content') && + resp.request().method() === 'DELETE', + { timeout: 10000 } + ).catch(() => { + console.log('删除请求可能已完成'); + }); + } + } catch (error) { + console.error(`删除内容失败 (ID: ${contentId}):`, error); + } + } + + async deleteContentByTitle(title: string) { + try { + await this.goto(); + + const row = this.page.locator(`tr:has-text("${title}")`); + + if (await row.count() > 0) { + await row.first().locator('button[title="删除"]').click({ timeout: 5000 }); + await this.page.waitForTimeout(300); + + await this.page.click('button:has-text("确认删除")', { timeout: 5000 }); + + await this.page.waitForResponse(resp => + resp.url().includes('/api/admin/content') && + resp.request().method() === 'DELETE', + { timeout: 8000 } + ).catch(() => { + console.log('删除请求可能已完成'); + }); + + await this.page.waitForTimeout(500); + } + } catch (error) { + console.error(`删除内容失败 (标题: ${title}):`, error); } } async expectContentInList(title: string) { + console.log(`检查内容是否在列表中: ${title}`); + await this.goto(); - const row = this.page.locator(`tr:has-text("${title}")`); - await expect(row).toBeVisible(); + await this.page.waitForLoadState('domcontentloaded'); + await this.page.waitForTimeout(2000); + + let row = this.page.locator(`tr:has-text("${title}")`); + let isVisible = await row.count() > 0; + + if (!isVisible) { + console.log('内容不在第一页,尝试搜索'); + + const searchInput = this.page.locator('input[placeholder*="搜索"]'); + if (await searchInput.count() > 0) { + await searchInput.fill(title); + await this.page.keyboard.press('Enter'); + await this.page.waitForTimeout(2000); + + row = this.page.locator(`tr:has-text("${title}")`); + isVisible = await row.count() > 0; + } + } + + if (!isVisible) { + console.log('搜索后仍未找到,尝试刷新页面'); + await this.page.reload({ waitUntil: 'domcontentloaded' }); + await this.page.waitForSelector('table', { timeout: 10000, state: 'visible' }); + await this.page.waitForTimeout(2000); + + row = this.page.locator(`tr:has-text("${title}")`); + isVisible = await row.count() > 0; + } + + if (!isVisible) { + const allRows = this.page.locator('table tbody tr'); + const rowCount = await allRows.count(); + console.log(`列表中共有 ${rowCount} 行内容`); + + for (let i = 0; i < Math.min(rowCount, 10); i++) { + const rowText = await allRows.nth(i).textContent(); + console.log(`行 ${i + 1}: ${rowText?.trim().substring(0, 150)}`); + } + } + + await expect(row.first()).toBeVisible({ timeout: 15000 }); + console.log(`✅ 找到内容: ${title}`); } async expectContentNotInList(title: string) {