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.
You're probably wrapping a Router (like a BrowerRouter
or MemoryRouter
) 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
import { BrowserRouter } from 'react-router-dom'
...
render(<BrowserRouter><Login {...loginProps} /></BrowserRouter>);