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

如何让Playwright监听postMessage通信触发的message事件

问题根因

你当前写法的核心问题是,page.evaluate 执行的代码运行在浏览器隔离上下文,传入的参数是序列化后拷贝到浏览器环境的,和Node测试侧的returnEvent 不存在引用关联,浏览器侧对该变量的修改完全不会同步到测试代码的执行环境,因此你拿到的永远是空对象。

解决方案

方案1:通过 exposeBinding 直接跨上下文传递数据

Playwright 提供的exposeBinding 方法可以把Node侧的函数暴露给浏览器上下文调用,你可以用它直接把监听到的message数据回传到测试侧,无需硬等固定时长:

// 定义Promise等待消息返回
const waitForPaymentMessage = new Promise<any>((resolve) => {
  page.exposeBinding('onPaymentMessage', (_, eventData) => resolve(eventData));
});

// 注入message监听器,符合条件时调用暴露的方法回传数据
await page.evaluate(() => {
  window.addEventListener('message', (event: MessageEvent) => {
    if (event.data.messageId === 'payment-method') {
      // @ts-ignore 调用Node侧暴露的方法传递数据
      window.onPaymentMessage(event.data);
    }
  });
});

// 执行触发消息的操作
await creditCardDetailsPage.fillFormValid();

// 等待消息返回,可自定义超时时间,默认5秒
const receivedEvent = await waitForPaymentMessage;

// 直接执行断言
await expect(receivedEvent).toEqual(<MY DATA OBJECT HERE>)

方案2:等待浏览器侧全局变量赋值后拉取

如果你不想使用exposeBinding,也可以把符合条件的事件挂载到window全局对象上,测试侧等待变量生成后再拉取到Node上下文使用:

// 注入监听器,符合条件时将事件挂载到window全局对象
await page.evaluate(() => {
  // @ts-ignore 声明全局存储变量
  window.paymentMessageEvent = null;
  window.addEventListener('message', (event: MessageEvent) => {
    if (event.data.messageId === 'payment-method') {
      // @ts-ignore 赋值全局变量
      window.paymentMessageEvent = event.data;
    }
  });
});

await creditCardDetailsPage.fillFormValid();

// 等待全局变量被赋值,可自定义超时时间
await page.waitForFunction(() => window.paymentMessageEvent !== null, { timeout: 10000 });

// 拉取浏览器侧的全局变量到测试上下文
const receivedEvent = await page.evaluate(() => window.paymentMessageEvent);

await expect(receivedEvent).toEqual(<MY DATA OBJECT HERE>)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 17:15:03