jsdom может запускать скрипты, встроенные в тег документа <head>
, но как заставить его запускать скрипты, связанные с заголовком документа через <script src="">
?
Для вариантов, которые я использую:
{
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>
Полный минимальный рабочий пример: https://github.com/cg433n/jsdom-test
Проблема здесь в том, что DOMContentLoaded
является асинхронным событием. Вы регистрируетесь до того, как это произойдет. Вам нужно дождаться его срабатывания; только тогда произойдет ваш document.write()
.
Что-то вроде этого, вероятно, должно работать:
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>`
});
});
Я понимаю! Вы молодцы - продолжайте в том же духе!
Примечание: 2 функции демо выше являются рискованными.
request
обесценивается. Результат npm install request
:setImmediate
рискованно в долгосрочной перспективе .В качестве альтернативы я рекомендую использовать fs
для чтения и загрузки кодов js из файлов, см. Stackoverflow на основе подхода @EricRicketts ' FS.read()
в #3023 и addEventListener()
@Domenic в № 1914. Предлагаемая рабочая демонстрация включает в себя:
fs.readFileSync
для загрузки внешних js в html в виде строкЭто, вероятно, помешает вам выполнять вызовы xhr/API и, следовательно, лишь частично решит проблему.
Я не мог понять, как заставить URL работать.
В идеале будет приветствоваться обновленный минимальный JSDOM, загружающий файлы external.js через рабочую демонстрацию URL . :сердце:
Самый полезный комментарий
Проблема здесь в том, что
DOMContentLoaded
является асинхронным событием. Вы регистрируетесь до того, как это произойдет. Вам нужно дождаться его срабатывания; только тогда произойдет вашdocument.write()
.Что-то вроде этого, вероятно, должно работать: