error-context.md 10 KB

Instructions

  • Following Playwright test failed.
  • Explain why, be concise, respect Playwright best practices.
  • Provide a snippet of code with the fix, if possible.

Test info

  • Name: regression\23-frontend-e2e.spec.ts >> 前端 UI 完整验收 >> E12: 历史记录页 - 时间标签栏/视图切换/列表项点击
  • Location: regression\23-frontend-e2e.spec.ts:441:7

Error details

Error: expect(locator).toBeVisible() failed

Locator: locator('text=全部').first()
Expected: visible
Timeout: 15000ms
Error: element(s) not found

Call log:
  - Expect "toBeVisible" with timeout 15000ms
  - waiting for locator('text=全部').first()

Test source

  346 |       (await page.locator('.chapter-content').count()) > 0;
  347 |     expect(hasChapterUI || true).toBeTruthy();
  348 | 
  349 |     // 返回按钮
  350 |     const backBtn = page.locator('.back-icon').first();
  351 |     if (await backBtn.count() > 0) await expect(backBtn).toBeVisible();
  352 | 
  353 |     await page.screenshot({ path: `${SCREENSHOT_DIR}/e2e-E08-chapter-detail.png`, fullPage: true }).catch(() => {});
  354 |   });
  355 | 
  356 |   test('E09: 会员订阅页 - 套餐卡片/支付方式/订阅按钮/点击套餐', async ({ page }) => {
  357 |     await page.goto(`${FRONTEND_URL}/#/pages/member/index`, { waitUntil: 'networkidle', timeout: 30000 });
  358 |     await page.waitForTimeout(3000);
  359 | 
  360 |     // Token 余额
  361 |     const tokenEl = page.locator('text=Token').first();
  362 |     if (await tokenEl.count() > 0) await expect(tokenEl).toBeVisible();
  363 | 
  364 |     // 点击选择此套餐按钮
  365 |     const planBtns = page.locator('text=选择此套餐');
  366 |     if (await planBtns.count() > 0) {
  367 |       await planBtns.first().click();
  368 |       await page.waitForTimeout(1000);
  369 |       console.log('点击选择此套餐按钮成功');
  370 |     }
  371 | 
  372 |     // 点击立即订阅按钮
  373 |     const subscribeBtn = page.locator('text=立即订阅').first();
  374 |     if (await subscribeBtn.count() > 0) {
  375 |       await subscribeBtn.click();
  376 |       await page.waitForTimeout(1000);
  377 |       console.log('点击立即订阅按钮成功,URL:', page.url());
  378 |     }
  379 | 
  380 |     await page.screenshot({ path: `${SCREENSHOT_DIR}/e2e-E09-member.png`, fullPage: true }).catch(() => {});
  381 |   });
  382 | 
  383 |   test('E10: 专辑列表页 - 列表展示/空状态/创建入口', async ({ page }) => {
  384 |     await page.goto(`${FRONTEND_URL}/#/pages/albums/index`, { waitUntil: 'networkidle', timeout: 30000 });
  385 |     await page.waitForTimeout(3000);
  386 | 
  387 |     await expect(page.locator('text=专辑').first()).toBeVisible();
  388 | 
  389 |     // 空状态或内容(更宽松检查)
  390 |     const hasContent =
  391 |       (await page.locator('text=暂无专辑').count()) > 0 ||
  392 |       (await page.locator('text=创建你的第一个专辑').count()) > 0 ||
  393 |       (await page.locator('.item').count()) > 0 ||
  394 |       (await page.locator('.album-card').count()) > 0;
  395 |     expect(hasContent).toBeTruthy();
  396 | 
  397 |     // 点击创建专辑按钮
  398 |     const createBtn = page.locator('text=创建专辑').first();
  399 |     if (await createBtn.count() > 0) {
  400 |       await createBtn.click();
  401 |       await page.waitForTimeout(1000);
  402 |       console.log('点击创建专辑按钮成功,URL:', page.url());
  403 |     }
  404 | 
  405 |     await page.screenshot({ path: `${SCREENSHOT_DIR}/e2e-E10-albums.png`, fullPage: true }).catch(() => {});
  406 |   });
  407 | 
  408 |   // =============================================
  409 |   // E11-E15: 功能页面(搜索/历史/视频/收藏/设置)
  410 |   // =============================================
  411 | 
  412 |   test('E11: 搜索页 - 搜索框输入/历史记录/热门推荐/点击搜索', async ({ page }) => {
  413 |     await page.goto(`${FRONTEND_URL}/#/pages/search/index`, { waitUntil: 'networkidle', timeout: 30000 });
  414 |     await page.waitForTimeout(4000);
  415 | 
  416 |     // 搜索输入框(uniapp可能用input或view模拟)
  417 |     const searchInput = page.locator('input').first();
  418 |     if (await searchInput.count() > 0) {
  419 |       await expect(searchInput).toBeVisible();
  420 |       await searchInput.click();
  421 |       await searchInput.fill('测试搜索');
  422 |       await page.waitForTimeout(500);
  423 |     }
  424 | 
  425 |     // 搜索按钮(使用CSS类选择器避免匹配placeholder)
  426 |     const searchBtn = page.locator('.search-btn').first();
  427 |     if (await searchBtn.count() > 0) {
  428 |       await expect(searchBtn).toBeVisible();
  429 |     }
  430 | 
  431 |     // 历史记录或热门推荐或输入提示(至少有一个区域存在)
  432 |     const hasSection =
  433 |       (await page.locator('text=搜索历史').count()) > 0 ||
  434 |       (await page.locator('text=热门推荐').count()) > 0 ||
  435 |       (await page.locator('text=输入关键词').count()) > 0;
  436 |     expect(hasSection || true).toBeTruthy();
  437 | 
  438 |     await page.screenshot({ path: `${SCREENSHOT_DIR}/e2e-E11-search.png`, fullPage: true }).catch(() => {});
  439 |   });
  440 | 
  441 |   test('E12: 历史记录页 - 时间标签栏/视图切换/列表项点击', async ({ page }) => {
  442 |     await page.goto(`${FRONTEND_URL}/#/pages/history/index`, { waitUntil: 'networkidle', timeout: 30000 });
  443 |     await page.waitForTimeout(3000);
  444 | 
  445 |     // 全部标签
> 446 |     await expect(page.locator('text=全部').first()).toBeVisible();
      |                                                   ^ Error: expect(locator).toBeVisible() failed
  447 | 
  448 |     // 点击今天标签
  449 |     const todayTab = page.locator('text=今天').first();
  450 |     if (await todayTab.count() > 0) {
  451 |       await todayTab.click();
  452 |       await page.waitForTimeout(500);
  453 |       console.log('点击今天标签成功');
  454 |     }
  455 | 
  456 |     // 点击本周标签
  457 |     const weekTab = page.locator('text=本周').first();
  458 |     if (await weekTab.count() > 0) {
  459 |       await weekTab.click();
  460 |       await page.waitForTimeout(500);
  461 |       console.log('点击本周标签成功');
  462 |     }
  463 | 
  464 |     // 点击聚合视图切换
  465 |     const aggregateBtn = page.locator('text=聚合').first();
  466 |     if (await aggregateBtn.count() > 0) {
  467 |       await aggregateBtn.click();
  468 |       await page.waitForTimeout(500);
  469 |       console.log('点击聚合视图成功');
  470 |     }
  471 | 
  472 |     // 点击列表视图切换
  473 |     const listBtn = page.locator('text=列表').first();
  474 |     if (await listBtn.count() > 0) {
  475 |       await listBtn.click();
  476 |       await page.waitForTimeout(500);
  477 |       console.log('点击列表视图成功');
  478 |     }
  479 | 
  480 |     await page.screenshot({ path: `${SCREENSHOT_DIR}/e2e-E12-history.png`, fullPage: true }).catch(() => {});
  481 |   });
  482 | 
  483 |   test('E13: 视频生成列表页 - 创建入口/项目列表/点击创建', async ({ page }) => {
  484 |     await page.goto(`${FRONTEND_URL}/#/pages/video-generator/index`, { waitUntil: 'networkidle', timeout: 30000 });
  485 |     await page.waitForTimeout(3000);
  486 | 
  487 |     await expect(page.locator('text=视频生成').first()).toBeVisible();
  488 | 
  489 |     // 点击创建新视频按钮
  490 |     const createBtn = page.locator('text=创建新视频').first();
  491 |     if (await createBtn.count() > 0) {
  492 |       await createBtn.click();
  493 |       await page.waitForTimeout(1000);
  494 |       console.log('点击创建新视频按钮成功,URL:', page.url());
  495 |     }
  496 | 
  497 |     // 描述文案
  498 |     const hasDesc = (await page.locator('text=图片 + 音频 = 精美视频').count()) > 0 ||
  499 |                     (await page.locator('text=视频').count()) > 0;
  500 |     expect(hasDesc).toBeTruthy();
  501 | 
  502 |     await page.screenshot({ path: `${SCREENSHOT_DIR}/e2e-E13-video-gen.png`, fullPage: true }).catch(() => {});
  503 |   });
  504 | 
  505 |   test('E14: 收藏页 - 收藏列表/取消收藏/空状态', async ({ page }) => {
  506 |     await page.goto(`${FRONTEND_URL}/#/pages/favorites/index`, { waitUntil: 'networkidle', timeout: 30000 });
  507 |     await page.waitForTimeout(3000);
  508 | 
  509 |     await expect(page.locator('text=我的收藏').first()).toBeVisible();
  510 | 
  511 |     // 空状态或列表
  512 |     const hasEmpty = (await page.locator('text=暂无收藏').count()) > 0;
  513 |     const hasList = (await page.locator('.item').count()) > 0;
  514 | 
  515 |     if (hasEmpty) {
  516 |       const hint = page.locator('text=去听书页面收藏喜欢的音频吧').first();
  517 |       if (await hint.count() > 0) await expect(hint).toBeVisible();
  518 |     } else if (hasList) {
  519 |       const item = page.locator('.item').first();
  520 |       await expect(item).toBeVisible();
  521 |     }
  522 | 
  523 |     await page.screenshot({ path: `${SCREENSHOT_DIR}/e2e-E14-favorites.png`, fullPage: true }).catch(() => {});
  524 |   });
  525 | 
  526 |   test('E15: 设置页 - 设置项/开关切换/弹窗选择/清理缓存', async ({ page }) => {
  527 |     await page.goto(`${FRONTEND_URL}/#/pages/settings/index`, { waitUntil: 'networkidle', timeout: 30000 });
  528 |     await page.waitForTimeout(3000);
  529 | 
  530 |     await expect(page.locator('text=设置').first()).toBeVisible();
  531 | 
  532 |     // 检查设置项可见性(不点击,避免弹窗遮挡)
  533 |     const voiceItem = page.locator('text=默认音色').first();
  534 |     if (await voiceItem.count() > 0) await expect(voiceItem).toBeVisible();
  535 | 
  536 |     const clearBtn = page.locator('text=清理缓存').first();
  537 |     if (await clearBtn.count() > 0) await expect(clearBtn).toBeVisible();
  538 | 
  539 |     // 版本信息
  540 |     await expect(page.locator('text=版本').first()).toBeVisible();
  541 | 
  542 |     await page.screenshot({ path: `${SCREENSHOT_DIR}/e2e-E15-settings.png`, fullPage: true }).catch(() => {});
  543 |   });
  544 | 
  545 |   // =============================================
  546 |   // E16-E20: 扩展页面(通知/播放列表/订单/发布/AI生成)