Note: This question is not a duplicate of other existing questions because this question does not use jsdom.env()
function call which older version of JSDOM use.
File bar.js
:
console.log('bar says: hello')
File foo.js
:
var jsdom = require('jsdom')
var html = '<!DOCTYPE html><head><script src="bar.js"></script></head><body><div>Foo</div></body>'
var window = new jsdom.JSDOM(html).window
window.onload = function () {
console.log('window loaded')
}
When I run foo.js
, I get this output.
$ node foo.js
window loaded
Why did bar says: hello
output did not come? It looks like bar.js
was not loaded. How can I make jsdom
load the file in the script
tag?
[EDIT/SOLUTION]: Problem solved after following a suggestion in the answer by Quentin. This code works:
var jsdom = require('jsdom')
var html = '<!DOCTYPE html><head><script src="bar.js"></script></head><body><div>Foo</div></body>'
var window = new jsdom.JSDOM(html, { runScripts: "dangerously", resources: "usable" }).window
window.onload = function () {
console.log('window loaded')
}
Note: This question is not a duplicate of other existing questions because this question does not use jsdom.env()
function call which older version of JSDOM use.
File bar.js
:
console.log('bar says: hello')
File foo.js
:
var jsdom = require('jsdom')
var html = '<!DOCTYPE html><head><script src="bar.js"></script></head><body><div>Foo</div></body>'
var window = new jsdom.JSDOM(html).window
window.onload = function () {
console.log('window loaded')
}
When I run foo.js
, I get this output.
$ node foo.js
window loaded
Why did bar says: hello
output did not come? It looks like bar.js
was not loaded. How can I make jsdom
load the file in the script
tag?
[EDIT/SOLUTION]: Problem solved after following a suggestion in the answer by Quentin. This code works:
var jsdom = require('jsdom')
var html = '<!DOCTYPE html><head><script src="bar.js"></script></head><body><div>Foo</div></body>'
var window = new jsdom.JSDOM(html, { runScripts: "dangerously", resources: "usable" }).window
window.onload = function () {
console.log('window loaded')
}
Share
Improve this question
edited Sep 1, 2020 at 20:35
Hugolpz
18.3k28 gold badges105 silver badges191 bronze badges
asked Oct 30, 2018 at 17:08
Lone LearnerLone Learner
20.6k25 gold badges114 silver badges218 bronze badges
4
|
3 Answers
Reset to default 12Go to the JSDOM homepage.
Skim the headings until you find one marked Executing scripts
To enable executing scripts inside the page, you can use the
runScripts: "dangerously"
option:const dom = new JSDOM(`<body> <script>document.body.appendChild(document.createElement("hr"));</script> </body>`, { runScripts: "dangerously" }); // The script will be executed and modify the DOM: dom.window.document.body.children.length === 2;
Again we emphasize to only use this when feeding jsdom code you know is safe. If you use it on arbitrary user-supplied code, or code from the Internet, you are effectively running untrusted Node.js code, and your machine could be compromised.
If you want to execute external scripts, included via
<script src="">
, you'll also need to ensure that they load them. To do this, add the optionresources: "usable"
as described below.
Given I was unable to reproduce the url
-based solution from the code above...
Brutal bundle alternative : inline it all !
Read the various .js
files, inject them as string into the html page. Then wait the page to load as in a normal navigator.
These libraries are loaded into _window = new JSDOM(html, { options }).window;
and therefor available to your node script.
This is likely to prevent you from doing xhr calls and therefore only partially solve the issue.
say-hello.js
// fired when loaded
console.log("say-hello.js says: hello!")
// defined and needing a call
var sayBye = function(name) {
var name = name ||'Hero!';
console.log("say-hello.js says: Good bye! "+name)
}
main.js:
const fs = require("fs");
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
var NAME = process.env.NAME; // variable from terminal
var html = '<!DOCTYPE html><head></head><body><div>Foo</div></body>'
var _window = new JSDOM(html, {
runScripts: "dangerously",
resources: "usable" }).window;
/* ************************************************************************* */
/* Add scripts to head ***************************************************** */
var jsFiles = [
'say-hello.js'
];
var scriptsContent = ``;
for(var i =0; i< jsFiles.length;i++){
console.log(__dirname + '/'+ jsFiles[i])
let scriptContent = fs.readFileSync( jsFiles[i], 'utf8');
scriptsContent = scriptsContent + `
/* ******************************************************************************************* */
/* `+jsFiles[i]+` **************************************************************************** */
`+scriptContent;
};
let scriptElement = _window.document.createElement('script');
scriptElement.textContent = scriptsContent;
_window.document.head.appendChild(scriptElement);
/* ************************************************************************* */
/* Run page **************************************************************** */
_window.document.addEventListener('DOMContentLoaded', () => {
console.log('main says: DOMContentLoaded')
// We need to delay one extra turn because we are the first DOMContentLoaded listener,
// but we want to execute this code only after the second DOMContentLoaded listener
// (added by external.js) fires.
_window.sayBye(NAME); // prints "say-hello.js says: Good bye!"
});
Run it:
NAME=John node main.js # expects hello and good bye to john messages
Source:
- https://github.com/jsdom/jsdom/issues/1914
- https://github.com/jsdom/jsdom/issues/3023
Using JSDOM option url : file://${__dirname}/index.html
could work, according to a source. If you test it, please report result here.
jsdom.env()
. This one does not. How is that answer applicable here? – Lone Learner Commented Oct 30, 2018 at 17:14bar.js
andfoo.js
but I'am unable to reproduce your scenario. It only returnswindow loaded
but notbar says: hello
. Is the code above missing some settings or code ? – Hugolpz Commented Sep 1, 2020 at 17:53