-
Notifications
You must be signed in to change notification settings - Fork 27k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
jest example fails with next/link
#1827
Comments
Hmm, on the back of this, Note: I tried |
+1. Echoed too on #1204 |
I think we need to fix this bug. On it. |
@arunoda did you get anywhere on this? I don't know how to get around this at all, so my application is currently failing all tests :( |
Not sure if this is related, but I'm getting the same error if I'll try to test container that uses |
Yes. When we use We need to find a way to mock this. import Router from `next/router`
const mockedRouter = { push: () => {} }
Router.router = mockedRouter |
@arunoda that seems to work. Thanks! |
For anyone else landing here trying to make this work with a |
With next 3.x, even without prefetch, |
@kgoggin could you please show your code? did not really understand what you mean by noop and when you put it. |
@kgoggin it seems that I understood. import Router from 'next/router'
const mockedRouter = { push: () => {}, prefetch: () => {} }
Router.router = mockedRouter |
ps when I mock it like this in storybook config for stories to work then I get |
in the end for storybook (not for jest) I mocked it like this in config: const actionWithPromise = () => {
action('clicked link')();
// we need to return promise because it is needed by Link.linkClicked
return new Promise((resolve, reject) => reject());
};
const mockedRouter = {
push: actionWithPromise,
replace: actionWithPromise,
prefetch: () => {},
};
Router.router = mockedRouter; for jest I just have router fully ignored: |
link
next/link
Anybody got advice on mocking I tried |
@kylemh I ran into this and was able to get it working by wrapping the story in a HOC that provides a custom router object in it's context. It looks like next/router relies on the legacy context API so this will probably break in later versions. Here's my mock files: const { Component } = require('react');
const Router = require('next/router').default;
const { action } = require('@storybook/addon-actions');
const PropTypes = require('prop-types');
const actionWithPromise = () => {
action('clicked link')();
return new Promise((resolve, reject) => reject());
};
const mockedRouter = {
push: actionWithPromise,
replace: actionWithPromise,
prefetch: () => {},
route: '/mock-route',
pathname: 'mock-path',
};
Router.router = mockedRouter;
const withMockRouterContext = (mockRouter) => {
class MockRouterContext extends Component {
getChildContext() {
return {
router: Object.assign(mockedRouter, mockRouter),
};
}
render() {
return this.props.children;
}
}
MockRouterContext.childContextTypes = {
router: PropTypes.object,
};
return MockRouterContext;
};
module.exports.mockedRouter = mockedRouter;
module.exports.withMockRouterContext = withMockRouterContext; Then just wrap your story with a MockRouter: import { withMockRouterContext } from 'test-utils/react/nextjs/router';
const MockRouter1 = withMockRouterContext([extendDefaultMockRouter]);
stories.add(
'Default',
() => (
<MockRouter1>
<ActiveLink href="test-active">Test</ActiveLink>
</MockRouter1>
)
); |
@ssylvia looks like @nickluger got a convo going in #5205 Yours worked. I also added a bit more logic and used it as a global decorator so as to not interfere with the Will be migrating to |
…ter" inside the client side of your app. vercel/next.js#1827
Would be good to see this fixed after almost 2 years. This is a barrier to anyone coming to Next.js as they'll bump into this pretty soon when they try to |
thanks @ssylvia, I used a tweaked version of what you suggested: /* tslint:disable */
import { Component } from 'react';
import Router from 'next/router';
import { action } from '@storybook/addon-actions';
import PropTypes from 'prop-types';
const actionWithPromise = () => {
action('clicked link')();
return new Promise((_, reject) => reject());
};
const mockedRouter = {
push: actionWithPromise,
replace: actionWithPromise,
prefetch: () => {},
route: '/mock-route',
pathname: 'mock-path',
};
// @ts-ignore
Router.router = mockedRouter;
const withMockRouterContext = mockRouter => {
class MockRouterContext extends Component {
public getChildContext() {
return {
router: { ...mockedRouter, ...mockRouter },
};
}
public render() {
return this.props.children;
}
}
// @ts-ignore
MockRouterContext.childContextTypes = {
router: PropTypes.object,
};
return MockRouterContext;
};
export const StorybookRouterFix = withMockRouterContext(mockedRouter); Usageimport { StorybookRouterFix } from '/utils/storybook/StoryRouterFix';
// ....
storiesOf('ComponentThatHasALink', module)
.add('ComponentThatHasALink', () => (
<StorybookRouterFix>
<ComponentThatHasALink
/>
</StorybookRouterFix>
)); |
If you only want to show the component without the const Router = {}
const mockedRouter = { push: () => {}, prefetch: () => {} }
Router.router = mockedRouter |
Fixes #1827 This doesn't affect integration tests as they'd use `next build` which forces production mode. Development forces `development`.
Leaving my two cents, based on previous replies:
|
The Edit: found this: #7479 |
Adding to @wilson-alberto-kununu 's example this is what we cooked up in the team when your component's behavior depends on values coming from router values (and why else would you use // (In your the test file of `<Something />` component:
async function createComponent(queryStringParams = {}) {
jest.doMock('next/router', () => ({
withRouter: component => {
component.defaultProps = {
...component.defaultProps,
router: {
pathname: 'something',
query: queryStringParams
},
};
return component;
},
}));
const { Something } = await import('./something'); // 👈 please note the dynamic import
return mount(<Something />);
} |
Example repo: https://github.com/remy/next-examples/tree/master/with-jest#fails-with
The jest example in the examples directory is too simple, so it quickly falls over when I started testing a slightly larger app (than a single page with some jsx).
How do we get snapshot testing to work with next? Can we have jest tell next (somehow???) that
prefetch
shouldn't happen?The text was updated successfully, but these errors were encountered: