Reputation: 368
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
Upvotes: 6
Views: 10821
Reputation: 41
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
Upvotes: 0
Reputation: 844
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
Upvotes: 8