开发者问题收集

NextJS useRouter() 在带有 Storybook 插件的单元测试中返回 null

2021-12-10
2450

我在 NextJS 应用中使用 Jest 和 React Testing Library 将故事集成到单元测试中时遇到了问题。在 Storybook 中,我的 NextJS 组件渲染没有问题, Storybook Addon Next Router 工作正常。但是,在我的 Jest 测试文件中,我的测试抛出错误,因为 useRouter() 返回 null。我相信我已经正确设置了所有插件。

我的设置:

问题:

我已根据文档设置了所有文件。故事在 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() 在我的故事中按预期工作,我能够使用它的所有属性,包括 pathnamelocale 。但是,由于某种原因,当 React Testing Library 呈现组合故事时,useRouter() 函数返回 null。

我尝试过的方法:

// 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。任何见解都将不胜感激。

1个回答

我遇到了同样的问题。我通过将 WithNextRouter 导出为 preview.js 上的装饰器解决了该问题。

// preview.js

import { WithNextRouter } from 'storybook-addon-next-router/dist/decorators';

export const decorators = [WithNextRouter];
Jorge Leites
2022-03-24