首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >用Jest模拟NextJS路由器事件

用Jest模拟NextJS路由器事件
EN

Stack Overflow用户
提问于 2021-09-09 23:15:17
回答 3查看 18.3K关注 0票数 8

我试图用Jest来模拟NextJS路由器事件。在NextJS路由器& Jest找到了相关的资源。那里的实现与我的非常相似。

但是,上面提到的解决办法对我没有用。

我的考试如下:

代码语言:javascript
运行
复制
import { mount, ReactWrapper } from 'enzyme';
import FavoritesPage from 'pages/user/favorites';
import configureStore, { MockStore } from 'redux-mock-store';
import storeInitialState from '__tests__/unit/support/storeInitialState';
import { Provider } from 'react-redux';
import { waitFor } from '@testing-library/react';
import { RequestStates } from 'types/State';
import useAdSetup from 'lib/hooks/useAdSetup';
import { AgeType, PageType } from 'lib/CarGurusAds/TaxonomySchema';

const mockRequestState = RequestStates.Finished;

jest.mock('lib/Auth');
jest.mock('lib/EventLogger');
jest.mock('lib/hooks/useAdSetup');

jest.mock('lib/hooks/useFetchFavorites', () => {
  return (): { requestState: RequestStates } => {
    return {
      requestState: mockRequestState,
    };
  };
});

jest.mock('next/router');

const mockStore = configureStore();

let store: MockStore;

describe('when clicking the price drop subnav button', () => {
  let component: ReactWrapper;

  beforeEach(async () => {
    store = mockStore(storeInitialState);
    await waitFor(() => {
      component = mount(
        <Provider store={store}>
          <FavoritesPage />
        </Provider>
      );
    });
    component.find('.price-drop-nav-item').simulate('click');
  });

  it('shows price drops', () => {
    let eventName;
    let routeChangeHandler;
    let useRouter = jest.fn();

    useRouter.mockImplementation(() => {
      return {
        events: {
          on: jest.fn((event, callback) => {
            eventName = event;
            routeChangeHandler = callback;
          }),
          off: jest.fn((event, callback) => {
            eventName = event;
            routeChangeHandler = callback;
          }),
        },
      };
    });
  
    expect(useRouter).toHaveBeenCalledTimes(1);
    expect(component.find('.price-drop-nav-item').hasClass('active')).toBeTruthy();
  });
});

在内部,与引用的示例一样,我的组件有以下内容:

代码语言:javascript
运行
复制
  useEffect(() => {
    const handleComplete: any = async (url: string) => {
      if (window) {
        await trackReturnToSeachClick(url);
      }
    };
    router.events.on('routeChangeComplete', handleComplete);
    router.events.on('routeChangeError', handleComplete);

    // Cleanup event listeners
    return (): void => {
      router.events.off('routeChangeComplete', handleComplete);
      router.events.off('routeChangeError', handleComplete);
    };
  }, [router]);

与引用的示例不同的是,当我运行代码时,仍然会得到以下错误:

代码语言:javascript
运行
复制
TypeError: Cannot read property 'on' of undefined

我遗漏了什么?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2021-09-10 01:47:05

我在网上找到了一堆相关的样本。就NextJS 11而言,最有用的是vercel/next.js的线程。在此基础上,我提出了以下工作解决方案:

代码语言:javascript
运行
复制
jest.mock('next/router', () => ({
  useRouter() {
    return ({
      route: '/',
      pathname: '',
      query: '',
      asPath: '',
      push: jest.fn(),
      events: {
        on: jest.fn(),
        off: jest.fn()
      },
      beforePopState: jest.fn(() => null),
      prefetch: jest.fn(() => null)
    });
  },
}));

const mockStore = configureStore();

let store: MockStore;

describe('when clicking the price drop subnav button', () => {
  let component: ReactWrapper;
  
  beforeEach(async () => {
    store = mockStore(storeInitialState);

    const useRouter = jest.spyOn(require("next/router"), "useRouter");

    useRouter.mockImplementation(() => ({
      route: '/',
      pathname: '',
      query: '',
      asPath: '',
      push: jest.fn(),
      events: {
        on: jest.fn(),
        off: jest.fn()
      },
      beforePopState: jest.fn(() => null),
      prefetch: jest.fn(() => null)
    }));

    component = mount(
        <Provider store={store}>
          <FavoritesPage />
        </Provider>
    );
    component.find('.price-drop-nav-item').simulate('click');
  });

  it('shows price drops', () => {
  
    // expect(useRouter).toHaveBeenCalledTimes(1);
    expect(component.find('.price-drop-nav-item').hasClass('active')).toBeTruthy();
  });
});

没有什么对我有用的。expect(useRouter).toHaveBeenCalledTimes(1)的测试也不起作用。:)

票数 21
EN

Stack Overflow用户

发布于 2022-09-23 15:51:03

首先,你嘲笑useRouter。

代码语言:javascript
运行
复制
jest.mock('next/router', () => ({
  userRouter: jest.fn()
})

然后,将返回值添加到模拟中。我们需要events.on和events.off,所以我们会把它还回去。

代码语言:javascript
运行
复制
test('some test', () => {
  useRouter.mockReturnValue({
    events: {
      on: () => {},
      off: () => {},
    }
  })
  render(<SomeComponent />)
  expect(useRouter).toHaveBeenCalled()
})

就这样。在on方法中添加模拟函数是没有用的:on: jest.fn(),因为您无法访问它们。所以虚拟函数() => {}就可以了。如果您想测试是否用正确的值调用events.on,请执行以下操作:

代码语言:javascript
运行
复制
jest.mock('next/router', () => ({
  useRouter: jest.fn()
}))

const mockOn = jest.fn()

test('some test', () => {
  useRouter.mockReturnValue({
    events: {
      on: mockOn,
      off: () => {},
    }
  })
  render(<SomeComponent />)
  expect(useRouter).toHaveBeenCalled()
  expect(mockOn).toHaveBeenCalled()
  expect(mockOn).toHaveBeenCalledWith('some event', expect.any(Function))
})

我写了更多关于在dev.to上的一篇文章中嘲弄next/路由器的文章。

票数 0
EN

Stack Overflow用户

发布于 2022-09-30 21:19:22

我只是把它放在测试文件的顶层,然后再调用describe

代码语言:javascript
运行
复制
jest.mock('next/router', () => ({
  useRouter() {
    return {
      pathname: '',
      // ... whatever else you you call on `router`
    };
  },
}));
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69125633

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档