如何在Vitest中为每个测试动态设置自定义Hook的模拟返回值?
解决Vitest中自定义Hook单测试用例不同返回值的问题
问题根源
你当前的测试代码在beforeEach中提前渲染了组件,而每个测试用例里设置mock返回值的操作是在组件渲染之后执行的。这导致组件调用useGetStatusPageContent时,mock还未被设置返回值,自然返回undefined。
解决方案
调整测试流程:先设置mock返回值,再渲染组件。同时在beforeEach中重置mock,确保每个测试用例的环境干净无残留。
修改后的代码如下:
import { cleanup, render, screen } from '@testing-library/react' import { beforeEach, describe, expect, test, vi } from 'vitest' import { useGetStatusPageContent } from '../../src/hooks/useGetStatusPageContent' import KycStatusPage from '../../src/pages/KycStatusPage' import { kycTestIds } from '../../testIds' import { AppTestWrapper } from '../components/TestWrappers' vi.mock('@inet-client-management-fe/shared', async (importOriginal) => { const actual = (await importOriginal()) as NonNullable<unknown> return { ...actual, useLoadingScreenContext: () => { return { loadingScreenExpired: false } } } }) const mocks = vi.hoisted(() => { return { useGetStatusPageContent: vi.fn() } }) vi.mock('../../src/hooks/useGetStatusPageContent', () => { return { useGetStatusPageContent: mocks.useGetStatusPageContent } }) describe('KycStatusPage', () => { beforeEach(() => { // 重置mock,清除之前的调用记录和返回值,保证每个测试用例环境干净 mocks.useGetStatusPageContent.mockReset() }) afterEach(cleanup) test('Should display SplashActiveAlert', () => { // 1. 先设置当前测试需要的mock返回值 mocks.useGetStatusPageContent.mockReturnValue({ header: 'STATUS.PROCESSING_HEADER', message: 'STATUS.PROCESSING_MESSAGE', icon: 'info' }) // 2. 再渲染组件,此时组件会使用已设置的mock数据 render( <AppTestWrapper> <KycStatusPage /> </AppTestWrapper> ) expect(screen.getByTestId(kycTestIds.SplashActiveAlert)).toBeInTheDocument() }) test('Should not display SplashActiveAlert', () => { // 1. 先设置当前测试需要的mock返回值 mocks.useGetStatusPageContent.mockReturnValue({ header: 'STATUS.CANT_PROCESS_HEADER', message: 'STATUS.CANT_PROCESS_MESSAGE', icon: 'bank' }) // 2. 再渲染组件 render( <AppTestWrapper> <KycStatusPage /> </AppTestWrapper> ) expect(screen.queryByTestId(kycTestIds.SplashActiveAlert)).not.toBeInTheDocument() }) })
关键调整点
- 移除
beforeEach中的render调用,避免组件提前渲染 - 添加
mockReset()到beforeEach,清除mock的历史状态,防止测试用例间互相干扰 - 每个测试用例严格遵循「设置mock → 渲染组件 → 断言」的顺序
- 直接使用
mocks.useGetStatusPageContent操作mock,无需额外用vi.mocked()包装
内容的提问来源于stack exchange,提问作者Tuyen Thanh
相关产品推荐
相关产品推荐

