React集成测试调用Cognito报错:Native crypto模块无法获取安全随机数
解决方案
方案1:全局注入Crypto Polyfill(适合需要真实调用Cognito接口的集成测试)
这个方案是给Node测试环境补全浏览器端的crypto全局对象,完全适配Cognito的源码判断逻辑。
- 第一步:在测试初始化的最前置位置执行polyfill代码,比如Jest的
setupFiles/setupFilesAfterEnv配置指向的文件,Vitest同理,不要在单测用例内部才执行,此时Cognito依赖已经加载完成,配置不会生效。 - 第二步:使用如下正确的polyfill代码:
// 先引入Node原生crypto模块 import * as nodeCrypto from 'crypto'; // 兼容不同运行时的全局指向 const globalAsAny = global as any; // 同时挂载到所有可能被Cognito识别的全局对象上 globalAsAny.crypto = nodeCrypto; globalAsAny.window = globalAsAny.window || {}; globalAsAny.window.crypto = nodeCrypto; globalAsAny.self = globalAsAny.self || globalAsAny; // Node 19以下版本原生crypto没有getRandomValues方法,手动补全 if (!nodeCrypto.getRandomValues) { nodeCrypto.getRandomValues = (typedArray: Uint8Array | Uint16Array | Uint32Array) => { const randomBytes = nodeCrypto.randomBytes(typedArray.length); for (let i = 0; i < typedArray.length; i++) { typedArray[i] = randomBytes[i]; } return typedArray; }; }
方案2:Mock Cognito依赖(适合不需要真实调用Cognito接口的测试)
如果你的测试不需要真实请求AWS Cognito服务,可以直接mock对应的方法,彻底规避环境依赖问题,以Jest为例:
jest.mock('amazon-cognito-identity-js', () => { return { CognitoUser: jest.fn().mockImplementation(() => { return { authenticateUser: jest.fn((authDetails, callbacks) => { // 模拟成功返回,按需调整返回值 callbacks.onSuccess({ getIdToken: () => ({ getJwtToken: () => 'mock-jwt-token' }) }); }) }; }), CognitoUserPool: jest.fn(), AuthenticationDetails: jest.fn() }; });
之前方案不生效的原因
- 没有提前引入Node原生的crypto模块,直接赋值时
crypto本身就是undefined - 挂载时机过晚,Cognito的工具函数加载时,全局crypto还没有被赋值
- 只挂载到了单个全局对象上,部分打包配置或者运行时环境下Cognito识别的全局指向不是你挂载的对象
内容的提问来源于stack exchange,提问作者Przemek Lach
相关产品推荐
相关产品推荐

