React测试中Mock渲染Headless UI组件及解决组件渲染为undefined问题
看起来你遇到的核心问题是Headless UI的复合组件(比如Menu和Transition)在测试环境中没有被正确Mock,导致渲染时出现undefined。另外你的测试代码中注释了Redux Provider,这可能也会间接导致依赖Redux的子组件(比如AdvertSwitch)无法正常初始化。下面是一步步的解决方案:
1. 修正Headless UI的Mock结构
你当前的Mock只是简单地spread了真实模块,但Headless UI的组件(比如Menu)是包含子组件(Button、Items、Item)的复合对象,在测试环境下直接引用真实模块可能无法正确初始化这些子组件。需要显式模拟这些复合组件的结构:
jest.mock('@headlessui/react', () => { // 保留真实模块的其他导出(如果需要) const actual = jest.requireActual('@headlessui/react'); return { ...actual, // 模拟Menu复合组件,返回简单的HTML元素作为替代 Menu: { Button: ({ children, ...props }) => <button {...props}>{children}</button>, Items: ({ children, ...props }) => <div {...props}>{children}</div>, Item: ({ children, ...props }) => <div {...props}>{children}</div>, }, // 模拟Transition组件,直接返回子元素(假设测试时不需要动画逻辑) Transition: ({ children }) => { // Transition组件会传递一个包含`open`状态的对象给子元素,这里模拟open为true return children({ open: true, close: jest.fn() }); }, }; });
这样Mock后,AdvertSwitch中的Menu.Button、Menu.Items等就不会是undefined了,而是被替换成了简单的可渲染元素。
2. 恢复Redux Provider的注入
你的测试代码中注释了<Provider store={store}>,如果App或其子组件(比如Dashboard、AdvertSwitch)依赖Redux状态,那么缺少Store会导致组件无法正常渲染,间接引发子组件undefined的问题。请恢复Store的创建和Provider的包裹:
import { rootReducer } from './store'; function renderApp( store = createStore( rootReducer, {}, composeWithDevTools(applyMiddleware(thunk)) ), props = {} ) { return render( <SnackbarProvider> <MemoryRouter> <Provider store={store}> <App {...props} /> </Provider> </MemoryRouter> </SnackbarProvider> ); }
如果不需要完整的DevTools,也可以简化Store创建:
store = createStore(rootReducer, {}, applyMiddleware(thunk))
3. 验证Mock是否生效
在AdvertSwitch中你已经加了console.log({ Menu, Transition }),运行测试时查看控制台输出:
- 如果输出的是你Mock的组件结构(比如
Menu.Button是一个函数组件),说明Mock成功; - 如果还是undefined,检查Mock的路径是否正确(比如
@headlessui/react是否是正确的包名),或者是否有其他地方覆盖了这个Mock。
4. 优化测试断言
最后,为了确保测试有效,建议添加一些断言,比如检查AdvertSwitch中的广告商名称是否被渲染:
test('test render app component with AdvertSwitch', async () => { const { getByText } = renderApp(); // 检查第一个广告商名称是否存在 expect(getByText('advertiser-one')).toBeInTheDocument(); });
这样可以明确验证组件是否正确渲染,而不仅仅是没有报错。
内容的提问来源于stack exchange,提问作者Hasham Minhas

