Как загрузить локальный файл JavaScript с помощью JSDOM?

Я не могу использовать JSDOM (версия 13.0.0) для загрузки скриптов из локальной файловой системы с относительным путем.

Я изучил следующие вопросы, но они не отвечают на мой вопрос:

Файл 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?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
7
0
6 981
2

Ответы 2

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 не работает

Второй подход (с использованием env) не работает. Однако первый делает.

Erik Kránicz 06.06.2019 08:22

В первом подходе замените setTimeout(..., 5000); на dom.window.addEventListerner('load', ...);, чтобы избежать паузы.

Black Mantha 09.11.2020 14:30

Отличный ответ от 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);
});

Другие вопросы по теме