开玩笑地嘲笑“文件”

Mocking `document` in jest

我正在开玩笑地为我的 Web 组件项目编写测试。我已经使用带有 es2015 预设的 babel。我在加载 js 文件时遇到问题。我遵循了一段代码,其中 document 对象有一个 currentScript 对象。但在测试上下文中它是 null。所以我在想嘲笑同样的事情。但是 jest.fn() 并没有真正的帮助。我该如何处理这个问题?

jest 失败的一段代码。

var currentScriptElement = document._currentScript || document.currentScript;
var importDoc = currentScriptElement.ownerDocument;

我写的测试用例。 component.test.js

import * as Component from './sample-component.js';

describe('component test', function() {
  it('check instance', function() {
    console.log(Component);
    expect(Component).toBeDefined();
  });
});

以下是jest抛出的错误

Test suite failed to run

    TypeError: Cannot read property 'ownerDocument' of null

      at src/components/sample-component/sample-component.js:4:39

更新: 根据 Andreas Köberle 的建议,我添加了一些全局变量并尝试模拟如下

__DEV__.document.currentScript = document._currentScript = {
  ownerDocument: ''
};
__DEV__.window = {
  document: __DEV__.document
}
__DEV__.document.registerElement = jest.fn();

import * as Component from './arc-sample-component.js';

describe('component test', function() {
  it('check instance', function() {
    console.log(Component);
    expect(Component).toBeDefined();
  });
});

但运气不好

更新: 我在没有 __dev__ 的情况下尝试了上面的代码。也可以通过将文档设置为全局。

我开玩笑地使用 setUpFiles 属性 解决了这个问题。这将在 jsdom 之后和每次测试之前执行,这对我来说是完美的。

在 Jest 配置中设置 setupFiles,例如:

"setupFiles": ["<rootDir>/browserMock.js"]


// browserMock.js
Object.defineProperty(document, 'currentScript', {
  value: document.createElement('script'),
});

理想情况是加载 webcomponents.js 以填充 jsdom。

我可以在 nodejs 上使用 global scope 模块解决同样的问题,使用模拟文档设置文档,在我的例子中,getElementsByClassName

// My simple mock file
export default {
    getElementsByClassName: () => {
        return [{
            className: 'welcome'
        }]
    }
};

// Your test file
import document from './name.component.mock.js';
global.document = {
    getElementsByClassName: document.getElementsByClassName
};

如果你像我一样希望将文档模拟为未定义(例如,用于服务器端/客户端测试),我可以在我的测试套件中使用 object.defineProperty 而无需使用 setupFiles

示例:

beforeAll(() => {
  Object.defineProperty(global, 'document', {});
})

如果您需要为属性定义测试值,可以使用一种更精细的方法。每个属性都需要单独定义,还需要使属性writeable:

Object.defineProperty(window.document, 'URL', {
  writable: true,
  value: 'someurl'
});

参见:https://github.com/facebook/jest/issues/890

使用 Jest 21.2.1 和 Node v8.11.1

这对我有用

与其他人所说的类似,但与其尝试自己模拟 DOM,不如使用 JSDOM:

// __mocks__/client.js

import { JSDOM } from "jsdom"
const dom = new JSDOM()
global.document = dom.window.document
global.window = dom.window

然后在你的笑话配置中:

    "setupFiles": [
      "./__mocks__/client.js"
    ],

我一直在努力为我正在进行的项目模拟文档。我在 React 组件内调用 document.querySelector() 并需要确保它正常工作。最终这对我有用:

it('should test something', () => {
  const spyFunc = jest.fn();
  Object.defineProperty(global.document, 'querySelector', { value: spyFunc });
  <run some test>
  expect(spyFunc).toHaveBeenCalled()
});

希望对您有所帮助

const wrapper = document.createElement('div');
const render = shallow(<MockComponent{...props} />);
document.getElementById = jest.fn((id) => {
      wrapper.innerHTML = render.find(`#${id}`).html();
      return wrapper;
    });

这是我名为 super-project 的项目中的结构,位于文件夹 super-project:


  • 超级项目
    • 配置
      • __mocks__
        • dom.js
    • 来源
      • user.js
    • 测试
      • user.test.js
    • jest.config.js
    • package.json

您需要设置 Jest 以在测试中使用模拟:

dom.js:

import { JSDOM } from "jsdom"
const dom = new JSDOM()
global.document = dom.window.document
global.window = dom.window

user.js:

export function create() {
  return document.createElement('table');  
}

user.test.js:

import { create } from "../src/user";

test('create table', () => {
  expect(create().outerHTML).toBe('<table></table>');
});

jest.config.js:

module.exports = {
  setupFiles: ["./config/__mocks__/dom.js"],
};

参考文献:

您需要创建一个手动模拟:
https://jestjs.io/docs/en/manual-mocks.html

正在操纵 DOM 对象:
https://jestjs.io/docs/en/tutorial-jquery

开玩笑配置:
https://jestjs.io/docs/en/configuration

我找到了另一个解决方案。假设在您的组件内部,您想通过 className (document.getElementsByClassName) 获取对 DOM 中元素的引用。您可以执行以下操作:

let wrapper
beforeEach(() => {
    wrapper = mount(<YourComponent/>)
    jest.spyOn(document, 'getElementsByClassName').mockImplementation(() => 
        [wrapper.find('.some-class').getDOMNode()]
    )
})

通过这种方式,您可以手动将 getElementsByClassName 的 return 值设置为等于 .some-class 的引用。可能需要通过调用 wrapper.setProps({}).

重新渲染组件

希望这对你们中的一些人有所帮助!