TypeScript环境下Jest spyOn监听SendGrid send函数失效问题
解决Jest测试SendGrid send函数调用问题(TypeScript环境)
你的问题核心有两个:一是测试环境缺少SendGrid API key导致的Unauthorized错误,二是jest.spyOn没有正确监听send函数的调用。下面是具体的修复方案:
1. 用jest.mock替代spyOn模拟整个SendGrid模块
直接使用jest.spyOn可能因为模块加载顺序问题,无法覆盖到Mutation中导入的sgMail实例。更好的方式是直接模拟整个@sendgrid/mail模块,既能避免真实API调用,也能准确监听函数调用。
修改测试代码如下:
import { gql } from 'graphql-tag'; import { client } from '../your-client-path'; // 替换为你的client实际路径 // 模拟整个@sendgrid/mail模块,替换所有方法为jest mock函数 jest.mock('@sendgrid/mail', () => ({ setApiKey: jest.fn(), // 模拟API key设置函数,避免真实校验 send: jest.fn().mockResolvedValue('Success') // 模拟发送函数,返回成功Promise })); // 必须在mock之后导入Mutation模块,确保它使用的是模拟版sgMail import { Mutation } from '../your-mutation-path'; // 替换为你的Mutation文件实际路径 const signUpUserMutation = gql` mutation($data: ValidationInput) { signUpUser (data: $data) { id email } } `; it('should send a registration email, with a link containing the registration id', async () => { // 从模拟模块中获取send函数的mock实例 const { send } = require('@sendgrid/mail'); const variables = { data: { email: "test@test.de", password: "anyPassword" } }; await client.mutate({ mutation: signUpUserMutation, variables }); // 断言send函数被调用 expect(send).toHaveBeenCalled(); // 还可以进一步校验调用参数是否符合预期 expect(send).toHaveBeenCalledWith(expect.objectContaining({ to: "test@test.de", subject: "Account validation" })); });
2. 为什么原来的spyOn不生效?
在你的原始代码中,测试文件导入Mutation模块时,Mutation已经加载并执行了sgMail.setApiKey,此时它使用的是真实sgMail实例的引用。之后再用spyOn去监听,无法覆盖这个已经被引用的函数。而jest.mock会在模块加载前替换整个模块,确保Mutation从一开始就使用模拟版本。
3. 解决Unauthorized错误
通过完全模拟@sendgrid/mail模块,真实的setApiKey和send逻辑都不会被执行,自然不会因为缺少API key抛出Unauthorized错误。
额外提示:保留部分真实逻辑的场景
如果你希望保留setApiKey的真实逻辑,只模拟send函数,可以修改mock方式:
jest.mock('@sendgrid/mail', () => { const originalModule = jest.requireActual('@sendgrid/mail'); return { ...originalModule, send: jest.fn().mockResolvedValue('Success') }; });
这种情况下需要在测试环境中设置MAIL_API_KEY(比如通过dotenv加载测试环境变量),否则setApiKey仍可能触发错误,因此更推荐第一种完全模拟的方案。
内容的提问来源于stack exchange,提问作者lorenzbayr
相关产品推荐
相关产品推荐

