jest 找不到 `btoa` 和 `atob`

jest is failing to find `bota` and `atob`

创建一个像这样的笑话测试:

test("btoa", () => {
  expect(btoa("aaa")).toStrictEqual("YWFh");
});

失败

ReferenceError: btoa is not defined

但是,node 确实从节点 16 开始定义了 btoa,因此如下:

console.log(bota("aaa"))

正确输出 YWFh.

如何配置 jest 才能通过此测试?很明显,jest 测试运行器中发生了一些事情,无法在当前节点环境中执行,或者正在剥离特定的内置函数,只是我似乎找不到任何关于如何调试或调整它的文档。

更新

通过在“纯 js”中手动编写编码或依赖于类似的东西,有一些解决方法,但我特别感兴趣的是为什么玩笑的执行结束无法找到似乎存在的内置函数在其他环境中。

这在 mocha 等其他测试框架中也能正常工作,因此它显然与 jest runner 尤其相关。

更新

关于 为什么 btoa/atob 在 node 中可用但在 jest 运行 中不可用的大量搜索和挠头之后,我终于想通了出去。 Jest 在 vm 中运行所有测试,这是一个隔离的沙箱环境。 btoa/atob 方法不会自动暴露在 VM 内的 global 对象上。最好用例子来解释:

const vm = require('vm');

// this works outside the vm - but for legacy reasons only
// you shouldn't be doing this in the first place
btoa('aaa'); // -> "YWFh"

const context = vm.createContext({});
const code = 'btoa("aaa")';
vm.runInContext(code, context); //-> Uncaught ReferenceError: btoa is not defined

Note: The answer described below is still the "solution" - you need to define these methods for use in node, and then you need to expose them using jest's globalSetup.


原回答

问题的根源在于 NodeJS 和 Web 浏览器具有不同的 API。例如,当我尝试在我的节点应用程序中使用 btoa 时收到此弃用通知。

解决方案的第一部分是您需要提供自己的 atob/btoa 方法以在 NodeJs 中使用(参见 examples here). Then you need to make these available using jest's globalSetup 配置:

/** Encodes a string as base64 format */
global.btoa = (str: string) => Buffer.from(str, 'binary').toString('base64');

/** Decodes a base64 encoded string */
global.atob = (str: string) => Buffer.from(str, 'base64').toString('binary');

如果您觉得自己做这件事不自在,可以使用一些库和工具为您做这件事(jsdom、phantomjs、testing-library)。这些库本质上是在节点环境中复制浏览器 API,以执行 运行 测试、server-side 渲染等操作。我建议阅读 testing web frameworks 以获取代码示例和技术。