现象
报 Error: Test timeout of 30000ms exceeded 或 locator.waitFor: Timeout 30000ms exceeded;本地通过、CI 超时;只在并行执行时失败;页面明显还在加载骨架屏。
诊断
先单独运行该用例并开启 trace:
npx playwright test tests/checkout.spec.ts --trace on --workers=1
npx playwright show-trace test-results/checkout/trace.zip
npx playwright test tests/checkout.spec.ts --debug
trace 包含失败时的 DOM 快照、网络请求与控制台输出,能看出页面究竟停在什么状态;Inspector 会高亮定位器并说明是可见性、稳定性还是遮挡导致等待。截图里若有错误提示或加载动画,通常是应用问题而非选择器笔误。再用单 worker 重复执行:
npx playwright test tests/checkout.spec.ts --workers=1 --repeat-each=3
串行通过而并行失败,说明用例共享了账号或数据,不是等待时间不够。
修复
使用 web-first 断言和基于角色、标签的定位器,等待可观察条件而不是固定睡眠:
await page.getByRole('button', { name: 'Place order' }).click();
await expect(page.getByRole('heading', { name: 'Order confirmed' })).toBeVisible();
await expect(page).toHaveURL(/\/orders\/\d+/);
依赖接口结果时,用 page.waitForResponse 与点击同时等待。为每个 worker 准备独立数据,避免执行顺序耦合;确属慢流程的用例再单独设置超时,不要全局调大。
验证
按 CI 的 worker 数量连续运行三次且不启用重试,全部通过;打开通过用例的 trace,确认元素在预期步骤被找到并操作,而不是靠偶然的长等待。若仍偶发失败,继续检查共享数据与网络竞态,而不是继续加超时。