Jest Spy模拟失效及node-fetch参数监听问题求助
解决ConvertkitServer测试中的两个问题
问题1:jest.spyOn未生效,仍执行真实的getConvertkitTags方法
这大概率是你spyOn的目标不对,常见原因和解决方式:
如果ConvertkitServer是类,你spyOn了类本身而非实例
类的实例方法存在于原型上,直接spyOn类不会影响实例的方法调用。正确做法是先创建实例,再spyOn这个实例的方法:const server = new ConvertkitServer(); // 模拟返回2个标签 jest.spyOn(server, 'getConvertkitTags').mockResolvedValue([ { id: 'tag1', name: '标签1' }, { id: 'tag2', name: '标签2' } ]); // 执行测试 await server.addSubscriberTags();getConvertkitTags是箭头函数
箭头函数作为对象方法时,是不可配置的属性,jest无法替换它的实现。这种情况需要把箭头函数改成普通函数:// 原错误写法(箭头函数) const ConvertkitServer = { getConvertkitTags: async () => { /* ... */ } }; // 改成普通函数 const ConvertkitServer = { async getConvertkitTags() { /* ... */ } };模块导出的对象被重新引用
如果你的代码里是重新赋值了ConvertkitServer对象,比如const server = {...ConvertkitServer},spyOn原对象的方法不会生效,因为新对象的方法是独立的引用。需要确保测试中使用的是同一个对象引用。
问题2:监听fetch的调用参数(无需Mock,保留真实请求)
可以用jest.spyOn包装原始fetch实现,既保留真实请求逻辑,又能捕获调用参数:
针对node-fetch的情况:
const nodeFetch = require('node-fetch'); // Spy on node-fetch的默认导出,保留原始实现 const fetchSpy = jest.spyOn(nodeFetch, 'default').mockImplementation(nodeFetch.default); // 执行测试代码 await server.addSubscriberTags(); // 检查调用参数 expect(fetchSpy).toHaveBeenCalledWith( // 验证URL匹配 expect.stringContaining('api.convertkit.com/v3/tags'), // 验证请求配置 expect.objectContaining({ method: 'POST', headers: expect.objectContaining({ 'Authorization': expect.stringContaining('Bearer') }), body: expect.stringContaining('subscriber_id=') }) ); // 测试结束后还原fetch fetchSpy.mockRestore();
针对全局fetch的情况(如果你的代码中使用global.fetch):
const originalFetch = global.fetch; const fetchSpy = jest.spyOn(global, 'fetch').mockImplementation(originalFetch); // 执行测试 await server.addSubscriberTags(); // 检查参数 expect(fetchSpy).toHaveBeenCalledTimes(1); // 验证调用次数 const [url, options] = fetchSpy.mock.calls[0]; // 获取第一次调用的参数 expect(url).toBe('https://api.convertkit.com/v3/tags/assign'); expect(options.method).toBe('POST'); // 还原 fetchSpy.mockRestore();
另外,如果你已经在用MSW拦截请求,也可以在MSW的handler里直接捕获请求参数:
import { rest } from 'msw'; // 在handler中记录请求参数 let capturedRequest; rest.post('https://api.convertkit.com/v3/tags/assign', (req, res, ctx) => { capturedRequest = req; return res(ctx.json({ success: true })); }); // 执行测试后检查 expect(capturedRequest.url).toBe('https://api.convertkit.com/v3/tags/assign'); expect(await capturedRequest.json()).toEqual({ subscriber_id: '123', tag_ids: ['tag1', 'tag2'] });
内容的提问来源于stack exchange,提问作者Andrew Connell
相关产品推荐
相关产品推荐

