我需要测试一些在分配了URL的文档上创建元素然后单击的代码。
我正在使用Jest。
const link = document.createElement('a')
我放弃了模拟文档的尝试,因为我看不到一种简单的方法来进行模拟,尽管模拟点击会很不错。
我需要知道createElement
发生了,所以我决定创建一个间谍:
jest.spyOn(document, 'createElement')
由于某种原因,间谍无法通过测试,并且收到与尝试模拟文档时相同的错误:
Error: TypeError: Cannot set property 'href' of undefined
document.createElement
下面的代码是:
link.href = url
有什么想法吗?
答案 0 :(得分:0)
这是解决方案,我使用node.js运行时环境进行演示:
class Link {
private name: string;
private _href: string = '';
constructor(name) {
this.name = name;
}
get href() {
return this._href;
}
set href(url) {
this._href = url;
}
}
const document = {
createElement(name) {
return new Link(name);
}
};
function createLink(url) {
const link = document.createElement('a');
link.href = url;
return link;
}
export { createLink, document, Link };
单元测试:
import { createLink, document, Link } from './';
describe('createLink', () => {
it('t1', () => {
const url = 'https://github.com/mrdulin';
jest.spyOn(document, 'createElement').mockReturnValueOnce(new Link('mock link'));
const link = createLink(url);
expect(link).toBeInstanceOf(Link);
expect(link.href).toBe(url);
});
});
PASS src/stackoverflow/57088724/index.spec.ts
createLink
✓ t1 (6ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 2.451s, estimated 3s
答案 1 :(得分:0)
在我最新的开源项目 (TabMerger) 上工作时,我想出了一个更简单的解决方案,并认为它更直观,可以帮助正在苦苦挣扎的人。此外,它可以很容易地根据您的需要进行调整。
// function to test
function exportJSON() {
chrome.storage.local.get("groups", (local) => {
var group_blocks = local.groups;
chrome.storage.sync.get("settings", (sync) => {
group_blocks["settings"] = sync.settings;
var dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(group_blocks, null, 2));
// want to test all of below also!!
var anchor = document.createElement("a");
anchor.setAttribute("href", dataStr);
anchor.setAttribute("download", AppHelper.outputFileName() + ".json");
anchor.click();
anchor.remove();
});
});
}
为了测试,我只是模拟 document.createElement
函数的返回值以返回一个可以被监视的锚对象:
describe("exportJSON", () => {
it("correctly exports a JSON file of the current configuration", () => {
// ARRANGE
// creates the anchor tag as an object
function makeAnchor(target) {
return {
target,
setAttribute: jest.fn((key, value) => (target[key] = value)),
click: jest.fn(),
remove: jest.fn(),
};
}
// spy on the document.createElement and mock its return
// also spy on each anchor function you want to test
var anchor = makeAnchor({ href: "#", download: "" });
var createElementMock = jest.spyOn(document, "createElement").mockReturnValue(anchor);
var setAttributeSpy = jest.spyOn(anchor, "setAttribute");
var clickSpy = jest.spyOn(anchor, "click");
var removeSpy = jest.spyOn(anchor, "remove");
// create expectations
var group_blocks = JSON.parse(localStorage.getItem("groups"));
group_blocks["settings"] = JSON.parse(sessionStorage.getItem("settings"));
const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(group_blocks, null, 2));
jest.clearAllMocks(); // start with clean mocks/spies before call is made
// ACT
AppFunc.exportJSON();
// ASSERT
// chromeLocalGetSpy, chromeSyncGetSpy defined elsewhere as
// jest.spyOn(chrome.storage.local, "get") & jest.spyOn(chrome.storage.sync, "get"), respectively.
expect(chromeLocalGetSpy).toHaveBeenCalledTimes(1);
expect(chromeLocalGetSpy).toHaveBeenCalledWith("groups", anything);
expect(chromeSyncGetSpy).toHaveBeenCalledTimes(1);
expect(chromeSyncGetSpy).toHaveBeenCalledWith("settings", anything);
expect(document.createElement).toHaveBeenCalledTimes(1);
expect(document.createElement).toHaveBeenCalledWith("a");
expect(setAttributeSpy).toHaveBeenCalledTimes(2);
expect(setAttributeSpy).toHaveBeenNthCalledWith(1, "href", dataStr);
expect(setAttributeSpy).toHaveBeenNthCalledWith(2, "download", AppHelper.outputFileName() + ".json");
expect(clickSpy).toHaveBeenCalledTimes(1);
expect(removeSpy).toHaveBeenCalledTimes(1);
createElementMock.mockRestore(); // restore document.createElement so that it is unchanged in other tests
});
});
exportJSON
√ correctly exports a JSON file of the current configuration (48 ms)
完整代码可在我的 GitHub
您可以看到 localStorage
和 sessionStorage
分别用于模拟 chrome.storage.local
和 chrome.storage.sync
API,位于 <rootDir>/tests/__mocks__/chromeMock.js
文件夹中。