You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用React Testing Library测试依赖媒体查询的响应式React组件

问题原因说明

这个问题不是React Testing Library(RTL)特有,本质是Jest默认使用的jsdom运行环境的限制:

  • react-responsive底层依赖浏览器标准window.matchMediaAPI执行媒体查询匹配,而非直接读取window.innerWidth判断
  • jsdom的matchMedia默认实现不会根据当前视口尺寸动态计算查询结果,不管你设置的innerWidth是多少,所有媒体查询默认都会返回不匹配,所以才会走到兜底渲染逻辑。
解决方案

你需要对useMediaQuery进行mock,或者模拟matchMedia的实现,两种常用方案如下:

方案1:直接mock react-responsive的useMediaQuery hook(更简单,推荐)

直接在测试用例中控制不同媒体查询的返回值,不需要关心底层API实现:

// test spec 修改后
import React from 'react'
import Test from './MediaQueryTest'
import { render, screen } from '@testing-library/react'
import { useMediaQuery } from 'react-responsive'

// 全局mock react-responsive库
jest.mock('react-responsive', () => ({
  useMediaQuery: jest.fn(),
}))

it('should render for desktop', () => {
  // 针对当前测试用例设置返回值:桌面查询匹配,移动端查询不匹配
  useMediaQuery.mockImplementation(({ query }) => {
    const DESKTOP_MEDIA_QUERY = 'only screen and (min-width: 1024px)'
    const MOBILE_MEDIA_QUERY = 'only screen and (max-width : 480px)'
    if (query === DESKTOP_MEDIA_QUERY) return true
    if (query === MOBILE_MEDIA_QUERY) return false
    return false
  })

  render(<Test/>)
  expect(screen.getByText('desktop')).toBeInTheDocument()
})

// 移动端测试同理
it('should render for mobile', () => {
  useMediaQuery.mockImplementation(({ query }) => {
    const DESKTOP_MEDIA_QUERY = 'only screen and (min-width: 1024px)'
    const MOBILE_MEDIA_QUERY = 'only screen and (max-width : 480px)'
    if (query === DESKTOP_MEDIA_QUERY) return false
    if (query === MOBILE_MEDIA_QUERY) return true
    return false
  })

  render(<Test/>)
  expect(screen.getByText('mobile')).toBeInTheDocument()
})

注意:mock后组件渲染逻辑完全同步,不需要使用findBy这类异步查询方法,直接用getBy即可。

方案2:mock window.matchMedia (更贴近真实运行逻辑)

如果需要模拟修改视口宽度触发媒体查询变化的场景,可以直接模拟matchMedia的实现:

// 可以放在测试 setup 文件里全局生效
const setMatchMediaMock = (width) => {
  window.matchMedia = jest.fn().mockImplementation(query => {
    // 简单解析媒体查询的宽限规则,可根据自己的查询规则扩展
    const ruleMatch = query.match(/\((min|max)-width\s*:\s*(\d+)px\)/)
    let matches = false
    if (ruleMatch) {
      const [, type, val] = ruleMatch
      matches = type === 'min' ? width >= +val : width <= +val
    }
    return {
      matches,
      addListener: jest.fn(),
      removeListener: jest.fn(),
    }
  })
}

// 测试用例中使用
it('should render for desktop', () => {
  setMatchMediaMock(1024) // 设置视口宽度为1024px
  render(<Test/>)
  expect(screen.getByText('desktop')).toBeInTheDocument()
})

内容的提问来源于stack exchange,提问作者Neil Girardi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 23:27:01