Playwright如何模拟请求延迟/永不响应的测试场景?
问题描述
我需要测试服务在响应延迟或永不响应时的表现,目前采用了如下暴力实现方式:
await page.route(url, () => page.waitForTimeout(1000));
但Playwright文档指出page.waitForTimeout()仅适用于调试场景。我想了解:
- 如何让页面请求指定URL时触发超时?
- 另一种场景:当页面请求
api/items这类接口时,如何在请求未完成前检查页面状态?
测试示例代码如下:
import { test, expect } from '@playwright/test'; test('banner shows in progress message', async ({ page }) => { await page.route('**/async-resource.json', () => { // 该请求应在测试结束前保持未完成状态 page.waitForTimeout(1000); }); await page.goto('https://async.page/'); const banner = page.getByRole('banner'); await expect(banner).toHaveText('Your data are being prepared!'); });
解决方案
1. 模拟指定URL请求超时或挂起
不要使用page.waitForTimeout(),可以通过以下两种方式实现:
- 模拟请求永不响应:创建一个永远不resolve的Promise,让请求一直处于挂起状态:
await page.route('**/async-resource.json', () => new Promise(() => {})); - 模拟请求超时错误:延迟后拒绝Promise,触发请求超时:
await page.route('**/async-resource.json', () => new Promise((_, reject) => setTimeout(() => reject(new Error("请求超时")), 1000)) );
2. 在请求未完成前检查页面状态
通过拦截请求后不立即处理(不调用route.continue()或route.fulfill()),即可在请求挂起时检查页面状态。修正后的测试代码如下:
import { test, expect } from '@playwright/test'; test('banner shows in progress message', async ({ page }) => { // 拦截请求并保持挂起 await page.route('**/async-resource.json', (route) => { // 不调用任何处理方法,请求会一直处于未完成状态 }); await page.goto('https://async.page/'); // 等待请求被拦截(确保页面已发起请求) await page.waitForEvent('request', req => req.url().includes('async-resource.json')); // 此时请求未完成,检查页面加载状态 const banner = page.getByRole('banner'); await expect(banner).toHaveText('Your data are being prepared!'); // 若后续需要恢复请求,可调用 route.continue() // route.continue(); });
如果需要更灵活的控制(比如后续恢复请求),可以将路由实例保存到Promise中:
import { test, expect } from '@playwright/test'; test('banner shows in progress message', async ({ page }) => { let holdRoute; const requestHeld = new Promise(resolve => { page.route('**/async-resource.json', (route) => { holdRoute = route; resolve(); }); }); await page.goto('https://async.page/'); await requestHeld; // 等待请求被拦截 // 检查页面状态 const banner = page.getByRole('banner'); await expect(banner).toHaveText('Your data are being prepared!'); // 可选:恢复请求 // holdRoute.continue(); });
内容的提问来源于stack exchange,提问作者pbaranski
相关产品推荐
相关产品推荐

