Creating a jest test like:
test("btoa", () => { expect(btoa("aaa")).toStrictEqual("YWFh"); });
fails with
ReferenceError: btoa is not defined
however, node
does define btoa
as of node 16, and so the following:
console.log(bota("aaa"))
correctly outputs YWFh
.
How can I configure jest to get this test to pass? Clearly something is happening in the jest test runner to not execute in the current node environment, or otherwise is stripping specific built-ins, only I can’t seem to find any documentation on how to debug or adjust this.
Update
There are work arounds by writing the encoding manually in “pure js” or depending on something that’s similar, but I’m particularly interested in why the jest execution ending is failing to find built-ins that seem to be present in other environments.
This also works fine in other testing frameworks like mocha, so it’s clearly related to the jest runner in particular.
Advertisement
Answer
Update
After much searching and head scratching as to why btoa/atob
are available in node but NOT available in jest running in node, I finally figured it out. Jest runs all tests inside a vm
, which is an isolated sandbox environment. The btoa/atob
methods are not automatically exposed on the global
object inside of a VM. Best explained by example:
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
.
Original answer
The root of your problem is the fact that NodeJS and web browsers have different APIs. For example, I get this deprecation notice when I try to use btoa
in my node application.
The first part of the solution is that you need to provide your own atob
/btoa
methods for use in NodeJs (see examples here). Then you need to make these available using jest’s globalSetup
config:
/** 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');
If you don’t feel comfortable doing this yourself, there are libraries and tools out there that do it for you (jsdom, phantomjs, testing-library). These libraries essentially replicate the browser APIs in a node environment for doing things like running tests, server-side rendering, etc. I recommend reading about testing web frameworks for code examples and techniques.