You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 20:27:05