I've created a very simple page that just displays a single message, as I'm trying to test out the JSDOM to use document
. However, I'm getting the below error.
First of all, I have seen the countless examples online, in addition to the questions posted on Stack Overflow, but I have not been able to resolve even the simplest example. As a side-note, I am new to Javascript.
My code so far is as follows:
Root Directory
--->index.html
--->module.js
--->package-lock.json
--->package.json
--->test
--->--->messageTest.js
The different files are as follows:
index.html
<!doctype html>
<head>
<meta charset="utf-8">
<title>jsdom Unit Test</title>
</head>
<body>
<p id='msg'>Hello, World!</p>
<script src="module.js"></script>
</body>
</html>
module.js
function updateMsg(newMsg) {
document.getElementById('msg').innerHTML = newMsg;
}
updateMsg("Changing message");
module.exports = updateMsg;
package.json
{
"name": "message-example",
"version": "1.0.0",
"description": "Testing how to use the JSDOM",
"main": "module.js",
"scripts": {
"test": "mocha"
},
"author": "",
"license": "ISC",
"devDependencies": {
"chai": "^4.2.0",
"jsdom": "^15.1.1",
"mocha": "^6.2.0",
"mocha-jsdom": "^2.0.0",
"rewire": "^4.0.1",
"sinon": "^7.3.2"
}
}
messageTest.js
var updateMsg = require('../module.js');
const expect = require('chai').expect
const { JSDOM } = require('jsdom');
describe('updateMsg', function () {
before(function() {
return JSDOM.fromFile('index.html')
.then((dom) => {
global.window = dom.window;
global.document = window.document;
});
})
it ('updates the innerHTML of element with id "msg"', function () {
expect(document.getElementById('msg').innerHTML).to.equal('Hello, World!');
updateMsg('The new msg!');
expect(document.getElementById('msg').innerHTML).to.equal('The new msg!');
});
});
If I run the test with npm test
, I get the ReferenceError: document is not defined
error at the document.getElementByID...
step in the module.js file.
If I remove the updateMsg("Changing message")
, my test obviously runs fine.
I've created a very simple page that just displays a single message, as I'm trying to test out the JSDOM to use document
. However, I'm getting the below error.
First of all, I have seen the countless examples online, in addition to the questions posted on Stack Overflow, but I have not been able to resolve even the simplest example. As a side-note, I am new to Javascript.
My code so far is as follows:
Root Directory
--->index.html
--->module.js
--->package-lock.json
--->package.json
--->test
--->--->messageTest.js
The different files are as follows:
index.html
<!doctype html>
<head>
<meta charset="utf-8">
<title>jsdom Unit Test</title>
</head>
<body>
<p id='msg'>Hello, World!</p>
<script src="module.js"></script>
</body>
</html>
module.js
function updateMsg(newMsg) {
document.getElementById('msg').innerHTML = newMsg;
}
updateMsg("Changing message");
module.exports = updateMsg;
package.json
{
"name": "message-example",
"version": "1.0.0",
"description": "Testing how to use the JSDOM",
"main": "module.js",
"scripts": {
"test": "mocha"
},
"author": "",
"license": "ISC",
"devDependencies": {
"chai": "^4.2.0",
"jsdom": "^15.1.1",
"mocha": "^6.2.0",
"mocha-jsdom": "^2.0.0",
"rewire": "^4.0.1",
"sinon": "^7.3.2"
}
}
messageTest.js
var updateMsg = require('../module.js');
const expect = require('chai').expect
const { JSDOM } = require('jsdom');
describe('updateMsg', function () {
before(function() {
return JSDOM.fromFile('index.html')
.then((dom) => {
global.window = dom.window;
global.document = window.document;
});
})
it ('updates the innerHTML of element with id "msg"', function () {
expect(document.getElementById('msg').innerHTML).to.equal('Hello, World!');
updateMsg('The new msg!');
expect(document.getElementById('msg').innerHTML).to.equal('The new msg!');
});
});
If I run the test with npm test
, I get the ReferenceError: document is not defined
error at the document.getElementByID...
step in the module.js file.
If I remove the updateMsg("Changing message")
, my test obviously runs fine.
-
Your code seems to run well, it display the text "Changing message" in the <p/> tag, check fiddle: jsfiddle/7k96oeuw And, its not
document.getElementByID
like you describe it, isdocument.getElementById
– JC Hernández Commented Jul 19, 2019 at 13:57 - Possible duplicate of stackoverflow./a/45961549/2444210 – IceMetalPunk Commented Jul 19, 2019 at 14:00
- Thanks for the catch. My code runs fine indeed (on a physical browser) but when I run the test where the browser needs to be simulated, I get that the document element is not found. This should be simulated with JSDOM (as far as I understand), but I'm not sure why it doesn't work. – Adam Commented Jul 19, 2019 at 14:00
1 Answer
Reset to default 2You have a couple of issues in that example:
You're mixing jsdom window and global node context. Avoid assigning to
global
(because that's making it easier to make that mistake), don'trequire()
scripts that you want to run in your virtual window.jsdom prevents running on-page scripts by default, so your module.js is neither loaded nor executed. You'll have to provide
{ resources: "usable", runScripts: "outside-only" }
parameters to fix that (make sure you read about the security implications in the jsdom README).You're not waiting for the
load
event, so your test is run before jsdom has a chance to load the script.
Working code would look something like this:
const expect = require("chai").expect;
const { JSDOM } = require("jsdom");
describe("updateMsg", function() {
let jsdom;
before(async function() {
jsdom = await JSDOM.fromFile("index.html", {
resources: "usable",
runScripts: "dangerously"
});
await new Promise(resolve =>
jsdom.window.addEventListener("load", resolve)
);
});
it('updates the innerHTML of element with id "msg"', function() {
expect(jsdom.window.document.getElementById("msg").innerHTML).to.equal(
"Hello, World!"
);
jsdom.window.updateMsg("The new msg!");
expect(jsdom.window.document.getElementById("msg").innerHTML).to.equal(
"The new msg!"
);
});
});
You'll also need to remove the module line from module.js, module
doesn't exist in the browser.