6

All of my components get data and methods from the Context. I want to test -at least- "component renders" case but of course, when I try to render component in a test case, it cannot find methods/functions and data that come from the Context. I couldn't find a way to pass Context values to a test case using React Testing Library or Jest (I need to use these libraries, no enzyme)

Let's say I want to test a simple Filter component.

Context (primitive usage I guess)

import { useState, useEffect, createContext } from "react";

const Context = createContext();

const ContextProvider = ({ children }) => {
  const [books, setBooks] = useState([]);
  // other data and method code..

  const handleFilter = (value) => {
    const filteredBooks = [...books];
    if (books.length > 0) {
      switch (value) {
        case "alphabetical":
          filteredBooks.sort((a, b) => a.title - b.title);
          setBooks(filteredBooks);
          break;
        case "publishdate":
          filteredBooks.sort(
            (a, b) => b.first_publish_year - a.first_publish_year
          );
          setBooks(filteredBooks);
          break;
        default:
          setBooks(filteredBooks);
      }
    }
  };

  return (
    <Context.Provider value={{ handleFilter }}>
      {children}
    </Context.Provider>
  );
};

export { ContextProvider, Context };

Filter

import { useContext } from "react";
import { Context } from "../context/Context";

function Filter() {
  const { handleFilter } = useContext(Context);

  return (
    <div className="filter" data-testid="filter-test">
      <div className="filter-content">
        <select
          defaultValue="none"
          className="filter-btn"
          onChange={(e) => handleFilter(e.target.value)}
        >
          <option value="none" defaultValue disabled>
            Filter Results
          </option>
          <option value="alphabetical">Alphabetically</option>
          <option value="publishdate">Publish Date (newest)</option>
        </select>
      </div>
    </div>
  );
}

export default Filter;

Filter.test.js

import { render, screen, cleanup } from '@testing-library/react';
import Filter from './Filter';

test('renders Filter component without crashing', () => {
  // I need to pass handleFilter function using Context somehow
  render(<Filter />);
  const filterComponent = screen.getByTestId('filter-test');
  expect(filterComponent).toBeInTheDocument();
});

If you want to see all code: https://codesandbox.io/s/inspiring-bhaskara-0s98g

1

2 Answers 2

8

The simple way of doing this is by passing your context provider as a wrapper of the first argument of render():

import { render, screen, cleanup } from '@testing-library/react';
import Filter from './Filter';

// import your context; it will include the provider
import { Context } from "../context/Context";

test('renders Filter component without crashing', () => {
  const contextValue = { handleFilter: () => {} };
  render(
    <Context.Provider value={contextValue}>
      <Filter />
    </Context.Provider>
  );

  const filterComponent = screen.getByTestId('filter-test');
  expect(filterComponent).toBeInTheDocument();
});

The other way is to provide your context as a wrapper to the render:

import { render, screen, cleanup } from '@testing-library/react';
import Filter from './Filter';

// import your context; it will include the provider
import { Context } from "../context/Context";

test('renders Filter component without crashing', () => {
  const contextValue = { handleFilter: () => {} };
  const wrapper = ({ children }) => (
    <Context.Provider value={contextValue}>
      {children}
    </Context.Provider>
  );

  render(<Filter />, { wrapper });

  const filterComponent = screen.getByTestId('filter-test');
  expect(filterComponent).toBeInTheDocument();
});

Either of the above two ways should work

Sign up to request clarification or add additional context in comments.

2 Comments

Which one is better do you think?
I prefer the first one, it's a bit more direct
0

The easiest way is to add an object as second parameter of the render method. You assign your Context Provider component as the value if that object wrapper property like this :

render(<MyComponent />,{ wrapper: ContextProvider})

Here is a blog post that explain well how to that correctly : How to test React Components depending on the Context API

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.