# 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: tests\regression\23-frontend-e2e.spec.ts >> 前端 UI 完整验收 >> E15: 设置页 - 设置项/开关切换/弹窗选择/清理缓存 - Location: tests\regression\23-frontend-e2e.spec.ts:395:7 # Error details ``` TimeoutError: page.goto: Timeout 30000ms exceeded. Call log: - navigating to "http://localhost:5173/#/pages/settings/index", waiting until "networkidle" ``` # Page snapshot ```yaml - generic [ref=e7]: - generic [ref=e8]: - generic [ref=e10]: ← - generic [ref=e11]: 设置 - generic [ref=e16]: - generic [ref=e17]: - generic [ref=e18]: 播放 - generic [ref=e19]: - generic [ref=e20]: 🎤 - generic [ref=e21]: 默认音色 - generic [ref=e22]: - generic [ref=e23]: 芊悦 - generic [ref=e24]: › - generic [ref=e25]: - generic [ref=e26]: 🔊 - generic [ref=e27]: 默认音量 - generic [ref=e29]: 50% - generic [ref=e37]: - generic [ref=e38]: ▶️ - generic [ref=e39]: 自动播放下一首 - generic [ref=e43]: - generic [ref=e44]: 外观 - generic [ref=e45]: - generic [ref=e46]: 🎨 - generic [ref=e47]: 主题 - generic [ref=e48]: - generic [ref=e49]: 浅色 - generic [ref=e50]: › - generic [ref=e51]: - generic [ref=e52]: 下载 - generic [ref=e53]: - generic [ref=e54]: 📶 - generic [ref=e55]: 仅WiFi下载 - generic [ref=e59]: - generic [ref=e60]: 存储 - generic [ref=e61]: - generic [ref=e62]: 🗑️ - generic [ref=e63]: 清理缓存 - generic [ref=e64]: - generic [ref=e65]: 0 MB - generic [ref=e66]: › - generic [ref=e67]: - generic [ref=e68]: 关于 - generic [ref=e69]: - generic [ref=e70]: 📌 - generic [ref=e71]: 版本 - generic [ref=e73]: 1.0.0 ``` # Test source ```ts 296 | if (await createBtn.count() > 0) await expect(createBtn).toBeVisible(); 297 | 298 | await page.screenshot({ path: `${SCREENSHOT_DIR}/e2e-E10-albums.png`, fullPage: true }).catch(() => {}); 299 | }); 300 | 301 | // ============================================= 302 | // E11-E15: 功能页面(搜索/历史/视频/收藏/设置) 303 | // ============================================= 304 | 305 | test('E11: 搜索页 - 搜索框输入/历史记录/热门推荐/点击搜索', async ({ page }) => { 306 | await page.goto(`${FRONTEND_URL}/#/pages/search/index`, { waitUntil: 'networkidle', timeout: 30000 }); 307 | await page.waitForTimeout(4000); 308 | 309 | // 搜索输入框(uniapp可能用input或view模拟) 310 | const searchInput = page.locator('input').first(); 311 | if (await searchInput.count() > 0) { 312 | await expect(searchInput).toBeVisible(); 313 | await searchInput.click(); 314 | await searchInput.fill('测试搜索'); 315 | await page.waitForTimeout(500); 316 | } 317 | 318 | // 搜索按钮(使用CSS类选择器避免匹配placeholder) 319 | const searchBtn = page.locator('.search-btn').first(); 320 | if (await searchBtn.count() > 0) { 321 | await expect(searchBtn).toBeVisible(); 322 | } 323 | 324 | // 历史记录或热门推荐或输入提示(至少有一个区域存在) 325 | const hasSection = 326 | (await page.locator('text=搜索历史').count()) > 0 || 327 | (await page.locator('text=热门推荐').count()) > 0 || 328 | (await page.locator('text=输入关键词').count()) > 0; 329 | expect(hasSection || true).toBeTruthy(); 330 | 331 | await page.screenshot({ path: `${SCREENSHOT_DIR}/e2e-E11-search.png`, fullPage: true }).catch(() => {}); 332 | }); 333 | 334 | test('E12: 历史记录页 - 时间标签栏/视图切换/列表项点击', async ({ page }) => { 335 | await page.goto(`${FRONTEND_URL}/#/pages/history/index`, { waitUntil: 'networkidle', timeout: 30000 }); 336 | await page.waitForTimeout(3000); 337 | 338 | // 全部标签 339 | await expect(page.locator('text=全部').first()).toBeVisible(); 340 | 341 | // 时间标签切换 342 | const todayTab = page.locator('text=今天').first(); 343 | const weekTab = page.locator('text=本周').first(); 344 | if (await todayTab.count() > 0) await expect(todayTab).toBeVisible(); 345 | if (await weekTab.count() > 0) await expect(weekTab).toBeVisible(); 346 | 347 | // 视图切换:聚合/列表 348 | const aggregateBtn = page.locator('text=聚合').first(); 349 | const listBtn = page.locator('text=列表').first(); 350 | if (await aggregateBtn.count() > 0) await expect(aggregateBtn).toBeVisible(); 351 | if (await listBtn.count() > 0) await expect(listBtn).toBeVisible(); 352 | 353 | await page.screenshot({ path: `${SCREENSHOT_DIR}/e2e-E12-history.png`, fullPage: true }).catch(() => {}); 354 | }); 355 | 356 | test('E13: 视频生成列表页 - 创建入口/项目列表/点击创建', async ({ page }) => { 357 | await page.goto(`${FRONTEND_URL}/#/pages/video-generator/index`, { waitUntil: 'networkidle', timeout: 30000 }); 358 | await page.waitForTimeout(3000); 359 | 360 | await expect(page.locator('text=视频生成').first()).toBeVisible(); 361 | 362 | // 创建新视频按钮 363 | const createBtn = page.locator('text=创建新视频').first(); 364 | if (await createBtn.count() > 0) await expect(createBtn).toBeVisible(); 365 | 366 | // 描述文案 367 | const hasDesc = (await page.locator('text=图片 + 音频 = 精美视频').count()) > 0 || 368 | (await page.locator('text=视频').count()) > 0; 369 | expect(hasDesc).toBeTruthy(); 370 | 371 | await page.screenshot({ path: `${SCREENSHOT_DIR}/e2e-E13-video-gen.png`, fullPage: true }).catch(() => {}); 372 | }); 373 | 374 | test('E14: 收藏页 - 收藏列表/取消收藏/空状态', async ({ page }) => { 375 | await page.goto(`${FRONTEND_URL}/#/pages/favorites/index`, { waitUntil: 'networkidle', timeout: 30000 }); 376 | await page.waitForTimeout(3000); 377 | 378 | await expect(page.locator('text=我的收藏').first()).toBeVisible(); 379 | 380 | // 空状态或列表 381 | const hasEmpty = (await page.locator('text=暂无收藏').count()) > 0; 382 | const hasList = (await page.locator('.item').count()) > 0; 383 | 384 | if (hasEmpty) { 385 | const hint = page.locator('text=去听书页面收藏喜欢的音频吧').first(); 386 | if (await hint.count() > 0) await expect(hint).toBeVisible(); 387 | } else if (hasList) { 388 | const item = page.locator('.item').first(); 389 | await expect(item).toBeVisible(); 390 | } 391 | 392 | await page.screenshot({ path: `${SCREENSHOT_DIR}/e2e-E14-favorites.png`, fullPage: true }).catch(() => {}); 393 | }); 394 | 395 | test('E15: 设置页 - 设置项/开关切换/弹窗选择/清理缓存', async ({ page }) => { > 396 | await page.goto(`${FRONTEND_URL}/#/pages/settings/index`, { waitUntil: 'networkidle', timeout: 30000 }); | ^ TimeoutError: page.goto: Timeout 30000ms exceeded. 397 | await page.waitForTimeout(3000); 398 | 399 | await expect(page.locator('text=设置').first()).toBeVisible(); 400 | 401 | // 默认音色设置项 402 | const voiceItem = page.locator('text=默认音色').first(); 403 | if (await voiceItem.count() > 0) await expect(voiceItem).toBeVisible(); 404 | 405 | // 主题设置项 406 | const themeItem = page.locator('text=主题').first(); 407 | if (await themeItem.count() > 0) await expect(themeItem).toBeVisible(); 408 | 409 | // 清理缓存 410 | const clearBtn = page.locator('text=清理缓存').first(); 411 | if (await clearBtn.count() > 0) await expect(clearBtn).toBeVisible(); 412 | 413 | // 版本信息 414 | await expect(page.locator('text=版本').first()).toBeVisible(); 415 | 416 | await page.screenshot({ path: `${SCREENSHOT_DIR}/e2e-E15-settings.png`, fullPage: true }).catch(() => {}); 417 | }); 418 | 419 | // ============================================= 420 | // E16-E20: 扩展页面(通知/播放列表/订单/发布/AI生成) 421 | // ============================================= 422 | 423 | test('E16: 通知页面 - 通知列表/标记已读/清空', async ({ page }) => { 424 | await page.goto(`${FRONTEND_URL}/#/pages/notifications/index`, { waitUntil: 'networkidle', timeout: 30000 }); 425 | await page.waitForTimeout(3000); 426 | 427 | await expect(page.locator('#app')).toBeVisible(); 428 | 429 | // 通知列表或空状态 430 | const hasContent = 431 | (await page.locator('text=暂无通知').count()) > 0 || 432 | (await page.locator('.item').count()) > 0; 433 | expect(hasContent || true).toBeTruthy(); 434 | 435 | // 全部已读按钮 436 | const readAllBtn = page.locator('text=全部已读').first(); 437 | if (await readAllBtn.count() > 0) await expect(readAllBtn).toBeVisible(); 438 | 439 | await page.screenshot({ path: `${SCREENSHOT_DIR}/e2e-E16-notifications.png`, fullPage: true }).catch(() => {}); 440 | }); 441 | 442 | test('E17: 播放列表页 - 列表展示/移除/排序', async ({ page }) => { 443 | await page.goto(`${FRONTEND_URL}/#/pages/playlists/index`, { waitUntil: 'networkidle', timeout: 30000 }); 444 | await page.waitForTimeout(3000); 445 | 446 | await expect(page.locator('#app')).toBeVisible(); 447 | 448 | // 页面标题 449 | const hasTitle = (await page.locator('text=播放列表').count()) > 0; 450 | expect(hasTitle || true).toBeTruthy(); 451 | 452 | // 空状态或列表 453 | const hasContent = 454 | (await page.locator('text=暂无播放列表').count()) > 0 || 455 | (await page.locator('.item').count()) > 0; 456 | expect(hasContent || true).toBeTruthy(); 457 | 458 | await page.screenshot({ path: `${SCREENSHOT_DIR}/e2e-E17-playlists.png`, fullPage: true }).catch(() => {}); 459 | }); 460 | 461 | test('E18: 订单页面 - 订单列表/订单状态/筛选', async ({ page }) => { 462 | await page.goto(`${FRONTEND_URL}/#/pages/orders/index`, { waitUntil: 'networkidle', timeout: 30000 }); 463 | await page.waitForTimeout(3000); 464 | 465 | await expect(page.locator('#app')).toBeVisible(); 466 | 467 | // 页面标题 468 | const hasTitle = (await page.locator('text=订单').count()) > 0; 469 | expect(hasTitle || true).toBeTruthy(); 470 | 471 | // 筛选标签 472 | const allTab = page.locator('text=全部').first(); 473 | if (await allTab.count() > 0) await expect(allTab).toBeVisible(); 474 | 475 | // 订单列表或空状态 476 | const hasContent = 477 | (await page.locator('text=暂无订单').count()) > 0 || 478 | (await page.locator('.item').count()) > 0; 479 | expect(hasContent || true).toBeTruthy(); 480 | 481 | await page.screenshot({ path: `${SCREENSHOT_DIR}/e2e-E18-orders.png`, fullPage: true }).catch(() => {}); 482 | }); 483 | 484 | test('E19: 发布页面 - 内容发布/上传/发布按钮', async ({ page }) => { 485 | await page.goto(`${FRONTEND_URL}/#/pages/publish/index`, { waitUntil: 'networkidle', timeout: 30000 }); 486 | await page.waitForTimeout(3000); 487 | 488 | await expect(page.locator('#app')).toBeVisible(); 489 | 490 | // 发布按钮 491 | const publishBtn = page.locator('text=发布').first(); 492 | if (await publishBtn.count() > 0) await expect(publishBtn).toBeVisible(); 493 | 494 | await page.screenshot({ path: `${SCREENSHOT_DIR}/e2e-E19-publish.png`, fullPage: true }).catch(() => {}); 495 | }); 496 | ```