Search code examples
javascripttestingmocha.jsglobaljsdom

JSDOM script element being overwritten in Mocha


I have two nearly identical JS files that I cannot change that I want to add tests for.

file 1:

const url = "https://file-1.js";

(function () {
  "use strict";
  window.onload = () => {
    const script = document.createElement("script");
    script.src = url;
    document.head.appendChild(script);
  };
})();

file 2:

const url = "https://file-2.js";

(function () {
  "use strict";
  window.onload = () => {
    const script = document.createElement("script");
    script.src = url;
    document.head.appendChild(script);
  };
})();

Then test 1:

const chai = require("chai");
const { expect } = chai;
const jsdom = require("jsdom");
const { JSDOM } = jsdom;

const { window } = new JSDOM(`<!DOCTYPE html><head></head><p>Fake document</p>`, {
  resources: "usable",
});

global.document = window.document;
global.window = window;

const myFile = require("../src/myFile");

describe("Test 1", function () {
    it("Loads a file from an external source", function (done) {
      console.log(window.document.head.children); // See what's going on
      expect(window.document.head.children[0].src).to.equal("https://file-1.js");
    });
});

test 2:

const chai = require("chai");
const { expect } = chai;
const jsdom = require("jsdom");
const { JSDOM } = jsdom;

const myFile2 = require("../src/myFile2");

describe("Test 2", function () {
    it("Loads a file from an external source", function (done) {
      console.log(window.document.head.children); // See what's going on
      expect(window.document.head.children[0].src).to.equal("https://file-2.js");
    });
});

Test 2 passes but test 1 fails. The value of both console.logs is:

HTMLCollection { '0': HTMLScriptElement {} }

And console.log(window.document.head.children[0].src) produces:

https://file-2.js

I'd expect there to be two children in window.document.head but there's only 1, per the above. It appears Mocha is loading all the required files in all tests first, and the appendChild in the 2nd file is overwriting the value from the first.

Is there a way around this? I experimented with done() or moving around where the require is called but it results in the same outcome.


Solution

  • After reviewing the repo in the answer from Christian I realized I needed to fire the window.onload event after importing each file.

    Also, I do not want to run ('dangerously') the scripts, just ensure that they are appended a document as a script element. That's all.

    The following works:

    const chai = require("chai");
    const { expect } = chai;
    const jsdom = require("jsdom");
    const { JSDOM } = jsdom;
    
    const { window } = new JSDOM(`<!DOCTYPE html><head></head><p>Fake document</p>`, {
      resources: "usable",
    });
    
    global.document = window.document;
    global.window = window;
    
    const downloaderPopup = require("../src/MyFile");
    window.dispatchEvent(new window.Event("load"));
    const downloaderMain = require("../src/MyFile2");
    window.dispatchEvent(new window.Event("load"));
    
    describe("Both tests", function () {
      describe("Test 1", function () {
        it("Dynamocally loads file 1", function () {
          expect(window.document.head.children[1].src).to.equal("https://file-1.js");
        });
      });
      describe("Test 2", function () {
        it("Dynamically loads file 2", function () {
          expect(window.document.head.children[0].src).to.equal("https://file-2.js");
        });
      });
    });