NextJS useRouter() 在带有 Storybook 插件的单元测试中返回 null
我在 NextJS 应用中使用 Jest 和 React Testing Library 将故事集成到单元测试中时遇到了问题。在 Storybook 中,我的 NextJS 组件渲染没有问题, Storybook Addon Next Router 工作正常。但是,在我的 Jest 测试文件中,我的测试抛出错误,因为 useRouter() 返回 null。我相信我已经正确设置了所有插件。
我的设置:
- NextJS 12
- Jest & React 测试库
- Storybook
- Storybook Addon Next Router (用于在 Storybook 中使用 Next 路由器)
- @storybook/testing-react (用于将我的故事、参数和参数与测试库集成)
问题:
我已根据文档设置了所有文件。故事在 Storybook 中呈现良好,并且 useRouter() 可以正常工作,这要归功于 Storybook Next 插件。但是,@storybook/testing-react 中的
composeStories()
函数似乎无法正确初始化第一个插件中的 Next 路由器提供程序。我的单元测试失败,错误如下:
Test suite failed to run
TypeError: Cannot read property 'locale' of null
并指向我的组件中的以下行:
// Events.tsx
const { locale = 'en' } = useRouter();
这是我的测试文件:
// Events.test.tsx
import React from 'react';
import { render, screen } from '@testing-library/react';
import { composeStories } from '@storybook/testing-react';
import * as stories from './Events.stories'
const { WithSeasonsAndEvents } = composeStories(stories);
describe('Events Screen', ()=> {
render(<WithSeasonsAndEvents />);
it('renders input data', ()=> {
// set up test
});
});
以及我的故事文件:
// Events.stories.tsx
import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import Events from './Events';
export default {
title: 'Events/Events Screen',
component: Events
} as ComponentMeta<typeof Events>;
const Template: ComponentStory<typeof Events> = (args) => <Events {...args} />;
export const WithSeasonsAndEvents = Template.bind({});
WithSeasonsAndEvents.args = {
// many args here
};
这个故事在 Storybook 中呈现良好。useRouter() 在我的故事中按预期工作,我能够使用它的所有属性,包括
pathname
和
locale
。但是,由于某种原因,当 React Testing Library 呈现组合故事时,useRouter() 函数返回 null。
我尝试过的方法:
- 已验证安装 @storybook/testing-react 并在 jest 设置文件中设置我的全局配置:
// jest-setup.ts
import '@testing-library/jest-dom/extend-expect';
import { setGlobalConfig } from '@storybook/testing-react';
// Storybook's preview file location
import * as globalStorybookConfig from './.storybook/preview';
setGlobalConfig(globalStorybookConfig);
- 已验证 jest 读取我的设置文件并找到我的 Storybook 预览文件
- 已验证 .storybook/preview.js 和 .storybook/main.js 均符合用法指南:
preview.js
// .storybook/preview.js
import '../styles/tailwind.css';
import { RouterContext } from "next/dist/shared/lib/router-context"; // next 12 https://storybook.js.org/docs/react/writing-stories/parameters
export const parameters = {
actions: { argTypesRegex: "^on[A-Z].*" },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
nextRouter: {
Provider: RouterContext.Provider,
locale: 'en',
},
}
main.js
// .storybook/main.js
module.exports = {
"stories": [
"../stories/**/*.stories.mdx",
"../stories/**/*.stories.@(js|jsx|ts|tsx)",
"../components/**/*.stories.@(js|jsx|ts|tsx|mdx)"
],
"addons": [
"@storybook/addon-links",
"@storybook/addon-essentials",
"storybook-addon-next-router",
],
"framework": "@storybook/react"
}
- 故事在 Storybook 中呈现良好,所有 useRouter() 功能均可正常工作,当我 console.log useRouter() 返回值时,我获得了完整的 NextJS useRouter 对象属性套件:
// >> console.log(useRouter()); inside Storybook
{
route: "/",
pathname: "/",
query: {},
asPath: "/",
events: {},
isFallback: false,
locale: 'en'
}
-
但是,在单元测试中,在我的组件内记录
useRouter();
的返回值时,它返回null
。可以理解的是,由于它为空,{ locale } 变量赋值在我的单元测试中引发错误。
-
在记录
useRouter
变量的值时,无论是在我的 Storybook 预览中还是在我的单元测试中,我都会得到以下函数:
// >> console.log(useRouter.toString())
function useRouter() {
return _react.default.useContext(_routerContext.RouterContext);
}
有人知道可能出了什么问题吗?我对 Storybook 还很陌生,但我尝试过查看 GitHuB 问题和在线问题,但无法解决。如果
composeStories()
fn 应该负责解决我的 Storybook 参数和参数,我不知道为什么
useRouter()
在 Jest 中返回 null。任何见解都将不胜感激。
我遇到了同样的问题。我通过将
WithNextRouter
导出为
preview.js
上的装饰器解决了该问题。
// preview.js
import { WithNextRouter } from 'storybook-addon-next-router/dist/decorators';
export const decorators = [WithNextRouter];