嘲笑`文件`开玩笑

时间:2016-12-12 09:47:45

标签: jestjs jsdom babel-jest

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

开玩笑失败的一段代码。

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

更新 根据AndreasKö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__的情况下尝试了上述代码。同时将文档设置为全局。

9 个答案:

答案 0 :(得分:10)

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

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

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


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

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

答案 1 :(得分:10)

与其他人所说的相似,但不是试图自己模拟DOM,而是使用JSDOM:

<强> __嘲笑__ / client.js

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

然后在你的jest配置中:

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

答案 2 :(得分:3)

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


  • 超级项目
    • 配置
      • GetSize(int): cmp edi, 1 sbb eax, eax and eax, 98 add eax, 150 ret
        • dom.js
    • src
      • user.js
    • 测试
      • user.test.js
    • jest.config.js
    • package.json

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

dom.js

GetSize:
        mov     eax, 248
        test    edi, edi
        je      .L1
        mov     eax, 150
.L1:
        ret

user.js

__mocks__

user.test.js

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

jest.config.js

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

参考:

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

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

最佳配置:
https://jestjs.io/docs/en/configuration

答案 3 :(得分:2)

我可以使用nodejs上的global范围模块解决同样的问题,使用模拟文档设置文档,在我的例子中,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
};

答案 4 :(得分:2)

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

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

答案 5 :(得分:1)

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

示例:

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

答案 6 :(得分:0)

如果需要为属性定义测试值,则会采用稍微细化的方法。每个属性都需要单独定义,并且还需要创建属性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

起作用

答案 7 :(得分:0)

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

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

这样,您可以手动将getElementsByClassName的返回值设置为等于.some-class的引用。可能有必要通过调用wrapper.setProps({})重新呈现组件。

希望这对您有所帮助!

答案 8 :(得分:-2)

希望这会有所帮助

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