Sorry if this seems really obvious, but I’ve been trying to figure out for two days now. I’m writing a simple unit test in vitest that renders a component to screen and then calling screen.debug()
. The test is
describe('Login unit tests', () => {
it('renders to screen', () => {
const loginProps = {
handleSubmit: (e: MouseEvent<HTMLButtonElement>) => Promise.resolve(console.log('handleSubmit')),
usernameProps: {
value: "",
placeholder: "Username",
onChange: (e: ChangeEvent<HTMLInputElement>) => console.log('changeEvent'),
type: "text"
},
passwordProps: {
value: "",
placeholder: "Password",
onChange: (e: ChangeEvent<HTMLInputElement>) => console.log('changeEvent'),
type: "password"
},
isHidden: true,
}
render(<Login {...loginProps} />);
screen.debug();
})
})
The function definitions are just stand-ins with correct type, but would most likely be a vi.fn()
. The component definition including interface of prop object is
interface LoginProps {
handleSubmit: (e: MouseEvent<HTMLButtonElement>) => Promise<void>,
usernameProps: InputProps,
passwordProps: InputProps,
isHidden: boolean,
}
const Login = ({
handleSubmit,
usernameProps,
passwordProps,
isHidden
}: LoginProps) => {
return (
<div className="login-container">
<div className="login-bounding-box">
<div className="login-title">Login</div>
<form className="login-form">
<input {...usernameProps} />
<input {...passwordProps} />
<button type="submit" onClick={handleSubmit}>Login</button>
</form>
<div className="error-msg" hidden={isHidden}>Username/password incorrect.</div>
<div className="signup-msg">
Don't have an account? Sign up <Link to="/signup">here</Link>.
</div>
</div>
</div>
)
}
After running npm run test
I get the following error:
TypeError: Cannot destructure property 'basename' of 'React__namespace.useContext(...)' as it is null.
❯ LinkWithRef node_modules/react-router-dom/index.tsx:427:11
❯ renderWithHooks node_modules/react-dom/cjs/react-dom.development.js:16305:18
❯ updateForwardRef node_modules/react-dom/cjs/react-dom.development.js:19226:20
❯ beginWork node_modules/react-dom/cjs/react-dom.development.js:21636:16
❯ beginWork$1 node_modules/react-dom/cjs/react-dom.development.js:27426:14
❯ performUnitOfWork node_modules/react-dom/cjs/react-dom.development.js:26560:12
❯ workLoopSync node_modules/react-dom/cjs/react-dom.development.js:26466:5
❯ renderRootSync node_modules/react-dom/cjs/react-dom.development.js:26434:7
❯ recoverFromConcurrentError node_modules/react-dom/cjs/react-dom.development.js:25850:20
❯ performConcurrentWorkOnRoot node_modules/react-dom/cjs/react-dom.development.js:25750:22
The interface for InputProps
is
export default interface InputProps {
value: string;
placeholder: string | undefined;
onChange: (e: ChangeEvent<HTMLInputElement>) => void;
type: string;
}
I know the error is coming from the render(<Login />)
line, but the error is cryptic and I’m not sure how to proceed. I assume there’s something wrong with how I’m passing in the props object to <Login />
but I can’t seem to figure out.
2
Answers
Thalles Cezar's answer is correct but just wanted to add for brevity that one usually uses
MemoryRouter
in tests and thatrender
comes with awrapper
option so the problem can be fixed by changing toYou’re probably wrapping a Router (like a
BrowerRouter
orMemoryRouter
) somewhere in your app.But for the tests, the component is rendered by itself, without the rest of the app.
In that case, it’s missing a Router, that React Router needs to find the
basename
property from its context.Try rendering your test wrapped in a router, like so