使用Vitest与Storybook进行快照测试时,如何Mock SVG组件?
解决Vitest快照测试中SVG组件导入的Mock问题
你遇到的错误核心是SVG组件的Mock未正确生效,导致React无法识别导入的ReactComponent类型。以下是具体的修复方案:
问题根源
你的代码存在三个关键问题:
- Mock执行时机太晚:在导入Story并初始化组件后才执行
vi.mock,此时组件已经加载,Mock没有生效 - ReactComponent的Mock值错误:返回的字符串
'div'不是合法的React组件类型,React需要的是函数/类组件 - 路径匹配规则不正确:
@assets/*的通配符写法无法精准匹配SVG文件路径
修复步骤
1. 调整Mock代码的位置与写法
将vi.mock移到所有依赖导入之前,并修正ReactComponent的返回值,使用正则匹配SVG文件:
import React from 'react'; import { render } from '@testing-library/react'; import '@testing-library/jest-dom/extend-expect'; import { composeStories } from '@storybook/testing-react'; import { vi } from 'vitest'; // 必须在导入stories和组件前执行Mock vi.mock(/@assets\/.*\.svg$/, () => { return { // 处理默认导入(如果组件中使用了import ECDLogo from '@assets/ecd_logo.svg') default: 'mock-svg-url', // 处理SVGR生成的ReactComponent命名导入,返回一个简单的React组件 ReactComponent: () => <div data-testid="mock-svg" />, }; }); // 现在再导入Story并初始化 import * as stories from './Nav.stories'; const { NavDefault } = composeStories(stories); describe('Nav Component', () => { test('it should match the snapshot', () => { const { asFragment } = render(<NavDefault />); expect(asFragment()).toMatchSnapshot(); }); });
2. 确保Vitest配置支持路径别名与SVGR(可选)
如果测试中仍存在路径解析问题,可在vitest.config.ts中同步Vite的配置:
import { defineConfig } from 'vitest/config'; import react from '@vitejs/plugin-react'; import svgr from 'vite-plugin-svgr'; import tsconfigPaths from 'vite-tsconfig-paths'; import path from 'path'; export default defineConfig({ plugins: [react(), svgr(), tsconfigPaths()], resolve: { alias: { '@': path.resolve(__dirname, './src'), '@assets': path.resolve(__dirname, './src/assets'), }, }, test: { environment: 'jsdom', // 必须配置jsdom环境用于React组件测试 }, });
说明
- 提前执行Mock:Vitest的
vi.mock是提升到模块顶部执行的,但显式放在导入前更直观,避免依赖执行顺序问题 - 合法的组件Mock:返回的
() => <div />是标准的React函数组件,能被正常渲染,同时保证快照的一致性 - 精准路径匹配:正则
/@assets\/.*\.svg$/会匹配所有@assets目录下的SVG文件,避免误匹配其他资源
内容的提问来源于stack exchange,提问作者TheKearnol
相关产品推荐
相关产品推荐

