JSDOM - 文档未定义

JSDOM - Document is not defined

我创建了一个非常简单的页面,它只显示一条消息,因为我正在尝试测试 JSDOM 以使用 document。但是,我收到以下错误。

首先,我在网上看了无数的例子,加上Stack Overflow上的问题,但是连最简单的例子我都解决不了。作为旁注,我是 Javascript.

的新手

到目前为止我的代码如下:

根目录

--->index.html
--->module.js
--->包-lock.json
--->package.json
--->测试
--->--->messageTest.js

不同的文件如下:

index.html

<!doctype html>
<head>
  <meta charset="utf-8">
  <title>jsdom Unit Test</title>
</head>

<body>
  <p id='msg'>Hello, World!</p>
  <script src="module.js"></script>
</body>
</html>

module.js

function updateMsg(newMsg) {
  document.getElementById('msg').innerHTML = newMsg;
}

updateMsg("Changing message");

module.exports = updateMsg;

package.json

{
  "name": "message-example",
  "version": "1.0.0",
  "description": "Testing how to use the JSDOM",
  "main": "module.js",
  "scripts": {
    "test": "mocha"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "chai": "^4.2.0",
    "jsdom": "^15.1.1",
    "mocha": "^6.2.0",
    "mocha-jsdom": "^2.0.0",
    "rewire": "^4.0.1",
    "sinon": "^7.3.2"
  }
}

messageTest.js

var updateMsg = require('../module.js');
const expect = require('chai').expect
const { JSDOM } = require('jsdom');

describe('updateMsg', function () {

  before(function() {
    return JSDOM.fromFile('index.html')
      .then((dom) => {
        global.window = dom.window;
        global.document = window.document;
      });
  })

  it ('updates the innerHTML of element with id "msg"', function () {
    expect(document.getElementById('msg').innerHTML).to.equal('Hello, World!');
    updateMsg('The new msg!');
    expect(document.getElementById('msg').innerHTML).to.equal('The new msg!');
  });
});

如果我 运行 使用 npm test 进行测试,我会在 module.js 的 document.getElementByID... 步骤得到 ReferenceError: document is not defined 错误 文件。

如果我删除 updateMsg("Changing message"),我的测试显然 运行 没问题。

你在那个例子中有几个问题:

  1. 您正在混合 jsdom window 和全局节点上下文。避免分配给 global(因为这样更容易犯错误),不要 require() 您想要 运行 的脚本在您的虚拟 window.

  2. jsdom 默认阻止 运行ning on-page 脚本,所以你的 module.js 既不加载也不执行。你必须提供 { resources: "usable", runScripts: "outside-only" } 参数来解决这个问题(确保你阅读了 jsdom README 中的安全隐患)。

  3. 您没有等待 load 事件,因此您的测试是 运行 在 jsdom 有机会加载脚本之前。

工作代码看起来像这样:

const expect = require("chai").expect;
const { JSDOM } = require("jsdom");

describe("updateMsg", function() {
  let jsdom;
  before(async function() {
    jsdom = await JSDOM.fromFile("index.html", {
      resources: "usable",
      runScripts: "dangerously"
    });
    await new Promise(resolve =>
      jsdom.window.addEventListener("load", resolve)
    );
  });

  it('updates the innerHTML of element with id "msg"', function() {
    expect(jsdom.window.document.getElementById("msg").innerHTML).to.equal(
      "Hello, World!"
    );
    jsdom.window.updateMsg("The new msg!");
    expect(jsdom.window.document.getElementById("msg").innerHTML).to.equal(
      "The new msg!"
    );
  });
});

您还需要从 module.js 中删除模块行,module 在浏览器中不存在。