测试自定义Hook时window未定义引发TypeError的解决方法
解决方法
首先,你的useMediaQuery Hook存在一个潜在问题:在useEffect中直接访问window.matchMedia,但未检查window是否存在。这会导致在服务端渲染或window未定义的环境中直接抛出错误,先修复这个问题:
import React from "react"; import isWindowDefined from "../isWindowDefined"; // 注意:你重复定义了isWindowDefined,建议删除本地定义,直接使用导入的版本 // export const isWindowDefined = () => window !== undefined; const useMediaQuery = (query: string): boolean => { const getMatches = (query: string): boolean => { if (isWindowDefined()) { return window.matchMedia(query).matches; } return false; }; const [matches, setMatches] = React.useState<boolean>(getMatches(query)); const handleChange = () => { setMatches(getMatches(query)); }; React.useEffect(() => { // 添加window存在性检查 if (!isWindowDefined()) return; const matchMedia = window.matchMedia(query); handleChange(); matchMedia.addEventListener("change", handleChange); return () => { matchMedia.removeEventListener("change", handleChange); }; }, [query]); return matches; }; export default useMediaQuery;
接下来,针对window未定义的测试场景,不要直接全局设置window = undefined——这会破坏react-test-renderer内部对window的依赖。更好的方式是模拟isWindowDefined函数返回false,让Hook认为window不存在,但实际保留window供测试库使用。
测试代码示例
假设你的isWindowDefined是单独的模块:
import React from 'react'; import { renderHook } from '@testing-library/react-hooks'; import useMediaQuery from './useMediaQuery'; import isWindowDefined from '../isWindowDefined'; // 模拟isWindowDefined返回false jest.mock('../isWindowDefined', () => () => false); test('当window未定义时返回false', () => { const { result } = renderHook(() => useMediaQuery('(min-width: 768px)')); expect(result.current).toBe(false); });
如果isWindowDefined是在useMediaQuery文件内部定义的,调整mock方式:
import React from 'react'; import { renderHook } from '@testing-library/react-hooks'; import * as useMediaQueryModule from './useMediaQuery'; // 模拟内部的isWindowDefined函数 jest.spyOn(useMediaQueryModule, 'isWindowDefined').mockReturnValue(false); test('当window未定义时返回false', () => { const { result } = renderHook(() => useMediaQueryModule.default('(min-width: 768px)')); expect(result.current).toBe(false); });
为什么不直接mock window?
如果强行全局设置window = undefined,react-test-renderer在执行时会尝试访问window.event等属性,导致抛出你遇到的TypeError。通过模拟isWindowDefined,我们既能验证Hook的 fallback 逻辑,又不会干扰测试库的正常运行。
内容的提问来源于stack exchange,提问作者karvai
相关产品推荐
相关产品推荐

