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

Cypress中WebSocket Mock响应写入文件遇异步问题求解决方案

Cypress Mock WebSocket 时异步写入文件的解决方案

我在使用Cypress Mock WebSocket时,希望把接收到的消息写入文件,但在Socket的事件处理器里执行cy.writeFile()这类异步Cypress命令会报错,需要合适的解决办法。

代码示例

export function trackWebSocketTraffic() {
  let messages: string[] = []

  cy.window().then((win) => {
    cy.stub(win, 'WebSocketFactory').callsFake(
      (url: string, handlers: WebSocketEventHandlers) => {
        console.log('WebSocket URL:', url)
        const webSocket = new WebSocket(url)
        webSocket.onopen = handlers.onopen
        webSocket.onmessage = (event: MessageEvent) => {
          messages.push(event.data)
          handlers.onmessage(event)
        }
        webSocket.onclose = (event: CloseEvent) => {
          cy.writeFile('./test', messages) // !!! Can't put cy.writeFile in async handler
          handlers.onclose(event)
        }
        return webSocket
      }
    )
  })
}

触发的错误信息

以下错误源自您的测试代码,而非Cypress。

Cypress检测到您从一个命令返回了Promise,同时在该Promise中调用了一个或多个cy命令。

返回Promise的命令是:

cy.get()

您在Promise中调用的cy命令是:

cy.writeFile()

由于Cypress命令本身已类似Promise,您无需对其进行包装或返回自定义Promise。

Cypress会以最终的Cypress命令返回值来解析您的命令。

将此设为错误而非警告的原因是,Cypress内部会串行排队命令,而Promise会在被调用时立即执行。尝试协调二者会导致Cypress永远无法解析。

当Cypress检测到源自测试代码的未捕获错误时,会自动使当前测试失败。

解决方案

1. 用cy.wrap()将操作纳入Cypress命令队列

WebSocket事件处理器属于异步回调,不在Cypress的命令执行流中,直接调用cy.writeFile()会触发错误。可以通过cy.wrap()把消息数组包装后,再执行写入命令,确保操作进入Cypress的串行队列:

修改onclose事件处理器:

webSocket.onclose = (event: CloseEvent) => {
  handlers.onclose(event)
  // 通过cy.wrap将messages注入Cypress命令流
  cy.wrap(messages).then(msgList => {
    cy.writeFile('./test', msgList)
  })
}

2. 借助Cypress Task调用Node.js文件系统

如果不需要通过Cypress命令队列执行,可利用Cypress的task机制,在Node.js环境中完成文件写入(避免浏览器上下文限制):

  1. 在cypress.config.js中注册自定义task:
const { defineConfig } = require('cypress')
const fs = require('fs')

module.exports = defineConfig({
  e2e: {
    setupNodeEvents(on, config) {
      on('task', {
        writeWebSocketMessages: (messages) => {
          // 用同步写入避免Promise嵌套,也可使用fs.writeFile异步版本
          fs.writeFileSync('./test', JSON.stringify(messages))
          return null
        }
      })
    },
  },
})
  1. 在WebSocket的onclose回调中调用该task:
webSocket.onclose = (event: CloseEvent) => {
  handlers.onclose(event)
  cy.task('writeWebSocketMessages', messages)
}

3. 测试流程中统一收集并写入

如果可以在测试用例中明确控制WebSocket关闭时机,可将消息挂载到window对象,在测试流程的合适节点统一执行写入:

  1. 修改trackWebSocketTraffic函数,将消息数组挂载到window:
export function trackWebSocketTraffic() {
  cy.window().then((win) => {
    win.webSocketMessages = [] // 挂载到window供测试用例访问
    cy.stub(win, 'WebSocketFactory').callsFake(
      (url: string, handlers: WebSocketEventHandlers) => {
        const webSocket = new WebSocket(url)
        webSocket.onopen = handlers.onopen
        webSocket.onmessage = (event: MessageEvent) => {
          win.webSocketMessages.push(event.data)
          handlers.onmessage(event)
        }
        webSocket.onclose = handlers.onclose
        return webSocket
      }
    )
  })
}
  1. 在测试用例中等待关闭后执行写入:
trackWebSocketTraffic()
// 执行触发WebSocket关闭的操作(示例)
cy.get('#close-socket-btn').click()
// 从window获取消息并写入
cy.window().then(win => {
  cy.writeFile('./test', win.webSocketMessages)
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 03:14:57