如何使用 Jest 使用加密或 window.msCrypto 来测试函数
How to use Jest to test functions using crypto or window.msCrypto
当 运行 使用 Jest 进行单元测试时,window.crypto
API 会导致问题。我还没有找到在不安装其他软件包的情况下将 crypto
合并到 Jest 中的方法,这是我做不到的。因此,在不使用另一个 npm 包的情况下,有没有一种方法可以测试使用的函数: crypto.getRandomValues()
在其中不会使 Jest 崩溃?感谢任何链接、建议或提示
这应该可以做到。使用以下代码全局设置 crypto
属性。这将允许 Jest 访问 window.crypto
并且不会导致任何问题。
const crypto = require('crypto');
Object.defineProperty(global.self, 'crypto', {
value: {
getRandomValues: arr => crypto.randomBytes(arr.length)
}
});
为您的玩笑环境添加 crypto
全局,就像在浏览器中一样。
您的 jest.config.js 应如下所示:
const {defaults} = require('jest-config');
module.exports = {
globals: {
...defaults.globals,
crypto: require('crypto')
}
};
与@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"],
};
对于 nodeJS + typescript,只需使用 global
而不是 global.self
import crypto from 'crypto'
Object.defineProperty(global, 'crypto', {
value: {
getRandomValues: (arr:any) => crypto.randomBytes(arr.length)
}
});
我在 Angular 8 中遇到这个问题,使用 uuid 生成器对 lib 进行 Jest 测试。在开玩笑的测试设置中,我模拟了这个:
Object.defineProperty(global.self, 'crypto', {
value: {
getRandomValues: arr => arr
},
});
const crypto = require('crypto');
global.crypto = crypto;
因为节点 15.x 你可以使用 crypto.webcrypto
例如
import crypto from "crypto";
Object.defineProperty(global.self, "crypto", {
value: {
subtle: crypto.webcrypto.subtle,
},
});
源自 AIVeligs 答案:
由于我在 Jest 中使用“节点”环境,所以我不得不使用
module.exports = {
preset: "ts-jest",
testEnvironment: "node",
globals: {
crypto: {
getRandomValues: (arr) => require("crypto").randomBytes(arr.length),
},
},
};
我正在使用 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)
};
直接在 module.exports
中添加 getRandomValues
函数定义不起作用,因为 globals
对象必须是 json 可序列化的(正如此处指定的那样:https://jestjs.io/docs/configuration#globals-object).
在使用 Jest 进行测试时,默认的 crypto
依赖项对我不起作用。
相反,我使用了 @peculiar/webcrypto
库:
yarn add -D @peculiar/webcrypto
然后在您的 Jest 安装文件中,只需添加:
import { Crypto } from "@peculiar/webcrypto";
window.crypto = new Crypto();
当前答案中的 polyfill 不完整,因为 Crypto.getRandomValues()
就地修改了它的参数并返回了它。您可以在浏览器控制台中通过 运行 之类的 const foo = new Int8Array(8); console.log(foo === crypto.getRandomValues(foo))
来验证这一点,它将打印 true
.
getRandomValues()
也不接受 Array
作为参数,它只接受整数 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 ]
。显然,这些并不等同,如果使用后者进行测试,您的被测组件可能不会按预期运行。
Node.js 的最新版本使用 webcrypto
module (should be a matter of setting globalThis.crypto = require('crypto').webcrypto
). If you're using an older version of Node (v14 or below) you might have better luck using crypto.randomFillSync()
解决了这个问题,它应该可以用作 getRandomValues()
的替代品,因为它修改了传递的缓冲区/TypedArray
就地.
在你的 Jest 安装文件中(不能通过 globals
configuration 设置,因为它只允许 JSON 兼容的值):
const { randomFillSync } = require('crypto')
Object.defineProperty(globalThis, 'crypto', {
value: { getRandomValues: randomFillSync },
})
dspacejs 的 答案几乎对我有用,除了我遇到了与 Mozgor 相同的问题。我收到一条错误消息,指出 window.crypto 是只读的。您可以使用 Object.assign 而不是直接尝试覆盖它。
用yarn add -D @peculiar/webcrypto
或npm i --save-dev @peculiar/webcrypto
安装@peculiar/webcrypto
然后将以下内容添加到您的 Jest 安装文件中:
import { Crypto } from "@peculiar/webcrypto";
Object.assign(window, {
crypto: new Crypto(),
})
在默认配置中,Jest assumes you are testing a Node.js environment。但是,当您使用 window
对象的方法时遇到错误,您可能正在制作网络应用程序。
所以如果你正在制作一个网络应用程序,你应该使用“jsdom”作为你的“testEnvironment”。 为此,请将 "testEnvironment": "jsdom",
插入到您的 Jest 配置中。
如果您维护一个“jest.config.js”文件,则添加它:
module.exports = {
...
"testEnvironment": "jsdom",
...
};
或者,如果您像我一样将 Jest 配置保存在“package.json”中:
{
...,
"jest": {
...,
"testEnvironment": "jsdom",
...
},
...
}
根据其他人在这里提出的建议,我通过以下方式解决了 window.crypto.subtle.digest 的问题:
Object.defineProperty(global.self, "crypto", {
value: {
getRandomValues: (arr: any) => crypto.randomBytes(arr.length),
subtle: {
digest: (algorithm: string, data: Uint8Array) => {
return new Promise((resolve, reject) =>
resolve(
createHash(algorithm.toLowerCase().replace("-", ""))
.update(data)
.digest()
)
);
},
},
},
});
或者,如果不使用 Typescript:
Object.defineProperty(global.self, "crypto", {
value: {
getRandomValues: (arr) => crypto.randomBytes(arr.length),
subtle: {
digest: (algorithm, data) => {
return new Promise((resolve, reject) =>
resolve(
createHash(algorithm.toLowerCase().replace("-", ""))
.update(data)
.digest()
)
);
},
},
},
});
字符串的重新格式化是可选的。也可以对算法进行硬编码,例如通过声明 'sha256' 或 'sha512' 或类似内容。
当 运行 使用 Jest 进行单元测试时,window.crypto
API 会导致问题。我还没有找到在不安装其他软件包的情况下将 crypto
合并到 Jest 中的方法,这是我做不到的。因此,在不使用另一个 npm 包的情况下,有没有一种方法可以测试使用的函数: crypto.getRandomValues()
在其中不会使 Jest 崩溃?感谢任何链接、建议或提示
这应该可以做到。使用以下代码全局设置 crypto
属性。这将允许 Jest 访问 window.crypto
并且不会导致任何问题。
const crypto = require('crypto');
Object.defineProperty(global.self, 'crypto', {
value: {
getRandomValues: arr => crypto.randomBytes(arr.length)
}
});
为您的玩笑环境添加 crypto
全局,就像在浏览器中一样。
您的 jest.config.js 应如下所示:
const {defaults} = require('jest-config');
module.exports = {
globals: {
...defaults.globals,
crypto: require('crypto')
}
};
与@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"],
};
对于 nodeJS + typescript,只需使用 global
而不是 global.self
import crypto from 'crypto'
Object.defineProperty(global, 'crypto', {
value: {
getRandomValues: (arr:any) => crypto.randomBytes(arr.length)
}
});
我在 Angular 8 中遇到这个问题,使用 uuid 生成器对 lib 进行 Jest 测试。在开玩笑的测试设置中,我模拟了这个:
Object.defineProperty(global.self, 'crypto', {
value: {
getRandomValues: arr => arr
},
});
const crypto = require('crypto');
global.crypto = crypto;
因为节点 15.x 你可以使用 crypto.webcrypto
例如
import crypto from "crypto";
Object.defineProperty(global.self, "crypto", {
value: {
subtle: crypto.webcrypto.subtle,
},
});
源自 AIVeligs 答案:
由于我在 Jest 中使用“节点”环境,所以我不得不使用
module.exports = {
preset: "ts-jest",
testEnvironment: "node",
globals: {
crypto: {
getRandomValues: (arr) => require("crypto").randomBytes(arr.length),
},
},
};
我正在使用 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)
};
直接在 module.exports
中添加 getRandomValues
函数定义不起作用,因为 globals
对象必须是 json 可序列化的(正如此处指定的那样:https://jestjs.io/docs/configuration#globals-object).
在使用 Jest 进行测试时,默认的 crypto
依赖项对我不起作用。
相反,我使用了 @peculiar/webcrypto
库:
yarn add -D @peculiar/webcrypto
然后在您的 Jest 安装文件中,只需添加:
import { Crypto } from "@peculiar/webcrypto";
window.crypto = new Crypto();
当前答案中的 polyfill 不完整,因为 Crypto.getRandomValues()
就地修改了它的参数并返回了它。您可以在浏览器控制台中通过 运行 之类的 const foo = new Int8Array(8); console.log(foo === crypto.getRandomValues(foo))
来验证这一点,它将打印 true
.
getRandomValues()
也不接受 Array
作为参数,它只接受整数 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 ]
。显然,这些并不等同,如果使用后者进行测试,您的被测组件可能不会按预期运行。
Node.js 的最新版本使用 webcrypto
module (should be a matter of setting globalThis.crypto = require('crypto').webcrypto
). If you're using an older version of Node (v14 or below) you might have better luck using crypto.randomFillSync()
解决了这个问题,它应该可以用作 getRandomValues()
的替代品,因为它修改了传递的缓冲区/TypedArray
就地.
在你的 Jest 安装文件中(不能通过 globals
configuration 设置,因为它只允许 JSON 兼容的值):
const { randomFillSync } = require('crypto')
Object.defineProperty(globalThis, 'crypto', {
value: { getRandomValues: randomFillSync },
})
dspacejs 的 答案几乎对我有用,除了我遇到了与 Mozgor 相同的问题。我收到一条错误消息,指出 window.crypto 是只读的。您可以使用 Object.assign 而不是直接尝试覆盖它。
用yarn add -D @peculiar/webcrypto
或npm i --save-dev @peculiar/webcrypto
然后将以下内容添加到您的 Jest 安装文件中:
import { Crypto } from "@peculiar/webcrypto";
Object.assign(window, {
crypto: new Crypto(),
})
在默认配置中,Jest assumes you are testing a Node.js environment。但是,当您使用 window
对象的方法时遇到错误,您可能正在制作网络应用程序。
所以如果你正在制作一个网络应用程序,你应该使用“jsdom”作为你的“testEnvironment”。 为此,请将 "testEnvironment": "jsdom",
插入到您的 Jest 配置中。
如果您维护一个“jest.config.js”文件,则添加它:
module.exports = {
...
"testEnvironment": "jsdom",
...
};
或者,如果您像我一样将 Jest 配置保存在“package.json”中:
{
...,
"jest": {
...,
"testEnvironment": "jsdom",
...
},
...
}
根据其他人在这里提出的建议,我通过以下方式解决了 window.crypto.subtle.digest 的问题:
Object.defineProperty(global.self, "crypto", {
value: {
getRandomValues: (arr: any) => crypto.randomBytes(arr.length),
subtle: {
digest: (algorithm: string, data: Uint8Array) => {
return new Promise((resolve, reject) =>
resolve(
createHash(algorithm.toLowerCase().replace("-", ""))
.update(data)
.digest()
)
);
},
},
},
});
或者,如果不使用 Typescript:
Object.defineProperty(global.self, "crypto", {
value: {
getRandomValues: (arr) => crypto.randomBytes(arr.length),
subtle: {
digest: (algorithm, data) => {
return new Promise((resolve, reject) =>
resolve(
createHash(algorithm.toLowerCase().replace("-", ""))
.update(data)
.digest()
)
);
},
},
},
});
字符串的重新格式化是可选的。也可以对算法进行硬编码,例如通过声明 'sha256' 或 'sha512' 或类似内容。