You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改Playwright请求追踪类:仅存在XHR请求时等待其完成

问题描述

我写了一个基于Playwright InflightRequests类的辅助方法,用来等待所有XHR请求完成,但在没有XHR请求的场景下,它还是会进入等待逻辑。我需要修改这个类,实现「有XHR请求就等全部完成,没有就直接跳过等待」的逻辑。另外想问问当前方法是否正确,以及有没有优化建议。

原代码

import {Page } from "@playwright/test";

export class InflightRequests {
    page: Page;
    requests: Set<unknown>;
  constructor(page:Page) {
    this.page = page;
    this.requests = new Set();
    this._onStarted = this._onStarted.bind(this);
    this._onFinished = this._onFinished.bind(this);
    this.page.on('request', this._onStarted);
    this.page.on('requestfinished', this._onFinished);
    this.page.on('requestfailed', this._onFinished);
  }

  _onStarted(request:any) { this.requests.add(request); }
  _onFinished(request:any) { this.requests.delete(request); }
 
  inflightRequests() { return Array.from(this.requests); }  

  dispose() {
    this.page.removeListener('request', this._onStarted);
    this.page.removeListener('requestfinished', this._onFinished);
    this.page.removeListener('requestfailed', this._onFinished);
  }
}

当前测试使用方式

expect.poll(() => this.tracker.inflightRequests().filter((request: any) => request.resourceType() === 'xhr').length).toBe(0)

解决方案与优化建议

一、修改类实现目标逻辑

当前问题核心是expect.poll会强制轮询直到条件满足,哪怕初始状态就没有XHR请求。我们可以通过单独跟踪XHR请求、封装智能等待方法来解决这个问题:

修改后的代码

import { Page, Request } from "@playwright/test";

export class InflightRequests {
    private page: Page;
    private allRequests: Set<Request>;
    private xhrRequests: Set<Request>; // 单独维护XHR请求集合

    constructor(page: Page) {
        this.page = page;
        this.allRequests = new Set();
        this.xhrRequests = new Set();
        this._onStarted = this._onStarted.bind(this);
        this._onFinished = this._onFinished.bind(this);
        this.page.on('request', this._onStarted);
        this.page.on('requestfinished', this._onFinished);
        this.page.on('requestfailed', this._onFinished);
    }

    private _onStarted(request: Request) {
        this.allRequests.add(request);
        // 仅跟踪XHR类型请求
        if (request.resourceType() === 'xhr') {
            this.xhrRequests.add(request);
        }
    }

    private _onFinished(request: Request) {
        this.allRequests.delete(request);
        this.xhrRequests.delete(request);
    }

    // 获取当前活跃的XHR请求
    inflightXhrRequests(): Request[] {
        return Array.from(this.xhrRequests);
    }

    // 智能等待方法:无XHR直接返回,有则等待全部完成
    async waitForXhrComplete(timeout = 5000) {
        if (this.xhrRequests.size === 0) {
            return;
        }
        await expect.poll(() => this.inflightXhrRequests().length, { timeout })
            .toBe(0);
    }

    inflightRequests(): Request[] {
        return Array.from(this.allRequests);
    }

    dispose() {
        this.page.removeListener('request', this._onStarted);
        this.page.removeListener('requestfinished', this._onFinished);
        this.page.removeListener('requestfailed', this._onFinished);
    }
}

修改后的使用方式

无需再手动过滤和写poll逻辑,直接调用封装好的方法即可:

await this.tracker.waitForXhrComplete();

二、原代码正确性分析

原代码的基础逻辑是可行的:通过监听请求生命周期事件跟踪活跃请求,dispose方法也正确移除了监听器避免内存泄漏。但存在明显不足:

  • 未区分请求类型,每次都需要在外部做filter,效率低且冗余
  • 无法直接判断是否需要等待,导致无XHR场景下仍会触发轮询,浪费测试时间

三、额外优化建议

  1. 类型安全强化:把原代码中的request: any替换为Playwright提供的Request类型,避免类型模糊导致的潜在错误
  2. 超时可配置:在等待方法中增加超时参数,防止极端情况下无限等待
  3. 扩展多类型支持:如果后续需要等待其他类型请求(如fetch、image),可以扩展方法支持自定义资源类型:
    async waitForRequestsComplete(resourceType: string = 'xhr', timeout = 5000) {
        const targetRequests = Array.from(this.allRequests).filter(req => 
            req.resourceType() === resourceType
        );
        if (targetRequests.length === 0) return;
        await expect.poll(() => 
            Array.from(this.allRequests).filter(req => req.resourceType() === resourceType).length,
            { timeout }
        ).toBe(0);
    }
    
  4. 防止重复监听:可以在构造函数中添加校验,避免同一Page实例被多次初始化该类(可选)

内容的提问来源于stack exchange,提问作者YusufOzt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 02:27:45