29

在反应中使用 Jest 运行单元测试时,window.cryptoAPI 会导致问题。我还没有找到一种crypto在不安装其他软件包的情况下合并到 Jest 中的方法,这是我无法做到的。因此,在不使用另一个 npm 包的情况下,有一种方法可以测试使用的函数:crypto.getRandomValues()在其中不会使 Jest 崩溃?感谢任何链接、建议或提示

4

13 回答 13

32

这应该这样做。crypto使用以下代码全局设置属性。这将允许 Jest 访问window.crypto并且不会引起任何问题。

const crypto = require('crypto');

Object.defineProperty(global.self, 'crypto', {
  value: {
    getRandomValues: arr => crypto.randomBytes(arr.length)
  }
});
于 2018-10-02T16:13:51.990 回答
17

像@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"],
};
于 2020-06-26T19:18:24.400 回答
7

从节点 15.x 开始,您可以使用crypto.webcrypto

例如。

import crypto from "crypto";

Object.defineProperty(global.self, "crypto", {
  value: {
    subtle: crypto.webcrypto.subtle,
  },
});
于 2021-03-18T08:12:12.613 回答
3

我正在使用 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 )。

于 2021-04-30T10:17:27.603 回答
3

对于 nodeJS + typescript,只需使用global而不是global.self

import crypto from 'crypto'

Object.defineProperty(global, 'crypto', {
  value: {
    getRandomValues: (arr:any) => crypto.randomBytes(arr.length)
  }
});
于 2020-09-05T01:56:14.363 回答
3

来自 AIVeligs 的答案:

因为我在 Jest 中使用“节点”环境,所以我不得不使用

module.exports = {
  preset: "ts-jest",
  testEnvironment: "node",
  globals: {
    crypto: {
      getRandomValues: (arr) => require("crypto").randomBytes(arr.length),
    },
  },
};
于 2021-04-22T14:39:40.800 回答
2

为您的 jest 环境添加crypto全局,就好像它在浏览器中一样。您的 jest.config.js 应该如下所示:

const {defaults} = require('jest-config');

module.exports = {
  globals: {
    ...defaults.globals,
    crypto: require('crypto')
  }
};

参考:https ://jestjs.io/docs/en/configuration#globals-object

于 2020-06-17T16:03:58.940 回答
2

当前答案中的 polyfill 是不完整的,因为Crypto.getRandomValues()它会就地修改其参数并返回它。const foo = new Int8Array(8); console.log(foo === crypto.getRandomValues(foo))您可以通过在浏览器控制台中运行类似的东西来验证这一点,它将打印true.

getRandomValues()也不接受 aArray作为它的参数,它只接受整数TypedArrays。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 },
})
于 2021-09-15T21:25:57.927 回答
2

在使用 Jest 进行测试期间,默认crypto依赖项对我不起作用。

相反,我使用了@peculiar/webcrypto图书馆:

yarn add -D @peculiar/webcrypto

然后在您的 Jest 设置文件中,添加以下内容:

import { Crypto } from "@peculiar/webcrypto";


window.crypto = new Crypto();
于 2021-08-13T04:14:54.097 回答
1
const crypto = require('crypto');
global.crypto = crypto;
于 2021-02-10T20:28:49.197 回答
1

我在使用 uuid 生成器的 lib 的 Jest 测试中遇到了这个问题。在开玩笑的测试设置中,我模拟了这个:

Object.defineProperty(global.self, 'crypto', {
  value: {
    getRandomValues: arr => arr
  },
});
于 2020-10-16T14:11:38.300 回答
1

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(),
})
于 2022-01-19T16:39:31.893 回答
1

在默认配置中,Jest 假设您正在测试 Node.js 环境。但是,当您使用对象的方法遇到错误时window,您可能正在制作一个 Web 应用程序。

所以如果你正在制作一个网络应用程序,你应该使用“jsdom”作为你的“testEnvironment”。为此,请插入"testEnvironment": "jsdom",您的 Jest 配置。

如果您维护一个“jest.config.js”文件,则将其添加如下:

module.exports = {
   ...
   "testEnvironment": "jsdom",
   ...
};

或者,如果像我一样,您将 Jest 配置保存在“package.json”中:

{
    ...,
    "jest": {
        ...,
        "testEnvironment": "jsdom",
        ...
    },
    ...
}
于 2022-01-27T09:09:46.513 回答