用 Jest 模拟 NextJS 路由事件
Mocking NextJS router events with Jest
我正在尝试用 Jest 模拟 NextJS 路由器事件。在 NextJS router & Jest 找到相关资源。那里的实现和我的非常相似。
但是,那里提到的解决方案对我不起作用。
我的测试如下:
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();
});
});
在内部,我的组件就像引用的示例一样具有以下内容:
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]);
与引用示例不同,当我 运行 我的代码时,我仍然收到以下错误:
TypeError: Cannot read property 'on' of undefined
我错过了什么?
在网上找了一堆相关的样本。就 NextJS 11 而言,最有用的是 vercel/next.js 处的线程。基于此,我能够将以下工作解决方案放在一起:
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)
的测试也不起作用。 :)
我正在尝试用 Jest 模拟 NextJS 路由器事件。在 NextJS router & Jest 找到相关资源。那里的实现和我的非常相似。
但是,那里提到的解决方案对我不起作用。
我的测试如下:
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();
});
});
在内部,我的组件就像引用的示例一样具有以下内容:
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]);
与引用示例不同,当我 运行 我的代码时,我仍然收到以下错误:
TypeError: Cannot read property 'on' of undefined
我错过了什么?
在网上找了一堆相关的样本。就 NextJS 11 而言,最有用的是 vercel/next.js 处的线程。基于此,我能够将以下工作解决方案放在一起:
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)
的测试也不起作用。 :)