我有两个几乎相同的JS文件,我无法更改它们要为其添加测试。
文件1:
const url = "https://file-1.js";
(function () {
"use strict";
window.onload = () => {
const script = document.createElement("script");
script.src = url;
document.head.appendChild(script);
};
})();
文件2:
const url = "https://file-2.js";
(function () {
"use strict";
window.onload = () => {
const script = document.createElement("script");
script.src = url;
document.head.appendChild(script);
};
})();
然后测试1:
const chai = require("chai");
const { expect } = chai;
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
const { window } = new JSDOM(`<!DOCTYPE html><head></head><p>Fake document</p>`, {
resources: "usable",
});
global.document = window.document;
global.window = window;
const myFile = require("../src/myFile");
describe("Test 1", function () {
it("Loads a file from an external source", function (done) {
console.log(window.document.head.children); // See what's going on
expect(window.document.head.children[0].src).to.equal("https://file-1.js");
});
});
测试2:
const chai = require("chai");
const { expect } = chai;
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
const myFile2 = require("../src/myFile2");
describe("Test 2", function () {
it("Loads a file from an external source", function (done) {
console.log(window.document.head.children); // See what's going on
expect(window.document.head.children[0].src).to.equal("https://file-2.js");
});
});
测试2通过,但测试1失败。两个console.logs的值是:
HTMLCollection { '0': HTMLScriptElement {} }
[console.log(window.document.head.children[0].src)
产生:
https://file-2.js
我希望window.document.head
中有两个孩子,但上面只有1个。看来Mocha首先要在所有测试中加载所有必需的文件,而第二个文件中的appendChild会覆盖第一个文件中的值。
有没有解决的办法?我尝试了done()
或在需要被调用的地方四处移动,但结果相同。
I created a repo for you to look at.一些注意事项:
如果要加载外部脚本,请为JSDOM设置runScripts: "dangerously"
标志(请参见this issue)。
我们需要自己手动重新触发load
事件-基本上,在执行脚本时,document.readyState
的状态为"complete"
,即load
事件已经触发。
这里发生的是,一旦JSDOM编译完HTML脚本,我们就在初始化时将其传递给window
。我们可以导入所需的内容,然后手动触发load
事件-只要我们不将任何脚本传递给初始JSDOM调用,就可以确保不会触发任何东西。
加载事件触发后,实际上已正确设置了生成的<script>
标签,但是由于它们包含没有实际加载内容的伪URL,因此该过程将抛出:Error: Could not load script: "https://file-1.js/"
。为了测试,我将这些URL更改为jQuery库和Hammer.js,您将需要添加逻辑以确保URL安全。
因为两个脚本都设置了window.onload = function() {...}
,所以如果我们都运行它们,然后触发load
事件(通常会这样做),则window.onload
在运行时将被test2.js
覆盖。我们可以解决这个问题,但这仅仅是因为我们知道脚本包含的内容。
过去几天我实际上一直在从事与此类似的工作,最近又提出了两个软件包来帮助解决类似的情况:enable-window-document(公开了window
和document
全局)和enable-browser-mode(旨在完全模拟浏览器运行时,将global
对象设置为window
,并公开window.include
函数以在全局上下文中评估导入的脚本,即: window.include('jquery.min.js')
,没有错误)。
对于这种情况(以及测试脚本的低复杂性),enable-window-document就足够了。当以完全浏览器兼容性模式运行时,由于两个脚本中的const url = ...
声明,我们实际上会失败-在启用完全浏览器兼容性的情况下,会在全局上下文中对这些脚本进行评估,从而导致尝试重新设置window.url
变量声明为const
。只需将window
和document
全局变量设置为[[will就可以用在此用例中,但是如果您开始加载复杂的脚本,则可能会遇到问题。
enable-browser-mode
变量),然后替换对浏览器JS的所有const
调用(require
和[C0 ])和test1.js
。这将确保该窗口引用全局对象,并且您的平均野生浏览器JS将按预期执行。加载所有脚本并解决test2.js
冲突后,我们运行测试:
include()
onload
而且很奇怪,我们无法在运行时访问// inside index.js ... console.log(document.head.outerHTML); console.log("jQuery:", window.$);
。但是,在控制台中:
$ node . RUNNING TESTS... <head><script src="https://code.jquery.com/jquery-3.5.1.min.js"></script><script src="https://hammerjs.github.io/dist/hammer.min.js"></script></head> jQuery: undefined
因此,我建议您四处逛逛,看看您可以做什么,而不能上班。[脚注:笑话是Facebook的热门垃圾,我不会在调试它时担心自己(声称
window.jQuery
中不存在$ node Welcome to Node.js v14.4.0. Type ".help" for more information. > require('.') RUNNING TESTS... <head><script src="https://code.jquery.com/jquery-3.5.1.min.js"></script><script src="https://hammerjs.github.io/dist/hammer.min.js"></script></head> jQuery: undefined {} > window.jQuery <ref *1> [Function: S] { fn: S { jquery: '3.5.1', constructor: [Circular *1], length: 0, toArray: [Function: toArray] ...
全局变量,依此类推)。尽管我可能会遗漏某些东西,但我们在此所做的工作还是很棘手,似乎超出了套件的范围。如果您想花时间调试它,请成为我的客人:我离开了项目结构,以便您可以运行window
并查看它在抱怨什么。无论如何,希望对您有所帮助。