# 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 完整验收 >> E13: 视频生成列表页 - 创建入口/项目列表/点击创建 - Location: regression\23-frontend-e2e.spec.ts:483: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 ```ts 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(); 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(); | ^ Error: expect(locator).toBeVisible() failed 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生成) 547 | // ============================================= 548 | 549 | test('E16: 通知页面 - 通知列表/标记已读/清空', async ({ page }) => { 550 | await page.goto(`${FRONTEND_URL}/#/pages/notifications/index`, { waitUntil: 'networkidle', timeout: 30000 }); 551 | await page.waitForTimeout(3000); 552 | 553 | await expect(page.locator('#app')).toBeVisible(); 554 | 555 | // 通知列表或空状态 556 | const hasContent = 557 | (await page.locator('text=暂无通知').count()) > 0 || 558 | (await page.locator('.item').count()) > 0; 559 | expect(hasContent || true).toBeTruthy(); 560 | 561 | // 点击全部已读按钮 562 | const readAllBtn = page.locator('text=全部已读').first(); 563 | if (await readAllBtn.count() > 0) { 564 | await readAllBtn.click(); 565 | await page.waitForTimeout(500); 566 | console.log('点击全部已读按钮成功'); 567 | } 568 | 569 | await page.screenshot({ path: `${SCREENSHOT_DIR}/e2e-E16-notifications.png`, fullPage: true }).catch(() => {}); 570 | }); 571 | 572 | test('E17: 播放列表页 - 列表展示/移除/排序', async ({ page }) => { 573 | await page.goto(`${FRONTEND_URL}/#/pages/playlists/index`, { waitUntil: 'networkidle', timeout: 30000 }); 574 | await page.waitForTimeout(3000); 575 | 576 | await expect(page.locator('#app')).toBeVisible(); 577 | 578 | // 页面标题 579 | const hasTitle = (await page.locator('text=播放列表').count()) > 0; 580 | expect(hasTitle || true).toBeTruthy(); 581 | 582 | // 空状态或列表 583 | const hasContent = 584 | (await page.locator('text=暂无播放列表').count()) > 0 || 585 | (await page.locator('.item').count()) > 0; 586 | expect(hasContent || true).toBeTruthy(); 587 | ```