jsdom pode executar scripts que estão embutidos dentro da tag <head>
do documento, mas como você faz com que ele execute scripts vinculados no cabeçalho do documento via <script src="">
?
Para opções que estou 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>
Exemplo de trabalho mínimo completo: https://github.com/cg433n/jsdom-test
O problema aqui é que DOMContentLoaded
é um evento assíncrono. Você está registrando antes que isso tenha a chance de acontecer. Você precisa esperar que ele dispare; só assim seu document.write()
vai acontecer.
Algo assim provavelmente deve 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>`
});
});
Eu vejo! Vocês são fantásticos - continuem o bom trabalho!
Aviso: 2 recursos da demonstração acima são arriscados.
request
é depreciado. npm install request
resulta em:setImmediate
é arriscado a longo prazo .Como alternativa, recomendo usar fs
para ler e carregar os códigos js de arquivos, consulte Stackoverflow baseado na abordagem FS.read()
de @EricRicketts em #3023 e addEventListener()
de @Domenic em #1914. A demonstração de trabalho que proponho inclui:
fs.readFileSync
para carregar js externos em html como stringsIsso provavelmente impedirá que você faça chamadas xhr/API e, portanto, resolva apenas parcialmente o problema.
Eu não conseguia descobrir a maneira de obter o trabalho de URL.
Idealmente, um JSDOM mínimo atualizado carregando arquivos external.js via URL de demonstração de trabalho seria bem-vindo. :coração:
Comentários muito úteis
O problema aqui é que
DOMContentLoaded
é um evento assíncrono. Você está registrando antes que isso tenha a chance de acontecer. Você precisa esperar que ele dispare; só assim seudocument.write()
vai acontecer.Algo assim provavelmente deve funcionar: