question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

JSDOM does not load <script> javascript code recursively

See original GitHub issue

If you have a script1 which create a script2 tag which itself create a script3 tag, then only script1 and script2 are listed in the DOM using the following code:

var jsdom = require('jsdom');
jsdom.defaultDocumentFeatures = { 
    FetchExternalResources   : ['script'],
    ProcessExternalResources : ['script'],
    MutationEvents           : '2.0',
};
var html = "<html><head><script src="script1.js"></script></head><body>test</body></html>";
var window = jsdom.jsdom( html ).createWindow();
window.addEventListener('load', function () { 
/* Only two script nodes in the DOM */
});

It looks like jsdom does not evaluate the code of script2, so jsdom does not seem to work recursively. This is a problem in my case. How to fix that?

Issue Analytics

  • State:closed
  • Created 10 years ago
  • Comments:8 (4 by maintainers)

github_iconTop GitHub Comments

9reactions
matthewkastorcommented, Aug 6, 2013

It is true, dynamically inserted scripts load asynchronously. When the document fires the load event your dynamically injected script tags may not have finished executing but your hard coded scripts will have (by default). There are module loaders that use this method to shorten page load times. Basically, you’d write script tags in the page to start your loader and have it dynamically insert script tags so everything loaded asynchronously. The module loaders provide methods for defining dependencies, so if you absolutely have to wait for a certain script to load before beginning some dependent script, you can do that. The module loader will also provide some signal indicating when it is finished loading all of the scripts. So, unless you’ve rolled your own loader, you should be able to find documentation on what events fire and when. For your loader you’d just hook into whatever the “all scripts have fired” event is and proceed from there.

There is no event defined to tell the browser when all dynamically generated script tags have loaded because there is no possible way for the browser to know how many script tags will be generated in the future.

Imagine it, you run a setInterval that generates a new script tag every 10 seconds. How is the browser to be expected to know that another script will be generated in ten seconds? When would it fire the “all dynamically generated and inserted scripts have executed”? When some idle time came up between intervals? Never? After every script dynamically inserted?

The solution is either in the documentation of your module loader or, you will have to create your own signal letting you know that all the dynamic scripts have been loaded. Then, you’ll wait for this signal before asking jsdom to do whatever it is that you want it to do after all dynamically injected scripts have been executed. The equivalent user action is navigating to a page, waiting for it to load completely, and then viewing the “live” source of the page with document.documentElement.innerHTML or tools available in the browser. If you want to go the quick and dirty route, you could defer your actions with a setTimeout that has some extremely long duration to ensure that a best effort has been made to execute the dynamically injected scripts before you take a snapshot or whatever.

@domenic Maybe a wiki article about this would help? I understand not wanting to reiterate every tip and trick about dealing with the live dom and http protocols but this is something pretty basic that is often a cause of confusion for people first using a headless browser.

http://www.stevesouders.com/blog/2009/04/27/loading-scripts-without-blocking/ http://www.sitepoint.com/non-blocking-async-defer/

0reactions
domeniccommented, Aug 6, 2013

Closed in favor of #675.

Read more comments on GitHub >

github_iconTop Results From Across the Web

jsdom doesn't process script inside web page - Stack Overflow
I am new to nodejs. I want to use jsdom to parse some web pages which may contain script code inside. But I...
Read more >
Easy Website Crawling with jsdom in Node.js
In the next step, we are initializing JSDOM with our string which converts it to an actual DOM, where we can work on....
Read more >
Using enzyme with JSDOM - GitHub Pages
Using enzyme with JSDOM. JSDOM is a JavaScript based headless browser that can be used to create a realistic testing environment.
Read more >
jsdom-fabricjs - npm Package Health Analysis | Snyk
If config.html and config.file are not provided, jsdom will load HTML from ... Similar to scripts , but it accepts JavaScript instead of...
Read more >
Configuring Jest compiled - w3resource
This is because of the need to load the actual transformers (e.g. babel or typescript) to perform transformation. Example: // setup.js ```module ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found