jsdom puede ejecutar secuencias de comandos que están en línea dentro de la etiqueta <head>
del documento, pero ¿cómo se ejecutan secuencias de comandos que están vinculadas en el encabezado del documento a través <script src="">
?
Para las opciones que estoy usando:
{
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>
Ejemplo de trabajo mínimo completo: https://github.com/cg433n/jsdom-test
El problema aquí es que DOMContentLoaded
es un evento asíncrono. Estás iniciando sesión antes de que tenga la oportunidad de suceder. Tienes que esperar a que se dispare; solo entonces sucederá su document.write()
.
Algo como esto probablemente debería funcionar:
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>`
});
});
¡Veo! Ustedes son fantásticos, ¡sigan con el buen trabajo!
Aviso: 2 características de la demostración anterior son riesgosas.
request
se deprecia. npm install request
da como resultado:setImmediate
es arriesgado a largo plazo .Alternativamente, recomiendo usar fs
para leer y cargar los códigos js de los archivos, vea Stackoverflow basado en el enfoque de FS.read()
de @EricRicketts en #3023 y addEventListener()
de @Domenic en #1914. La demostración de trabajo que propongo incluye:
fs.readFileSync
para cargar js externos en html como cadenasEs probable que esto le impida realizar llamadas xhr / API y, por lo tanto, solo resuelva parcialmente el problema.
No pude encontrar la manera de hacer funcionar la URL.
Idealmente, sería bienvenido un JSDOM mínimo actualizado que cargue archivos external.js a través de una demostración de trabajo de URL . :corazón:
Comentario más útil
El problema aquí es que
DOMContentLoaded
es un evento asíncrono. Estás iniciando sesión antes de que tenga la oportunidad de suceder. Tienes que esperar a que se dispare; solo entonces sucederá sudocument.write()
.Algo como esto probablemente debería funcionar: