【问题标题】:Jest + Material-UI : Correctly mocking useMediaQueryJest + Material-UI:正确模拟 useMediaQuery
【发布时间】:2019-10-04 10:52:25
【问题描述】:

我在我的一个组件中使用 Material-UI 的 useMediaQuery() 函数来确定用于组件内的 <Button>size 属性。

我正在尝试测试它在开玩笑测试中是否按预期工作,但是我当前的实现不起作用:

describe("Unit: <Navbar> On xs screens", () => {

  // Incorrectly returns `matches` as `false` ****************************
  window.matchMedia = jest.fn().mockImplementation(
    query => {
      return {
        matches: true,
        media: query,
        onchange: null,
        addListener: jest.fn(),
        removeListener: jest.fn()
      };
    }
  );

  it("renders as snapshot", async () => {
    const width = theme.breakpoints.values.sm - 1;
    const height = Math.round((width * 9) / 16);
    Object.defineProperty(window, "innerWidth", {
      writable: true,
      configurable: true,
      value: width
    });
    const { asFragment } = render(
      <Container backgroundColor={"#ffffff"}>
        <Navbar />
      </Container>
    );
    expect(asFragment()).toMatchSnapshot();
    const screenshot = await generateImage({
      viewport: { width, height }
    });
    expect(screenshot).toMatchImageSnapshot();
  });
});

describe("Unit: <Navbar> On md and up screens", () => {

  // Correctly returns `matches` as `false` ****************************
  window.matchMedia = jest.fn().mockImplementation(
    query => {
      return {
        matches: false,
        media: query,
        onchange: null,
        addListener: jest.fn(),
        removeListener: jest.fn()
      };
    }
  );

  it("renders as snapshot", async () => {
    const width = theme.breakpoints.values.md;
    const height = Math.round((width * 9) / 16);
    Object.defineProperty(window, "innerWidth", {
      writable: true,
      configurable: true,
      value: width
    });
    const { asFragment } = render(
      <Container backgroundColor={"#ffffff"}>
        <Navbar />
      </Container>
    );
    expect(asFragment()).toMatchSnapshot();
    const screenshot = await generateImage({
      viewport: { width, height }
    });
    expect(screenshot).toMatchImageSnapshot();
  });
});

以及我正在测试的组件(删除了不相关的部分):

const Navbar = () => {
  const theme = useTheme();
  const matchXs = useMediaQuery(theme.breakpoints.down("xs"));
  return (
    <Button size={matchXs ? "medium" : "large"}>
      Login
    </Button>
  );
};
export default Navbar;

它在第一次测试中以 false 的形式返回 matches,即使我已将其设置为返回 true。我知道这一点是因为它正在生成屏幕截图,并且我可以看到按钮大小设置为large 以进行第一次测试,而它应该设置为medium

它在生产中按预期工作。

如何在开玩笑测试中正确获得模拟 useMediaQuery()

【问题讨论】:

    标签: jestjs material-ui


    【解决方案1】:

    推荐的方法是使用css-mediaquery,现在在the MUI docs中提到:

    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);
      });
    });
    

    【讨论】:

    【解决方案2】:

    我想通了……

    useMediaQuery() 需要重新渲染组件才能工作,因为第一次渲染将返回您在options.defaultMatches 中定义的任何内容(默认为false)。

    此外,模拟需要针对每个测试 (it),而不是 describe

    当我使用 react-testing-library 时,我所要做的就是再次重新渲染组件并更改模拟的范围,然后它就可以工作了。

    下面是工作示例:

    const initTest = width => {
      Object.defineProperty(window, "innerWidth", {
        writable: true,
        configurable: true,
        value: width
      });
      window.matchMedia = jest.fn().mockImplementation(
        query => {
          return {
            matches: width >= theme.breakpoints.values.sm ? true : false,
            media: query,
            onchange: null,
            addListener: jest.fn(),
            removeListener: jest.fn()
          };
        }
      );
      const height = Math.round((width * 9) / 16);
      return { width, height };
    };
    
    describe("Unit: <Navbar> On xs screens", () => {
      it("renders as snapshot", async () => {
        const { width, height } = initTest(theme.breakpoints.values.sm - 1);
        const { asFragment, rerender} = render(
          <Container backgroundColor={"#ffffff"}>
            <Navbar />
          </Container>
        );
        rerender(
          <Container backgroundColor={"#ffffff"}>
            <Navbar />
          </Container>
        );
        expect(asFragment()).toMatchSnapshot();
        const screenshot = await generateImage({
          viewport: { width, height }
        });
        expect(screenshot).toMatchImageSnapshot();
      });
    });
    
    describe("Unit: <Navbar> On md and up screens", () => {
      it("renders as snapshot", async () => {
        const { width, height } = initTest(theme.breakpoints.values.md);
        const { asFragment } = render(
          <Container backgroundColor={"#ffffff"}>
            <Navbar />
          </Container>
        );
        rerender(
          <Container backgroundColor={"#ffffff"}>
            <Navbar />
          </Container>
        );
        expect(asFragment()).toMatchSnapshot();
        const screenshot = await generateImage({
          viewport: { width, height }
        });
        expect(screenshot).toMatchImageSnapshot();
      });
    });
    

    【讨论】:

      猜你喜欢
      • 2020-08-30
      • 1970-01-01
      • 1970-01-01
      • 2019-06-10
      • 2019-07-12
      • 2019-08-04
      • 1970-01-01
      • 1970-01-01
      • 2021-05-22
      相关资源
      最近更新 更多