【问题标题】:How to load local JavaScript file with JSDOM?如何使用 JSDOM 加载本地 JavaScript 文件?
【发布时间】:2018-11-10 05:33:16
【问题描述】:

我无法使用 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.log('foo')

文件bar.js

console.log('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)

如何在使用 JSDOM 时加载本地 JavaScript 文件?

【问题讨论】:

    标签: javascript node.js jsdom


    【解决方案1】:

    JSDOM 在执行时不知道在本地哪里查找该文件。因此,运行您的示例,您可以采用这两种方法中的任何一种。

    第一种方法

    您必须等待脚本文件加载并执行。

    在同一个文件夹中创建三个文件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.log(dom.window.document.body.textContent.trim());
    
      setTimeout(() => {
        console.log(dom.window.document.body.textContent.trim());
      }, 5000);
    });
    
     // console output
     // abc
     // 123
    

    第二种方法JSDOM env 中设置外部脚本基础根文件夹。

    js/index.js

    console.log('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.log(window.loadFromJSDOM);
        }
    );
    

    从这些参考资料中了解更多信息

    https://github.com/jsdom/jsdom/issues/1867

    jsdom.env: local jquery script doesn't work

    【讨论】:

    • 第二种方法(使用“env”)不起作用。但是第一个确实如此。
    • 在第一种方法中,将setTimeout(..., 5000); 替换为dom.window.addEventListerner('load', ...);,以避免引入停顿。
    • @BlackMantha,谢谢,不是.addEventListerner,而是.addEventListener
    【解决方案2】:

    来自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);
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-13
      • 1970-01-01
      • 2011-04-23
      • 2021-11-02
      • 2018-10-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多