Replies: 6 comments
-
🤔Something like this? MockNextContext
import React from 'react'
import PropTypes from 'prop-types'
export default class MockNextContext extends React.Component {
static propTypes = {
headManager: PropTypes.object,
router: PropTypes.object
}
static childContextTypes = {
headManager: PropTypes.object,
router: PropTypes.object
}
getChildContext () {
const { headManager, router } = this.props
return {
headManager: {
updateHead() {},
...headManager
},
router: {
asPath: "/",
route: "/",
pathname: "/",
query: {},
// TODO: Properly mock the following methods
back() {},
beforePopState() {},
prefetch() {},
push() {},
reload() {},
replace() {},
events: {
// TODO: Implement EventEmitter
on () {},
off () {},
trigger() {}
},
...router
}
}
}
render () {
return this.props.children
}
} Usage<MockNextContext>
<YourComponentTree/>
<MockNextContext> or <MockNextContext router={{ pathname: "/about", route: "/about", asPath: "/about" }}>
<YourComponentTree/>
<MockNextContext> |
Beta Was this translation helpful? Give feedback.
-
Yes, that'd be an easy to use and flexible solution. |
Beta Was this translation helpful? Give feedback.
-
Edit: This comment is now deprecated:
|
Beta Was this translation helpful? Give feedback.
-
The provided answers didn't really help me. I created a folder besides my ├── node_modules
├── __mocks__
│ ├─ next
│ └── router.js And then mocked the method: module.exports = {
withRouter: component => {
component.defaultProps = {
...component.defaultProps,
router: { pathname: 'mocked-path' }
}
return component
}
} And just mocked the |
Beta Was this translation helpful? Give feedback.
-
If you want to test logic based on values depending on the router (say you have logic related to // (In your the test file of the `<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 />);
} Because this is async and it uses dynamic import it might not be the most elegant solution out there but until there's a better way of doing it, it does the job and on my machine it clocked around 7-10 ms to run tests with it (way cheaper than snapshot testing). So it is not even slowing down your tests. |
Beta Was this translation helpful? Give feedback.
-
A closely related issue I'm having is previewing Next.js components in Storybook which render
The workaround I came to which feels least hacky is using a custom context to pass // LinkContext.tsx
import React from 'react';
import { LinkProps } from 'next/link';
/**
* Stub implementation of Link used by default if this context is consumed without a provider.
* This will _not_ work in a Next.js application, but is useful as a default in tests/previews.
*/
const StubLink: React.FC<LinkProps> = ({ children, href }) =>
React.cloneElement(React.Children.only(children) as any, { href });
/**
* React Context enabling components to use a <Link> component provided by an ancestor component,
* rather than directly from 'next/link'. This is useful when testing or previewing components
* (e.g. using Storybook), as importing 'next/link' directly results in errors such as:
*
* Uncaught Error: No router instance found.
* You should only use "next/router" inside the client side of your app.
*/
const LinkContext = React.createContext<{ Link: React.ComponentType<LinkProps> }>({
Link: StubLink,
});
export default LinkContext; // _app.tsx
import { AppProps } from 'next/app';
import Link from 'next/link';
const MyApp: React.FC<AppProps> = ({ Component, pageProps }) => {
return (
<LinkContext.Provider value={{ Link }}>
<Component {...pageProps} />
</LinkContext.Provider>
);
};
export default MyApp; Usage example: import LinkContext from './LinkContext';
const MyComponent: React.FC = () => {
const { Link } = useContext(LinkContext);
return (
<div>
<Link href="/example">
<a>Example</a>
</Link>
</div>
);
}; |
Beta Was this translation helpful? Give feedback.
-
Mock
withRouter
What we need
An easy way to mock
withRouter
and other context related stuff.What it currently breaks
If you create a component utilizing
withRouter
, you're not able to render it on its own any longer, as it's dependent on a global context.This mainly breaks:
storyboard
orreact cosmos
.Trying to work around it
A simple, manual mock for example via:
will throw an error (
TypeError: Cannot set property
), like this one babel/babel#8363.This is a related issue, where this approach was suggested: #1827
This suggestion (#1827 (comment)) is a monstrosity for a simple thing. And as the author, @ssylvia, correctly remarked - relies on the legacy context API. But i will use it in the meantime.
What i'd like
Some way to replace the whole Next context or pieces of it, without having to know how Next is creating and providing context internally.
Beta Was this translation helpful? Give feedback.
All reactions