skip to Main Content

Can anyone help with my tests for a React App with Redux store. I based my project on the counter Redux example app which cam with the below App.test.js file.

import React from 'react';
import { render } from '@testing-library/react';
import { Provider } from 'react-redux';
import { store } from './app/store';
import App from './App';

test('renders learn react link', () => {
  const { getByText } = render(
    <Provider store={store}>
      <App />
    </Provider>
  );

  expect(getByText(/learn/i)).toBeInTheDocument();
 });

When I run the test it gives the error:

TypeError: Cannot destructure property ‘basename’ of
‘React__namespace.useContext(…)’ as it is null.

I think this is because my app is getting data from Reddit API so nothing in store until this data is returned.

The above App.test.js test works on the Redux example project which I think is because the store in that example has fixed values to begin with.

App.js

import React from 'react';
import { Routes, Route } from 'react-router-dom';
import './App.css';
import Header  from './features/Header/Header';
import { Posts } from './features/Posts/Posts';
import { SubReddit } from './features/Subreddit/SubReddit';
import { Comments } from './features/Comments/Comments';
import Footer  from './features/Footer/Footer';

function App() {
  return (
    <div>
      <Header />
      <div className='homePage'>
        <SubReddit />
        <Routes>
          <Route path="/" element={<Posts />} />
          <Route path="/Comments" element={<Comments />} />
        </Routes>
      </div>
      <Footer />
    </div>
  );
}

export default App;

store.js

import { configureStore } from '@reduxjs/toolkit';
import postsReducer from '../features/Posts/postsSlice';
import subRedditReducer from 
'../features/Subreddit/subRedditSlice';
import commentsReducer from '../features/Comments/commentsSlice';

export const store = configureStore({ 
  reducer: {
    posts: postsReducer,
    subReddits: subRedditReducer,
    comments: commentsReducer
  },
});

2

Answers


  1. It looks like it’s related to the usage of react-router-dom.

    If you wanna use <Routes>, your <App> should be wrapped in a Router, like <BrowserRouter/>, like so :

    import { BrowserRouter } from 'react-router-dom'
    
    render(
      <BrowserRouter>
        <App />
      </BrowserRouter>,
      document.getElementById('root')
    )
    

    See : https://stackoverflow.com/a/75728680/1489088

    Also : https://reactrouter.com/en/main/router-components/browser-router

    Login or Signup to reply.
  2. It appears that App is rendering some components that require a routing context that is provided by one of the react-router-dom router components. App works in your regular code because you are likely wrapping it in a router, but in the unit test it is not.

    Generally in non-DOM environments, like Node.js, where you are running your tests you can’t, or shouldn’t, use the BrowserRouter. In unit testing you can use the MemoryRouter.

    A <MemoryRouter> stores its locations internally in an array. Unlike
    <BrowserHistory> and <HashHistory>, it isn’t tied to an external
    source, like the history stack in a browser. This makes it ideal
    for scenarios where you need complete control over the history stack,
    like testing
    .

    Example:

    import React from 'react';
    import { render } from '@testing-library/react';
    import { Provider } from 'react-redux';
    import { MemoryRouter } from 'react-router-dom';
    import { store } from './app/store';
    import App from './App';
    
    test('renders learn react link', () => {
      const { getByText } = render(
        <Provider store={store}>
          <MemoryRouter>
            <App />
          </MemoryRouter>
        </Provider>
      );
    
      expect(getByText(/learn/i)).toBeInTheDocument();
    });
    

    If you need to specify being on any specific route then use the initialEntries and initialIndex props. For example, if you had an App test that needed to be on the "/comments" path use the following:

    <MemoryRouter initialEntries={["/", "/comments"]}>
      ...
    </MemoryRouter>
    

    FWIW I don’t see where App is rendering a link with the text "learn", so I suspect you are testing too much in this specific test. I suspect the "learn" link is rendered in the Header and should probably be tested with that component’s unit testing.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search