jsdom peut exécuter des scripts qui sont en ligne à l'intérieur de la balise <head>
du document, mais comment lui faire exécuter des scripts qui sont liés à l'en-tête du document via <script src="">
?
Pour les options que j'utilise:
{
url: url,
resources: 'usable',
runScripts: 'dangerously',
}
// index.js
const request = require('request')
const jsdom = require('jsdom')
const {JSDOM} = jsdom
const url = 'http://localhost:8000'
request(url, (error, response, body) => {
const options = {
url: url,
resources: 'usable',
runScripts: 'dangerously',
}
const dom = new JSDOM(body, options)
console.log(dom.window.document.body.children.length) // Expecting to see `1`
console.log(dom.window.document.body.innerHTML) // Expecting to see `<h1>Hello world</h1>`
})
// external.js
document.addEventListener('DOMContentLoaded', () => {
document.write('<h1>Hello world!</h1>')
})
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JSDOM test</title>
<script src="external.js"></script>
</head>
<body>
</body>
</html>
Exemple de travail minimum complet : https://github.com/cg433n/jsdom-test
Le problème ici est que DOMContentLoaded
est un événement asynchrone. Vous vous connectez avant que cela ait une chance de se produire. Vous devez attendre qu'il se déclenche ; ce n'est qu'alors que votre document.write()
arrivera.
Quelque chose comme ça devrait probablement fonctionner :
const dom = new JSDOM(body, options)
dom.window.document.addEventListener('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.
setImmediate(() => {
console.log(dom.window.document.body.children.length) // Expecting to see `1`
console.log(dom.window.document.body.innerHTML) // Expecting to see `<h1>Hello world</h1>`
});
});
Je vois! Vous êtes fantastiques - continuez votre bon travail !
Remarque : 2 fonctionnalités de la démo ci-dessus sont risquées.
request
est amorti. npm install request
donne :setImmediate
est risqué à long terme .Alternativement, je recommande d'utiliser fs
pour lire et charger les codes js à partir de fichiers, voir Stackoverflow basé sur l' approche FS.read()
de @EricRicketts dans #3023 et addEventListener()
de @Domenic dans #1914. La démo de travail que je propose comprend :
fs.readFileSync
pour charger des js externes dans html sous forme de chaînesCela vous empêchera probablement de faire des appels xhr/API et ne résoudra donc que partiellement le problème.
Je n'arrivais pas à trouver le moyen d'obtenir un travail d'url.
Idéalement, un JSDOM minimal mis à jour chargeant des fichiers external.js via une démo de travail d'url serait le bienvenu. :cœur:
Commentaire le plus utile
Le problème ici est que
DOMContentLoaded
est un événement asynchrone. Vous vous connectez avant que cela ait une chance de se produire. Vous devez attendre qu'il se déclenche ; ce n'est qu'alors que votredocument.write()
arrivera.Quelque chose comme ça devrait probablement fonctionner :