JSDOM-未定义文档

时间:2019-07-19 13:48:00

标签: javascript html json dom jsdom

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

首先,除了在Stack Overflow上发布的问题外,我还在网上看到了无数的示例,但是即使是最简单的示例,我也无法解决。附带说明,我是Java的新手。

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

根目录

---> index.html
---> module.js
---> package-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 文件的ReferenceError: document is not defined步骤中收到document.getElementByID...错误。

如果我删除了updateMsg("Changing message"),我的测试显然可以正常运行。

1 个答案:

答案 0 :(得分:1)

在该示例中,您有几个问题:

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

  2. jsdom默认情况下阻止运行页面脚本,因此不会加载也不执行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在浏览器中不存在。