Node.js Azure Function使用Jest模拟POST请求报res.on is not a function问题
问题原因
你的Jest模拟逻辑存在两个核心错误:
https.request的执行逻辑是:调用后先返回Request实例(需要支持write/end/on('error')方法),待响应就绪后才会执行传入的回调函数,将Response对象作为参数传入回调。你之前的写法混淆了返回值和回调参数的边界。- 你在模拟中写了
cb('res')({on: jest.fn()}),相当于先执行回调传入字符串'res',再把回调的返回值当做函数二次调用,最终传给业务代码的res实际是字符串'res',自然不存在on方法,抛出类型错误。
修复方案
重新梳理https.request的模拟逻辑,分别实现Request实例和Response实例的方法,并且根据不同测试场景触发对应的data/end/error事件即可。
完整测试代码示例
const https = require('https'); const fs = require('fs'); const myFunction = require('./index'); // 模拟依赖模块 jest.mock('https'); jest.mock('fs', () => ({ readFileSync: jest.fn(() => '-----BEGIN CERTIFICATE-----\ntest_cert_content\n-----END CERTIFICATE-----\n') })); describe('Azure Function POST接口测试', () => { // 测试前预置环境变量 beforeAll(() => { process.env.username = 'test_user'; process.env.pwd = 'test_pwd'; process.env.host = 'test.api.com'; process.env.path = '/submit'; process.env.port = '443'; }); // 每次测试前重置模拟状态 beforeEach(() => { https.request.mockReset(); }); test('200响应正常返回场景', async () => { const mockReturnData = { code: 0, msg: 'success', result: {} }; // 模拟Request实例 const mockReq = { write: jest.fn(), end: jest.fn(), on: jest.fn() }; // 实现https.request模拟逻辑 https.request.mockImplementation((options, callback) => { // 模拟Response实例 const mockRes = { statusCode: 200, statusMessage: 'OK', on: jest.fn((event, cb) => { if (event === 'data') { // 触发data事件传入响应数据 cb(Buffer.from(JSON.stringify(mockReturnData))); } if (event === 'end') { // 触发end事件结束响应 cb(); } }) }; // 执行回调传入响应对象 callback(mockRes); return mockReq; }); const mockContext = { log: jest.fn() }; const postData = JSON.stringify({ correlationId: 'test_001', content: 'test' }); const result = await myFunction(mockContext, postData); // 断言执行结果符合预期 expect(result).toEqual(mockReturnData); expect(mockReq.write).toHaveBeenCalledWith(postData); expect(mockReq.end).toHaveBeenCalledTimes(1); }); test('401认证错误场景', async () => { const mockReq = { write: jest.fn(), end: jest.fn(), on: jest.fn() }; https.request.mockImplementation((options, callback) => { const mockRes = { statusCode: 401, statusMessage: 'Unauthorized', on: jest.fn((event, cb) => { if (event === 'data') cb(Buffer.from('')); if (event === 'end') cb(); }) }; callback(mockRes); return mockReq; }); const mockContext = { log: jest.fn() }; const postData = JSON.stringify({ correlationId: 'test_002' }); await expect(myFunction(mockContext, postData)).rejects.toEqual({ errorCode: 401, errorMessage: 'Unauthorized', errorDescription: 'Unauthorized' }); }); test('请求异常场景(域名无法解析)', async () => { const mockReq = { write: jest.fn(), end: jest.fn(), on: jest.fn((event, cb) => { if (event === 'error') cb(new Error('ENOTFOUND test.api.com')); }) }; https.request.mockImplementation(() => mockReq); const mockContext = { log: jest.fn() }; const postData = JSON.stringify({ correlationId: 'test_003' }); await expect(myFunction(mockContext, postData)).rejects.toEqual({ errorCode: 404, errorMessage: 'ENOTFOUND test.api.com', errorDescription: 'ENOTFOUND test.api.com' }); }); });
额外注意事项
如果需要测试非200/401的其他错误码、JSON解析异常等场景,只需要对应修改mockResponse的statusCode、返回的data内容即可。
内容的提问来源于stack exchange,提问作者Sharath Jallu
相关产品推荐
相关产品推荐

