尝试在 Enzyme 测试中模拟 MUI 的 useMediaQuery 挂钩行为

问题描述 投票:0回答:3

编辑:我能够确定 MUI 的指令在使用 RTL 时可以正常工作。这个问题只发生在酶测试中!

我正在关注 MUI 关于如何测试 useMediaQuery 的文档,但我很困惑我在组件中使用 useMediaQuery 的方式(在 MUI 文档中概述)是否与 MUI 中的测试说明兼容文档。

这是我组件中的代码:

import { useTheme } from '@mui/material/styles';
import useMediaQuery from '@material-ui/core/useMediaQuery';

  const List = () => {
      const theme = useTheme();
      const isDownLargeBreakpoint = 
      useMediaQuery(theme.breakpoints.down('lg'));

      ...
      
      {isDownLargeBreakpoint && (
          <ul className="list">
            // list items
          </ul>
      )}

  }

当我在本地运行应用程序时,useMediaQuery 挂钩按预期工作,当我调整 MUI 主题

true
断点下方/上方的屏幕大小时,它会在
false
lg
之间正确切换。

当我尝试使用推荐的设置方法运行测试时,尽管 window.innerWidth 低于满足 useMediaQuery 返回值

true
的值,但我在测试中总是得到
false
。也许是因为我没有在测试中重新渲染我的组件?或者我是否必须在
it
子句中做更多事情才能触发需要发生的事情?

这是使用 MUI 推荐的

css-mediaquery
的代码块以及 已经回答的这篇文章

import mediaQuery from 'css-mediaquery';

function createMatchMedia(width) {
  return (query) => ({
    matches: mediaQuery.match(query, {
      width,
    }),
    addListener: () => {},
    removeListener: () => {},
  });
}

describe('MyTests', () => {
  beforeAll(() => {
    window.matchMedia = createMatchMedia(window.innerWidth);
  });
});

这是我组织测试文件的方式:

import React from 'react';
import { shallow } from 'enzyme';
import mediaQuery from 'css-mediaquery';

import SessionStore from 'app/stores/SessionStore';

import CustomFields from '../CustomFields';
import CustomFieldButton from '../CustomFieldButton';

import PrepareFieldsList from '../PrepareFieldsList';

describe('PrepareFieldsList Component', () => {
  let wrapper;

  function createMatchMedia(width) {
    return (query) => ({
      matches: mediaQuery.match(query, {
        width,
      }),
      addListener: () => {},
      removeListener: () => {},
    });
  }

  beforeAll(() => {
    window.matchMedia = createMatchMedia(window.innerWidth);
  });

  const defaultProps = {
    customFields: [
      {
        data: null,
        id: 'fieldId',
        name: '',
        required: false,
        value: 'test',
      },
    ],
  };

  beforeEach(() => {
    jest.spyOn(SessionStore, 'getSession').mockReturnValue({
      hasFeature: () => true,
    });
    wrapper = shallow(<PrepareFieldsList {...defaultProps} />);
  });

  ...

  it('should render CustomFieldButton and CustomFields when hasFeature is true', () => {
    expect(wrapper.find(CustomFieldButton)).toHaveLength(1);
    expect(wrapper.find(CustomFields)).toHaveLength(1);
  });
});

reactjs material-ui enzyme
3个回答
0
投票

我认为这是因为 innerWidth 没有在 window 中定义,你需要手动设置它的值,所以你可以在 createMatchMedia 中传递值,如:createMatchMedia(1000) 或将值设置为 window.innerWidth,如下所示:

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

在你的例子中会是这样的:

 beforeAll(() => {
    Object.defineProperty(window, 'innerWidth', {writable: true, configurable: true, value: 500})
    window.matchMedia = createMatchMedia(window.innerWidth);
  });

0
投票

我想通了。在 Enzyme 中执行此操作时,您需要使用 jest 来模拟钩子及其返回值。

在测试文件的顶部:

import useMediaQuery from '@material-ui/core/useMediaQuery';

文件顶部的模拟,导入下方:

jest.mock('@material-ui/core/useMediaQuery');

然后更新模拟值:

useMediaQuery.mockReturnValueOnce(true);

确保在每个测试用例中渲染组件之前执行此操作。所以喜欢:

it('should render ChildComponent when useMediaQuery is true', () => {
    useMediaQuery.mockReturnValueOnce(true);
    const wrapper = shallow(<ParentComponent />);
    expect(wrapper).toContainExactlyOneMatchingElement(ChildComponent);
});

0
投票

我在花了一些时间诊断我的测试后遇到了这个问题,因为我的自定义断点未被识别,所以该测试失败了。最后,我的答案很简单,只需将正在测试的组件包装在 MUI ThemeProvider 中(传递我的主题)即可。否则,我使用文档中的示例来实现 matchMedia (link)。

<ThemeProvider theme={theme}>
  <Component />
<ThemeProvider>
© www.soinside.com 2019 - 2024. All rights reserved.