使用Jest测试MutationObserver

时间:2018-02-15 14:37:03

标签: jestjs

我编写了一个脚本,其主要目的是为一些表格的单元格添加新元素。

测试是通过类似的方式完成的:

document.body.innerHTML = `
<body>
    <div id="${containerID}">
        <table>
            <tr id="meta-1"><td> </td></tr>
            <tr id="meta-2"><td> </td></tr>
            <tr id="meta-3"><td> </td></tr>
            <tr id="no-meta-1"><td> </td></tr>
        </table>
    </div>
</body>
`;

    const element = document.querySelector(`#${containerID}`);

    const subject = new WPMLCFInfoHelper(containerID);
    subject.addInfo();

    expect(mockWPMLCFInfoInit).toHaveBeenCalledTimes(3);

mockWPMLCFInfoInit,当被调用时,它告诉我该元素已添加到单元格中。

当向表中添加新行时,部分代码使用MutationObserver再次调用mockWPMLCFInfoInit

new MutationObserver((mutations) => {
    mutations.map((mutation) => {
        mutation.addedNodes && Array.from(mutation.addedNodes).filter((node) => {
            console.log('New row added');
            return node.tagName.toLowerCase() === 'tr';
        }).map((element) => WPMLCFInfoHelper.addInfo(element))
    });
}).observe(metasTable, {
    subtree:   true,
    childList: true
});

WPMLCFInfoHelper.addInfomockWPMLCFInfoInit的真实版本(当然是一种模拟方法)。

从上面的测试中,如果添加类似的东西......

const table = element.querySelector(`table`);
var row = table.insertRow(0);

console.log('New row added');永远不会被调用。 当然,我也尝试在新行中添加所需的单元格。

当然,手动测试告诉我代码有效。

搜索一下,我的理解是不支持MutationObserver和there is no plan to support it

足够公平,但在这种情况下,我该如何测试我的代码部分?除了手动,即:)

7 个答案:

答案 0 :(得分:9)

我知道我在这里参加派对已经迟到了,但在我的jest设置文件中,我只是添加了以下模拟MutationObserver类。

global.MutationObserver = class {
    constructor(callback) {}
    disconnect() {}
    observe(element, initObject) {}
};

这显然不允许你测试观察者做你想做的事情,但是会允许代码的其余部分运行哪个是工作解决方案的路径。

答案 1 :(得分:6)

该问题实际上是由于JSm不支持MutationObserver而出现的,因此您必须提供适当的 polyfill

有点棘手的想法可能不是最好的解决方案(让我们使用库旨在与IE9-10兼容)。

第1步(将此库安装到devDependencies)

npm install --save-dev mutation-observer

第2步(导入并全局设置)

import MutationObserver from 'mutation-observer'
global.MutationObserver = MutationObserver 

test('your test case', () => { 
   ...
})

答案 2 :(得分:3)

我认为解决方案的一部分只是观念转变。单元测试不应确定MutationObserver是否正常工作。假设它是正确的,并模拟代码所利用的部分。

只需提取您的回调函数,即可对其进行独立测试;然后,模拟MutationObserver(如samuraiseoul's answer一样)以防止发生错误。将模拟的MutationRecord列表传递到您的回调中,并测试预期的结果。

也就是说,使用Jest模拟函数模拟MutationObserver及其observe()disconnect()方法将至少允许您检查已被MutationObserver实例的数量。创建以及是否在预期的时间调用了这些方法。

const mutationObserverMock = jest.fn(function MutationObserver(callback) {
    this.observe = jest.fn();
    this.disconnect = jest.fn();
    // Optionally add a trigger() method to manually trigger a change
    this.trigger = (mockedMutationsList) => {
        callback(mockedMutationsList, this);
    };
});
global.MutationObserver = mutationObserverMock;

it('your test case', () => {
    // after new MutationObserver() is called in your code
    expect(mutationObserverMock.mock.instances).toBe(1);

    const [observerInstance] = mutationObserverMock.mock.instances;
    expect(observerInstance.observe).toHaveBeenCalledTimes(1);
});

答案 3 :(得分:0)

为TypeScript用户添加的内容:

通过添加一个名为:mutation-observer.d.ts

的文件来声明该模块。
/// <reference path="../../node_modules/mutation-observer" />
declare module "mutation-observer";

然后在您的笑话文件中。

import MutationObserver from 'mutation-observer'
(global as any).MutationObserver = MutationObserver

答案 4 :(得分:0)

您可以使用mutationobserver-shim

在setup.js中添加它

import "mutationobserver-shim"

并安装

npm i -D mutationobserver-shim

答案 5 :(得分:0)

由于这里没有提到:jsdom已经支持MutationObserver一段时间了。

这是实现它的公关https://github.com/jsdom/jsdom/pull/2398

答案 6 :(得分:0)

这是 Matt 的答案 above 的打字稿重写。

// Test setup
const mutatationObserverMock = jest
  .fn<MutationObserver, [MutationCallback]>()
  .mockImplementation(() => {
    return {
      observe: jest.fn(),
      disconnect: jest.fn(),
      takeRecords: jest.fn(),
    };
  });
global.MutationObserver = mutatationObserverMock;

// Usage
new MutationObserver(() => {
  console.log("lol");
}).observe(document, {});

// Test
const observerCb = mutatationObserverMock.mock.calls[0][0];
observerCb([], mutatationObserverMock.mock.instances[0]);