NextJS useRouter() возвращает null в модульном тестировании с надстройкой Storybook

#jestjs #next.js #react-testing-library #storybook

#jestjs #next.js #react-testing-library #сборник рассказов

Вопрос:

Я столкнулся с проблемой при интеграции моих историй в мои модульные тесты с использованием библиотеки тестирования Jest amp; React в приложении NextJS. В Storybook мои компоненты NextJS отображаются без проблем, при этом дополнение Storybook Next Router работает должным образом. Однако в моем тестовом файле Jest мой тест выдает ошибку, потому что useRouter() возвращает null. Я считаю, что я правильно настроил все дополнения.

Моя настройка:

  • NextJS 12
  • Библиотека тестирования Jest и React
  • Сборник рассказов
  • Дополнение Storybook Next Router (для использования следующего маршрутизатора внутри Storybook)
  • @storybook /testing-реагировать (для интеграции моих историй, аргументов и параметров с библиотекой тестирования)

Проблема:

Я настроил все файлы в соответствии с документами. История отлично отображается внутри Storybook, а useRouter() работает благодаря дополнению Storybook Next. Однако composeStories() функция из @storybook /testing-react, похоже, не может правильно инициализировать следующего поставщика маршрутизатора из первого дополнения. Мой модульный тест завершается ошибкой со следующей ошибкой:

Не удалось запустить
TypeError: не удается прочитать свойство ‘locale’ 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
  });
});
 

И мой файл stories:

 // 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 . Однако по какой-то причине функция useRouter() возвращает null, когда составленная история отображается библиотекой тестирования React.

What I have tried:

 // 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);
 
  • Verified that jest reads my setup file and finds my Storybook preview file
  • Verified both .storybook/preview.js and .storybook/main.js match the usage guide:

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() работают, и когда я консолью.регистрируйте возвращаемое значение useRouter(), я получаю полный набор свойств объекта NextJS useRouter:
 // >> console.log(useRouter()); inside Storybook
{
    route: "/",
    pathname: "/",
    query: {},
    asPath: "/",
    events: {},
    isFallback: false,
    locale: 'en'
}
 
  • Однако в модульном тестировании при регистрации возвращаемого значения useRouter(); внутри моего компонента оно возвращается null . Понятно, что, поскольку оно равно null, { locale } присвоение переменной выдает ошибку в моем модульном тестировании.
  • При регистрации значения useRouter переменной как в моем предварительном просмотре сборника рассказов, так и в моем модульном тестировании я получаю следующую функцию:
 // >> console.log(useRouter.toString())
function useRouter() {
    return _react.default.useContext(_routerContext.RouterContext);
}
 

У кого-нибудь есть идеи о том, что может пойти не так? Я довольно новичок в Storybook, но я пытался просмотреть проблемы GitHub и онлайн и не смог решить. Понятия не имею, почему useRouter() возвращает null внутри Jest, если composeStories() fn должен позаботиться о разрешении моих параметров и аргументов сборника рассказов. Любая информация будет оценена.

Комментарии:

1. можете ли вы проверить, исправляет ли последняя версия storybook-addon-next-router эту проблему для вас? если нет, откройте проблему на GitHub, и я сделаю все возможное, чтобы помочь

Ответ №1:

Я работал с той же проблемой. Я решил это, экспортировав WithNextRouter в качестве декоратора на preview.js

 // preview.js

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

export const decorators = [WithNextRouter];