-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Don't stuff jsdom globals onto the Node global
A common antipattern we see when people use jsdom is copying globals from a jsdom window
onto the Node.js global, and then trying to run the code—intended for a browser—inside Node.js. This is very bad and you should not do it. It runs code intended for the web browser in some kind of hybrid franken-environment polluted with a ton of globals that don't make sense there, and loses all benefits of isolating your code into a jsdom window.
Instead, you should run the code inside the jsdom context itself. There are a variety of ways to do this. If you need to run a string of code, you can do
const { window } = new JSDOM(``, { runScripts: "outside-only" });
window.eval(`
// This code executes in the jsdom global scope
globalVariable = typeof XMLHttpRequest === "function";
`);
assert(window.globalVariable === true);
If you want to load a file into jsdom, you can do it by creating a script element:
const { window } = new JSDOM(``, { runScripts: "dangerously" });
const myLibrary = fs.readFileSync("../../whatever.js", { encoding: "utf-8" });
const scriptEl = window.document.createElement("script");
scriptEl.textContent = myLibrary;
window.document.body.appendChild(scriptEl);
Here's an example of how to load a library into a separate jsdom window created for each test:
const { JSDOM } = require("jsdom");
const myLibrary = fs.readFileSync("../../whatever.js", { encoding: "utf-8" });
let window;
beforeEach(() => {
window = (new JSDOM(``, { runScripts: "dangerously" })).window;
// Execute my library by inserting a <script> tag containing it.
const scriptEl = window.document.createElement("script");
scriptEl.textContent = myLibrary;
window.document.body.appendChild(scriptEl);
});
it("should do the right thing", () => {
assert.equal(window.myLibrary.doThing("foo"), "bar");
});
This way, each test creates an entirely new window and document. This contrasts with the very bad approach of mashing various properties of window
onto the Node.js global
, which causes all these properties to be shared not only across all your tests, but across your entire Node.js process.