Jest中无法Mock第三方库JSEncrypt问题求助
问题:Jest Mock JSEncrypt库失败,报错"encrypt.setPublicKey is not a function"
以下是基于JSEncrypt实现RSA公钥加密的密码加密函数:
// encryptPassword.js import { JSEncrypt } from 'jsencrypt'; export const encryptPassword = (pwd, rsaPublicKey) => { let retVal = pwd; try { const encrypt = new JSEncrypt(); encrypt.setPublicKey(rsaPublicKey); const encryptedValue = encrypt.encrypt(pwd); retVal = !encryptedValue ? pwd : encryptedValue; } catch (error) { console.log('in catch ',error) //Exception is occurred while doing password encryption } return retVal; };
尝试用Jest编写单元测试时,无法正确Mock JSEncrypt库,测试始终进入catch代码块,报错信息为encrypt.setPublicKey is not a function,测试代码如下:
// encryptPassword.test.js import { encryptPassword } from '../encryptPassword'; import { JSEncrypt } from 'jsencrypt'; // Mocking JSEncrypt module jest.mock('jsencrypt', () => { const mockJSEncryptInstance = { setPublicKey: jest.fn(), encrypt: jest.fn().mockImplementation((pwd) => { // Simulating encryption (just returning the input for simplicity) return pwd; }), }; const mockJSEncrypt = jest.fn().mockImplementation(() => { return mockJSEncryptInstance; }); return { JSEncrypt: mockJSEncrypt }; }); describe('encryptPassword function', () => { beforeEach(() => { // Clear all instances and calls to constructor and all methods JSEncrypt.mockClear(); }); test('should encrypt password successfully', () => { const pwd = 'password123'; const rsaPublicKey = 'publicKey'; const encryptedPwd = encryptPassword(pwd, rsaPublicKey); // Expect the encrypted password to be different from the original password //expect(encryptedPwd).not.toBe(pwd); }); });
解决方案
问题根源在于你的Mock实现使用了共享的实例对象,导致模块导出的Mock逻辑与实际代码的调用方式不匹配。修正后的测试代码如下:
import { encryptPassword } from '../encryptPassword'; import { JSEncrypt } from 'jsencrypt'; // 正确Mock JSEncrypt模块 jest.mock('jsencrypt', () => { // 为每个new操作生成独立的实例,确保每个实例都拥有自己的方法 return { JSEncrypt: jest.fn().mockImplementation(() => ({ setPublicKey: jest.fn(), encrypt: jest.fn((pwd) => `encrypted_${pwd}`) })) }; }); describe('encryptPassword function', () => { beforeEach(() => { JSEncrypt.mockClear(); // 清除实例方法的调用记录 const mockInstance = JSEncrypt.mock.instances[0]; if (mockInstance) { mockInstance.setPublicKey.mockClear(); mockInstance.encrypt.mockClear(); } }); test('should encrypt password successfully', () => { const pwd = 'password123'; const rsaPublicKey = 'publicKey'; const encryptedPwd = encryptPassword(pwd, rsaPublicKey); // 验证构造函数调用 expect(JSEncrypt).toHaveBeenCalledTimes(1); // 获取Mock实例并验证方法调用 const mockInstance = JSEncrypt.mock.instances[0]; expect(mockInstance.setPublicKey).toHaveBeenCalledWith(rsaPublicKey); expect(mockInstance.encrypt).toHaveBeenCalledWith(pwd); expect(encryptedPwd).toBe(`encrypted_${pwd}`); }); test('should return original password when encryption returns null', () => { const pwd = 'password123'; const rsaPublicKey = 'publicKey'; const mockInstance = JSEncrypt.mock.instances[0]; mockInstance.encrypt.mockReturnValue(null); const encryptedPwd = encryptPassword(pwd, rsaPublicKey); expect(encryptedPwd).toBe(pwd); }); test('should return original password when encryption throws error', () => { const pwd = 'password123'; const rsaPublicKey = 'publicKey'; const mockInstance = JSEncrypt.mock.instances[0]; mockInstance.encrypt.mockImplementation(() => { throw new Error('Encryption failed'); }); const encryptedPwd = encryptPassword(pwd, rsaPublicKey); expect(encryptedPwd).toBe(pwd); }); });
核心修正说明
- 移除共享的
mockJSEncryptInstance,改为在mockImplementation中直接返回带方法的对象,确保每次new JSEncrypt()都生成独立实例,避免状态污染 - 确保Mock的实例方法与原库的调用方式完全匹配,解决
setPublicKey is not a function的报错 - 补充多场景测试,覆盖加密成功、加密返回空值、加密抛出异常三种情况,确保函数逻辑符合预期
内容的提问来源于stack exchange,提问作者MLK
相关产品推荐
相关产品推荐

