Next.js项目中Storybook如何为每个Story单独Mock模块?
解决Next.js+Storybook中单个Story的模块Mock问题
方案1:手动修改require.cache实现模块Mock
不需要额外插件,直接在单个Story文件里修改Node.js的模块缓存,覆盖目标模块的导出,完全自定义Mock逻辑:
// 你的组件文件(比如ColorComponent.js) import randomColor from "randomcolor"; export const ColorComponent = () => { const color = randomColor(); return <div style={{ backgroundColor: color }}>Colored Box</div>; };
// 对应的Story文件(ColorComponent.stories.js) import { ColorComponent } from "./ColorComponent"; // 保存原始模块引用,避免影响其他Story let originalRandomColor; export default { title: "ColorComponent", component: ColorComponent, }; // 单个Mock的Story export const MockedFixedColor = () => { // 覆盖randomcolor模块的导出 originalRandomColor = require.cache[require.resolve("randomcolor")]; require.cache[require.resolve("randomcolor")] = { ...originalRandomColor, exports: { default: () => "#123456", // 自定义Mock返回值 }, }; return <ColorComponent />; }; // 组件卸载后恢复原始模块,防止污染其他Story MockedFixedColor.parameters = { docs: { story: { afterRender: () => { if (originalRandomColor) { require.cache[require.resolve("randomcolor")] = originalRandomColor; originalRandomColor = null; } }, }, }, };
方案2:用mock-require库简化动态Mock
这个库封装了模块Mock的逻辑,操作更简洁,支持单个Story的独立Mock:
- 先安装依赖:
npm install mock-require --save-dev
- 在Story中使用:
import mockRequire from "mock-require"; import { ColorComponent } from "./ColorComponent"; export default { title: "ColorComponent", component: ColorComponent, }; export const MockedWithLibrary = () => { // Mock randomcolor模块 mockRequire("randomcolor", () => "#123456"); // 重新加载组件,确保使用Mock后的模块 const { ColorComponent: MockedComponent } = mockRequire.reRequire("./ColorComponent"); return <MockedComponent />; }; // 清理Mock,恢复原始模块 MockedWithLibrary.parameters = { docs: { story: { afterRender: () => { mockRequire.stop("randomcolor"); }, }, }, };
方案3:针对React内置Hook的Mock(比如useMemo)
如果是MockReact内置Hook(如useMemo),可以用Storybook环境自带的jest.spyOn实现:
import React, { useMemo } from "react"; import { ComponentUsingUseMemo } from "./ComponentUsingUseMemo"; export default { title: "ComponentUsingUseMemo", component: ComponentUsingUseMemo, }; export const MockedUseMemoBehavior = () => { // Spy并Mock useMemo,强制同步执行回调 const originalUseMemo = useMemo; jest.spyOn(React, "useMemo").mockImplementation((fn) => fn()); return <ComponentUsingUseMemo />; }; // 恢复原始Hook,避免影响其他Story MockedUseMemoBehavior.parameters = { docs: { story: { afterRender: () => { React.useMemo.mockRestore(); }, }, }, };
关键注意事项
- 所有Mock操作必须在Story结束后恢复原始模块/Hook,否则会污染全局运行环境,导致其他Story出现异常。
- 针对Next.js的SSG/SSR相关模块,要确保Mock逻辑在组件渲染前执行,避免模块提前加载导致Mock失效。
内容的提问来源于stack exchange,提问作者Ahmed fouad
相关产品推荐
相关产品推荐

