Cypress监视React组件调用的外部函数失败及网络测试疑难咨询
一、为什么监视独立文件的函数失效?
你测试代码里导入的func和应用运行时的func不是同一个实例——测试代码在Cypress的Node环境执行,而应用代码是打包后在浏览器环境运行,两者的模块实例完全隔离。你给测试环境的func.call加了spy,但应用里调用的是浏览器环境里的那个,自然检测不到。
解决方法:
- 把
func挂载到浏览器的window对象上,这样测试可以通过cy.window()获取到应用里的实例:
在你的test.js里添加:
然后在测试里:export const func = { call: (e) => console.log(e), }; // 仅在测试环境暴露到window if (process.env.NODE_ENV === 'test') { window.testFunc = func; }describe("template spec", () => { it("calls func.call", () => { cy.visit("/"); cy.window().then(win => { cy.spy(win.testFunc, "call").as('funcCall'); // 用as命名方便后续断言 }); // 触发调用func.call的操作 cy.get('[data-testid="trigger-button"]').click(); cy.get('@funcCall').should('have.been.called'); }); }); - 或者用Cypress的
cy.stub直接替换应用里的函数实现,通过修改全局对象或者模块依赖(如果用webpack等打包工具,可通过注入替换模块)。
二、如何测试Socket.io流量?
方法1:监视浏览器里的Socket实例
如果应用里的Socket.io客户端挂载到了window,可以直接监听它的emit/on方法:
cy.visit('/'); cy.window().then(win => { // 监视socket.emit调用 cy.spy(win.socket, 'emit').as('socketEmit'); // 监视socket.on接收事件 cy.spy(win.socket, 'on').as('socketOn'); }); // 触发Socket操作 cy.get('[data-testid="send-socket-event"]').click(); // 断言emit被调用,且参数正确 cy.get('@socketEmit').should('have.been.calledWith', 'message', 'hello world');
方法2:拦截Socket.io的HTTP请求
Socket.io初始握手是HTTP请求,后续用WebSocket传输,你可以用cy.intercept拦截握手请求,或者监听WebSocket帧(Cypress 9+支持WebSocket拦截):
// 拦截Socket.io的握手请求 cy.intercept('GET', '/socket.io/?EIO=4&transport=polling*').as('socketHandshake'); cy.visit('/'); cy.wait('@socketHandshake'); // 拦截WebSocket帧(Cypress 9+) cy.intercept('ws', 'ws://localhost:3000/socket.io/*').as('socketWs'); cy.get('@socketWs').then(interception => { // 查看WebSocket的发送/接收数据 console.log(interception.messages); });
方法3:启动本地mock Socket服务
在测试前启动一个简单的Socket.io服务,让应用连接到这个mock服务,然后验证双向通信:
// 在测试文件顶部启动mock服务 const { Server } = require('socket.io'); let io; before(() => { io = new Server(3001); io.on('connection', (socket) => { socket.on('message', (data) => { socket.emit('reply', `received: ${data}`); }); }); }); after(() => { io.close(); }); it('tests socket communication', () => { // 确保应用连接到mock服务(可通过环境变量配置) cy.visit('/', { onBeforeLoad: (win) => { win.SOCKET_URL = 'ws://localhost:3001'; } }); cy.window().then(win => { cy.spy(win.socket, 'on').as('socketOn'); }); cy.get('[data-testid="send-message"]').click(); cy.get('@socketOn').should('have.been.calledWith', 'reply', 'received: hello'); });
三、如何获取fetch的原始请求体(包括FormData)?
cy.intercept里的req.body如果是FormData,会被序列化为字符串(比如multipart/form-data格式的字符串),无法直接读取。你需要用req.formData()方法异步解析:
cy.intercept('POST', '/api/upload', async (req) => { // 解析FormData const formData = await req.formData(); // 获取FormData里的字段 const username = formData.get('username'); const file = formData.get('avatar'); // 断言字段正确 expect(username).to.equal('test-user'); expect(file.name).to.equal('avatar.jpg'); // 发送mock响应 req.reply({ statusCode: 200, body: { success: true } }); }).as('uploadRequest'); // 触发上传操作 cy.get('[data-testid="upload-button"]').click(); cy.wait('@uploadRequest');
如果是普通JSON请求,直接用req.body即可;如果是application/x-www-form-urlencoded格式,可用req.body解析为对象,或用req.formData()获取。
内容的提问来源于stack exchange,提问作者Maddin
相关产品推荐
相关产品推荐

