skip to Main Content

My React app has an Item component that should redirect users to the App component by clicking a button inside a react-router-dom Link component. I’ve followed lots of tutorials that have given clear examples of how to implement Link inside components that don’t pass props. My guts tell me that my Item component props might be causing the Cannot destructure property 'basename' of 'React__namespace.useContext(...)' as it is null.] error because running tests on Jest are only possible when Link is not present in the code.

What I tried

  • Moved the RouteSwitch code to index.js
  • Moved the scripts that live in the components to src
  • Double-checked that I followed the tutorials correctly
  • Saw if this reactjs – Uncaught TypeError StackOverFlow answer is related to my problem

Can anybody point out what I’m missing here please?

item.js

import { Link } from "react-router-dom";

const Item = ({info},{addCart}) => {

  return(
    <>
      <Link to="/" ><button>X</button></Link>
      <img src={info.pic} alt={info.title}></img>
      <h1>{info.title}</h1>
      <p>{info.description}</p>
      <button onClick={()=>{addCart(info)}}>Add</button>
    </>
  )
};

export default Item;

routeswitch.js

import React from "react";
import { BrowserRouter,Routes,Route } from "react-router-dom";
import App from "./App"

const RouteSwitch = () =>{
  return(
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<App/>}/>
      </Routes>
    </BrowserRouter>
  );
}

export default RouteSwitch;

index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import RouteSwitch from "./routeswitch"
import './index.css';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <RouteSwitch/>
  </React.StrictMode>
);

item.test.js

import React from 'react';
import { render, cleanup,screen, getByAltText} from '@testing-library/react';
import '@testing-library/jest-dom'
import userEvent from '@testing-library/user-event';
import Item from './item';

afterEach(cleanup);
const details = {pic: `a pic`, title:`a title`, description:`a description`}
const addCartMock =jest.fn(); 

test(`Content renders`,()=>{
  render(<Item info={details} addCart={addCartMock}/>);

  const image = screen.getByAltText(`${details.title}`);
  expect(image).toBeInTheDocument();
  expect(image).toHaveAttribute(`src`,`${details.pic}`);
  expect(screen.getByRole(`heading`, {name:details.title})).toBeInTheDocument();
  expect(screen.getByText(`${details.description}`)).toBeInTheDocument();
  expect(screen.getByRole(`button`, {name: `Add`})).toBeInTheDocument();
});

test(`Add button click event`,()=>{
  render(<Item info={details} addCart={addCartMock(details)}/>);

  userEvent.click(screen.getByRole(`button`), {name: `Add`});
  expect(addCartMock).toHaveBeenCalledWith(details);
});

2

Answers


  1. The issue with the Link in the unit tests is that it requires a routing context to be provided to it. Import the MemoryRouter and render the component into it so the Link component has a routing context available to it.

    Example:

    import React from 'react';
    import { render, cleanup, screen, getByAltText } from '@testing-library/react';
    import '@testing-library/jest-dom';
    import userEvent from '@testing-library/user-event';
    import { MemoryRouter } from 'react-router-dom';
    import Item from './item';
    
    afterEach(cleanup);
    
    const details = {
      pic: "a pic",
      title: "a title",
      description: "a description",
    };
    const addCartMock = jest.fn(); 
    
    test("Content renders", () => {
      render(
        <MemoryRouter>
          <Item info={details} addCart={addCartMock} />
        </MemoryRouter>
      );
    
      const image = screen.getByAltText(`${details.title}`);
      expect(image).toBeInTheDocument();
      expect(image).toHaveAttribute("src",`${details.pic}`);
      expect(screen.getByRole("heading", { name: details.title })).toBeInTheDocument();
      expect(screen.getByText(`${details.description}`)).toBeInTheDocument();
      expect(screen.getByRole("button", { name: `Add` })).toBeInTheDocument();
    });
    
    test("Add button click event", () => {
      render(
        <MemoryRouter>
          <Item info={details} addCart={() => addCartMock(details)} />
        </MemoryRouter>
      );
    
      userEvent.click(screen.getByRole("button"), { name: "Add" });
      expect(addCartMock).toHaveBeenCalledWith(details);
    });
    

    You’ve also an issue accessing the props object in the Item component. There is only a single props object passed to React components and all props are destructured from it.

    const Item = ({ info, addCart }) => {
      return (
        <>
          <Link to="/"><button>X</button></Link>
          <img src={info.pic} alt={info.title} />
          <h1>{info.title}</h1>
          <p>{info.description}</p>
          <button onClick={()=>{addCart(info)}}>Add</button>
        </>
      );
    };
    
    Login or Signup to reply.
  2. Not sure if it’s what is causing the challenge, but in your item.js you are destructuring the props wrongly. you can either desructure it directly, or take the props and use dot notations to get its children:

    const Item = ({info, addCart}) => {
    
      return(
        <>
          // rest of your code
        </>
      )
    };
    

    OR

    const Item = (props) => {
    
      return(
        <>
          <Link to="/" ><button>X</button></Link>
          <img src={props.info.pic} alt={props.info.title}></img>
          <h1>{props.info.title}</h1>
          <p>{props.info.description}</p>
          <button onClick={()=>{props.addCart(info)}}>Add</button>
        </>
      )
    };
    

    OR

    const Item = (props) => {
      const {info, addCart} = props
      return(
        <>
          <Link to="/" ><button>X</button></Link>
          <img src={info.pic} alt={info.title}></img>
          <h1>{info.title}</h1>
          <p>{info.description}</p>
          <button onClick={()=>{addCart(info)}}>Add</button>
        </>
      )
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search