如何在React组件测试中模拟窗口大小变化

60

基本上当组件挂载时,我有一个事件监听器监听 resize 事件。它切换 isMobileView 状态,然后将其作为 prop 传递给子组件。 因此,这必须有效并进行测试。 我在测试方面相对较新,正在尝试找到一种方法,可以编写一个测试,调整窗口大小,并使所有逻辑发生,并测试它是否按照预期执行。

以下是代码 -

componentDidMount() {
    this.setMobileViewState()
    window.addEventListener('resize', this.setMobileViewState.bind(this));
}

setMobileViewState() {
    if(document.documentElement.clientWidth <= this.props.mobileMenuShowWidth) {
        this.setState({ isMobileView: true })
    } else {
        this.setState({ isMobileView: false })
    }
}

我知道代码是有效的,但我想为它编写一个测试。基本上只需要确保状态正确更改的东西。

7个回答

89

使用Jest和Enzyme,您可以完成以下操作。Jest内置了JSDOM。在测试中,Jest提供window对象,并由global表示(我认为Jest默认设置的window.innerWidth为1024像素):

test('Test something when the viewport changes.', () => {

    // Mount the component to test.
    const component = mount(<ComponentToTest/>);

    ...

    // Change the viewport to 500px.
    global.innerWidth = 500;

    // Trigger the window resize event.
    global.dispatchEvent(new Event('resize'));

    ...

    // Run your assertion.
});

1
根据 https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth 上的文档,innerWidth 是只读的。我们是否应该使用 window.resizeBy(x, y) 代替? - Simon
1
我正在使用 Jest 23.6.0,它对我来说很有效,也许需要升级 ‍♂️ - cameck
1
已确认在Jest 24.1.0中仍然有效。使用resizeBy是有意义的,但Jest没有实现它,而innerWidth不是只读的。 - Chris
6
似乎这个不再起作用了:“类型'Global'上不存在属性'innerWidth'”。 - Jake
1
我尝试在window对象上设置innerWidth,但我的@media css查询似乎没有为测试生效。这只适用于node.js中的“全局”对象,还是在浏览器中的“window”对象也可以使用? - 1ak31sha
显示剩余5条评论

43

如果您遇到了TypeScript错误消息:

无法分配给 'innerWidth',因为它是只读属性。

请尝试:

Object.defineProperty(window, 'innerWidth', {writable: true, configurable: true, value: 200})

8
尝试这条命令:
window = Object.assign(window, { innerWidth: 500 });

1
jest.spyOn(window.screen, "width", "get").mockReturnValue(1000);

8
请勿仅仅发布代码作为答案。未来的读者会感激您解释为什么这个答案能回答问题,而不是让他们从代码中推断出来。此外,由于这是一个旧问题,请解释一下它如何补充其他答案。 - Gert Arnold

1

1

对于任何使用 react-testing-library 的人来说,也有一种本地方式可以使用 fireEvent 来实现它。

  import { fireEvent } from '@testing-library/react';
  ...

  it('should resize', () => {
    window.innerWidth = 500;
    fireEvent(window, new Event('resize'));

    // your test here
  });

注意:此代码仅适用于JS。window.innerWidth是只读属性,使用时会出现构建错误。如果使用TS,请参考@Lauren Madigan的答案。 - PaulGrant
2
问题中没有看到任何TS要求。 - Can Ural

1

我在测试库中成功运行了它:

  it('should resize', () => {
    const altImage = 'test'

    window.innerWidth = 500

    fireEvent(window, new Event('resize'))

    waitFor(() => {
      expect(screen.getByAltText(altImage)).not.toBeInTheDocument()
    })
  })

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接