Cypress测试间WebSocket变量失效?握手失败问题排查
问题分析与解决方案
问题根源
你当前的代码将WebSocket实例声明在所有测试外部,属于全局变量。当运行多个测试时,所有测试会复用同一个WebSocket连接实例,导致连接状态混乱:
- 第一个测试可能已经打开并关闭了连接,后续测试再操作该实例时,连接可能处于异常状态(如已关闭、正在连接中)
- 服务器收到重复的连接请求或异常的握手信息,返回错误码200(通常表示HTTP请求而非WebSocket握手,属于协议错误)
修复方案
核心思路是每个测试使用独立的WebSocket实例,并确保测试前后的连接清理,避免状态交叉影响。
方案1:使用beforeEach/afterEach管理连接生命周期
describe("WebSocket测试组", () => { let ws; // 每个测试前创建全新的WebSocket连接 beforeEach(() => { ws = new WebSocket(wsUrl); }); // 每个测试后强制清理连接,避免残留状态 afterEach((done) => { switch(ws.readyState) { case WebSocket.OPEN: ws.close(); ws.onclose = () => done(); break; case WebSocket.CONNECTING: ws.onclose = () => done(); ws.close(); break; default: done(); } }); it("向WSS发送消息", (done) => { ws.onopen = () => { ws.send(Message); // 可选:验证服务器响应 ws.onmessage = (event) => { expect(event.data).to.equal("预期的响应内容"); done(); }; }; // 捕获连接错误,防止测试挂起 ws.onerror = (error) => done(error); }); it("关闭WSS连接", (done) => { ws.onopen = () => { ws.close(); ws.onclose = () => { expect(ws.readyState).to.equal(WebSocket.CLOSED); done(); }; }; ws.onerror = (error) => done(error); }); });
方案2:用Promise封装WebSocket流程(更符合Cypress异步模型)
避免使用done回调,改用Promise封装WebSocket的异步操作,让Cypress自动处理等待:
describe("WebSocket测试组", () => { it("向WSS发送消息", () => { cy.wrap(new Promise((resolve, reject) => { const ws = new WebSocket(wsUrl); ws.onopen = () => { ws.send(Message); ws.onmessage = (event) => { ws.close(); resolve(event.data); }; }; ws.onerror = reject; ws.onclose = () => reject(new Error("连接未完成就关闭")); })).then((response) => { expect(response).to.equal("预期的响应内容"); }); }); it("关闭WSS连接", () => { cy.wrap(new Promise((resolve, reject) => { const ws = new WebSocket(wsUrl); ws.onopen = () => { ws.close(); ws.onclose = () => resolve(); }; ws.onerror = reject; })).then(() => { // 验证连接已关闭(可选) }); }); });
关键注意事项
- 绝对不要复用WebSocket实例:每个测试必须创建独立的连接,避免状态污染
- 处理异常场景:添加
onerror监听,防止连接失败时测试无限挂起 - 确保清理完成:
afterEach中覆盖所有可能的连接状态(打开、连接中、已关闭),保证测试环境干净
内容的提问来源于stack exchange,提问作者Balmorax
相关产品推荐
相关产品推荐

