Jest 测试移动端 React 组件时如何模拟 useMediaQuery?

若彤 阅读 57

我写了个响应式组件,用 useMediaQuery 判断是不是移动端,但在 Jest 里跑测试一直报错说 matchMedia 未定义。试过 mock window.matchMedia,但还是不生效,到底该怎么正确模拟啊?

这是我的组件代码:

import { useState, useEffect } from 'react';

function useMediaQuery(query) {
  const [matches, setMatches] = useState(false);

  useEffect(() => {
    const media = window.matchMedia(query);
    if (media.matches !== matches) setMatches(media.matches);
    const listener = () => setMatches(media.matches);
    media.addEventListener('change', listener);
    return () => media.removeEventListener('change', listener);
  }, [matches, query]);

  return matches;
}

export default function MyComponent() {
  const isMobile = useMediaQuery('(max-width: 768px)');
  return isMobile ? <div>Mobile</div> : <div>Desktop</div>;
}
我来解答 赞 8 收藏
二维码
手机扫码查看
2 条解答
长孙芳芳
通用的做法是手动 mock window.matchMedia,但要注意 Jest 环境里这个方法需要我们自己定义返回值和事件监听。我以前也踩过坑,后来发现要这样写:

在你的测试文件开头加上这段代码:
beforeEach(() => {
window.matchMedia = jest.fn().mockImplementation(query => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // deprecated
removeListener: jest.fn(), // deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn()
}));
});


然后在具体测试用例里根据需要设置 matches 的返回值。比如要模拟移动端环境时:
test('renders mobile content', () => {
window.matchMedia.mockReturnValueOnce({
matches: true,
media: '(max-width: 768px)',
// 其他属性保持不变
});
// 继续写你的渲染和断言逻辑
});


记得要把 matches 设置为 true 来模拟移动端环境,不然默认是 false 哦。这招帮我解决了不少问题,希望也能帮到你。
点赞
2026-03-27 15:08
夏侯甜茜
我之前也遇到过这问题,window.matchMedia 在 JSDOM 里确实没实现。直接在测试文件开头加个全局 mock 就行:

beforeAll(() => {
window.matchMedia = (query) => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // deprecated
removeListener: jest.fn(), // deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
});
});


记得根据你的测试需求修改 matches 返回值。这样就能正常跑测试了。
点赞
2026-03-26 05:00