Я не могу использовать JSDOM (версия 13.0.0) для загрузки скриптов из локальной файловой системы с относительным путем.
Я изучил следующие вопросы, но они не отвечают на мой вопрос:
runScripts и resources там).Файл foo.js:
var jsdom = require('jsdom')
var html = `<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<script src = "bar.js"></script>
</head>
<body>
<div>Test</div>
</body>
</html>`
global.window = new jsdom.JSDOM(html, { runScripts: "dangerously", resources: "usable" }).window
console.info('foo')
Файл bar.js:
console.info('bar')
Вот ошибка, которую я получаю:
$ node foo.js
foo
Error: Could not load script: "bar.js"
at onErrorWrapped (/Users/lone/so/node_modules/jsdom/lib/jsdom/browser/resources/per-document-resource-loader.js:41:19)
at Object.check (/Users/lone/so/node_modules/jsdom/lib/jsdom/browser/resources/resource-queue.js:72:23)
at request.then.catch.err (/Users/lone/so/node_modules/jsdom/lib/jsdom/browser/resources/resource-queue.js:124:14)
at process._tickCallback (internal/process/next_tick.js:68:7)
at Function.Module.runMain (internal/modules/cjs/loader.js:746:11)
at startup (internal/bootstrap/node.js:240:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:564:3) Error: Tried to fetch invalid URL bar.js
at ResourceLoader.fetch (/Users/lone/so/node_modules/jsdom/lib/jsdom/browser/resources/resource-loader.js:84:29)
at PerDocumentResourceLoader.fetch (/Users/lone/so/node_modules/jsdom/lib/jsdom/browser/resources/per-document-resource-loader.js:16:42)
at HTMLScriptElementImpl._fetchExternalScript (/Users/lone/so/node_modules/jsdom/lib/jsdom/living/nodes/HTMLScriptElement-impl.js:92:30)
at HTMLScriptElementImpl._eval (/Users/lone/so/node_modules/jsdom/lib/jsdom/living/nodes/HTMLScriptElement-impl.js:161:12)
at HTMLScriptElementImpl._poppedOffStackOfOpenElements (/Users/lone/so/node_modules/jsdom/lib/jsdom/living/nodes/HTMLScriptElement-impl.js:126:10)
at OpenElementStack.pop (/Users/lone/so/node_modules/jsdom/lib/jsdom/browser/htmltodom.js:17:12)
at Object.endTagInText [as END_TAG_TOKEN] (/Users/lone/so/node_modules/parse5/lib/parser/index.js:2153:20)
at Parser._processToken (/Users/lone/so/node_modules/parse5/lib/parser/index.js:657:55)
at Parser._processInputToken (/Users/lone/so/node_modules/parse5/lib/parser/index.js:684:18)
at Parser._runParsingLoop (/Users/lone/so/node_modules/parse5/lib/parser/index.js:440:18)
Как я могу загрузить локальный файл JavaScript при использовании JSDOM?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


JSDOM не знает, где искать этот файл локально во время выполнения. Итак, запустив свой пример, вы можете следовать любому из этих двух подходов.
1-й подход
Вам нужно дождаться загрузки и выполнения файла сценария.
Создайте три файла index.html,index.js and test.js в одной папке.
index.html
<!doctype html>
<html>
<head>
<meta charset = "UTF-8">
<title></title>
</head>
<body>
abc
<script src='index.js'></script>
</body>
</html>
index.js
document.body.textContent = 123;
test.js
'use strict';
const { JSDOM } = require('jsdom');
const options = {
resources: 'usable',
runScripts: 'dangerously',
};
JSDOM.fromFile('index.html', options).then((dom) => {
console.info(dom.window.document.body.textContent.trim());
setTimeout(() => {
console.info(dom.window.document.body.textContent.trim());
}, 5000);
});
// console output
// abc
// 123
2-й подход
Установите базовую корневую папку внешних скриптов в JSDOM env.
js / index.js
console.info('load from jsdom');
var loadFromJSDOM = 'load from jsdom';
test.js
'use strict';
const { JSDOM } = require('jsdom');
JSDOM.env({
html: "<html><body></body></html>",
documentRoot: __dirname + '/js',
scripts: [
'index.js'
]
}, function (err, window) {
console.info(window.loadFromJSDOM);
}
);
Подробнее читайте в этих ссылках
https://github.com/jsdom/jsdom/issues/1867
jsdom.env: локальный скрипт jquery не работает
В первом подходе замените setTimeout(..., 5000); на dom.window.addEventListerner('load', ...);, чтобы избежать паузы.
Отличный ответ от front_end_dev. Это мне очень помогло, и я расскажу, как мой код работает с этим решением, чтобы быть более понятным. Может быть поможет другим.
import "@testing-library/jest-dom";
import { logDOM } from "@testing-library/dom";
import { JSDOM } from "jsdom";
import fs from "fs";
import path from "path";
const html = fs.readFileSync(path.resolve(__dirname, "../index.html"), "utf8");
let dom;
let container;
jest.dontMock("fs");
function waitForDom() {
return new Promise((resolve) => {
dom = new JSDOM(html, {
runScripts: "dangerously",
resources: "usable",
url: `file://${path.resolve(__dirname, "..")}/index.html`,
});
dom.window.document.addEventListener("DOMContentLoaded", () => {
resolve();
});
});
}
beforeAll(() => waitForDom());
beforeEach(() => {
container = dom.window.document.body;
});
afterEach(() => container = null)
it("should ", () => {
logDOM(container);
});
Второй подход (с использованием env) не работает. Однако первый делает.