在反应中使用 Jest 运行单元测试时,window.crypto
API 会导致问题。我还没有找到一种crypto
在不安装其他软件包的情况下合并到 Jest 中的方法,这是我无法做到的。因此,在不使用另一个 npm 包的情况下,有一种方法可以测试使用的函数:crypto.getRandomValues()
在其中不会使 Jest 崩溃?感谢任何链接、建议或提示
13 回答
这应该这样做。crypto
使用以下代码全局设置属性。这将允许 Jest 访问window.crypto
并且不会引起任何问题。
const crypto = require('crypto');
Object.defineProperty(global.self, 'crypto', {
value: {
getRandomValues: arr => crypto.randomBytes(arr.length)
}
});
像@RwwL 一样,接受的答案对我不起作用。我发现这个库中使用的 polyfill 确实有效:commit with polyfill
//setupTests.tsx
const nodeCrypto = require('crypto');
window.crypto = {
getRandomValues: function (buffer) {
return nodeCrypto.randomFillSync(buffer);
}
};
//jest.config.js
module.exports = {
//...
setupFilesAfterEnv: ["<rootDir>/src/setupTests.tsx"],
};
从节点 15.x 开始,您可以使用crypto.webcrypto
例如。
import crypto from "crypto";
Object.defineProperty(global.self, "crypto", {
value: {
subtle: crypto.webcrypto.subtle,
},
});
我正在使用 vue-jest,对我有用的是jest.config.js
文件中的以下配置:
module.exports = {
...
setupFiles: [
'<rootDir>/tests/settings/jest.crypto-setup.js',
],
};
并在jest.crypto-setup.js
:
global.crypto = {
getRandomValues: (arr) => require('crypto').randomBytes(arr.length)
};
直接添加getRandomValues
函数定义module.exports
不起作用,因为globals
对象必须是 json-serializable (如在此处指定:https ://jestjs.io/docs/configuration#globals-object )。
对于 nodeJS + typescript,只需使用global
而不是global.self
import crypto from 'crypto'
Object.defineProperty(global, 'crypto', {
value: {
getRandomValues: (arr:any) => crypto.randomBytes(arr.length)
}
});
来自 AIVeligs 的答案:
因为我在 Jest 中使用“节点”环境,所以我不得不使用
module.exports = {
preset: "ts-jest",
testEnvironment: "node",
globals: {
crypto: {
getRandomValues: (arr) => require("crypto").randomBytes(arr.length),
},
},
};
为您的 jest 环境添加crypto
全局,就好像它在浏览器中一样。您的 jest.config.js 应该如下所示:
const {defaults} = require('jest-config');
module.exports = {
globals: {
...defaults.globals,
crypto: require('crypto')
}
};
当前答案中的 polyfill 是不完整的,因为Crypto.getRandomValues()
它会就地修改其参数并返回它。const foo = new Int8Array(8); console.log(foo === crypto.getRandomValues(foo))
您可以通过在浏览器控制台中运行类似的东西来验证这一点,它将打印true
.
getRandomValues()
也不接受 aArray
作为它的参数,它只接受整数TypedArray
s。Node.js 的crypto.randomBytes()
函数不适合这个 polyfill,因为它输出原始字节,而getRandomValues()
可以接受元素高达 32 位的有符号整数数组。如果您crypto.getRandomValues(new Int32Array(8))
在浏览器中尝试,您可能会看到类似[ 304988465, -2059294531, 229644318, 2114525000, -1735257198, -1757724709, -52939542, 486981698 ]
. 但是,如果您node -e 'console.log([...require("crypto").randomBytes(8)])'
在命令行上尝试,您可能会看到[ 155, 124, 189, 86, 25, 44, 167, 159 ]
. 显然,这些是不等价的,如果使用后者进行测试,您的被测组件可能不会像预期的那样运行。
webcrypto
最新版本的 Node.js 用模块解决了这个问题(应该是设置的问题globalThis.crypto = require('crypto').webcrypto
)。如果您使用的是旧版本的 Node(v14 或更低版本),您可能会更幸运地使用crypto.randomFillSync()
,它应该可以用作替代品,getRandomValues()
因为它会修改传递的缓冲区/TypedArray
就地。
在您的 Jest 设置文件中(不能通过globals
配置进行设置,因为它只允许与 JSON 兼容的值):
const { randomFillSync } = require('crypto')
Object.defineProperty(globalThis, 'crypto', {
value: { getRandomValues: randomFillSync },
})
在使用 Jest 进行测试期间,默认crypto
依赖项对我不起作用。
相反,我使用了@peculiar/webcrypto
图书馆:
yarn add -D @peculiar/webcrypto
然后在您的 Jest 设置文件中,添加以下内容:
import { Crypto } from "@peculiar/webcrypto";
window.crypto = new Crypto();
const crypto = require('crypto');
global.crypto = crypto;
我在使用 uuid 生成器的 lib 的 Jest 测试中遇到了这个问题。在开玩笑的测试设置中,我模拟了这个:
Object.defineProperty(global.self, 'crypto', {
value: {
getRandomValues: arr => arr
},
});
dspacejs 的答案几乎对我有用,除了我和Mozgor有同样的问题。我收到一条错误消息,说 window.crypto 是只读的。您可以使用 Object.assign 而不是直接尝试覆盖它。
yarn add -D @peculiar/webcrypto
使用或 安装 @peculiar/webcryptonpm i --save-dev @peculiar/webcrypto
然后将以下内容添加到您的 Jest 设置文件中:
import { Crypto } from "@peculiar/webcrypto";
Object.assign(window, {
crypto: new Crypto(),
})
在默认配置中,Jest 假设您正在测试 Node.js 环境。但是,当您使用对象的方法遇到错误时window
,您可能正在制作一个 Web 应用程序。
所以如果你正在制作一个网络应用程序,你应该使用“jsdom”作为你的“testEnvironment”。为此,请插入"testEnvironment": "jsdom",
您的 Jest 配置。
如果您维护一个“jest.config.js”文件,则将其添加如下:
module.exports = {
...
"testEnvironment": "jsdom",
...
};
或者,如果像我一样,您将 Jest 配置保存在“package.json”中:
{
...,
"jest": {
...,
"testEnvironment": "jsdom",
...
},
...
}