To test React context components, wrap them in their provider inside the test. A component that reads context needs a provider above it, and without one it falls back to the default value and may render the wrong UI. Then assert the visible result the user sees.
Render with the provider
Wrap the component in its provider when you call render. This is the same requirement as the app, reproduced in one line of the test.
import { render, screen } from "@testing-library/react";
import { ThemeProvider } from "./theme-context";
import Settings from "./settings";
test("shows the dark mode label", () => {
render(
<ThemeProvider>
<Settings />
</ThemeProvider>
);
});Settings now has a real provider above it. The test can render the component and query its output without the component crashing on a missing context, and it exercises the same read path the real app uses.
Provide a fixed value for isolation
When the provider's own logic is not what you are testing, supply a fixed value so the test does not depend on it. Wrap the component in a provider with a known value.
import { render, screen } from "@testing-library/react";
import { ThemeContext } from "./theme-context";
import Settings from "./settings";
test("renders with a fixed theme", () => {
render(
<ThemeContext value={{ theme: "dark", setTheme: () => {} }}>
<Settings />
</ThemeContext>
);
expect(screen.getByRole("checkbox")).toBeChecked();
});The checkbox is checked because the fixed value is dark. The test stays stable even if the real provider changes how it stores state, and it only fails when the component itself renders the wrong output.
Test an update flow
To verify that a child can update the value, render through the real provider and interact with the component. The provider owns the state, so the update must flow back through context.
import userEvent from "@testing-library/user-event";
test("toggles the theme through context", async () => {
const user = userEvent.setup();
render(
<ThemeProvider>
<Settings />
</ThemeProvider>
);
await user.click(screen.getByRole("checkbox"));
expect(screen.getByRole("checkbox")).toBeChecked();
});The click calls the setter stored in the provider, React re-renders, and the checkbox reflects the new value. This verifies the full read and update path rather than only the initial render.
A reusable render wrapper
When several tests need the same provider, extract a render helper that wraps the component automatically. The helper keeps each test short and consistent.
import { render } from "@testing-library/react";
import { ThemeProvider } from "./theme-context";
function renderWithTheme(ui) {
return render(<ThemeProvider>{ui}</ThemeProvider>);
}Each test calls renderWithTheme instead of repeating the provider. When the provider gains props, you update the helper in one place and every test picks up the change.
What not to test
Do not assert on the raw context value or on the provider's internal state. A test should fail only when user-visible behavior changes, so a restructured provider should not break tests that check what appears on screen. Reserve provider-level tests for the provider's own logic, such as how it reacts to a missing default.
What to learn next
The same wrapping pattern applies to any provider, so review how to update context values from child components for the state and setter setup. To make a missing provider fail loudly instead of rendering a fallback, see safe default values for React context.
Rune AI
Key Insights
- Wrap the component in its provider inside the test.
- Use a fixed value to isolate the component from provider logic.
- Extract a custom render wrapper for repeated setup.
- Interact with user events and assert visible output.
- Test the provider separately when its own behavior matters.
Frequently Asked Questions
Do I need to wrap the component in its provider?
Should I test through the real provider?
What should I assert?
Conclusion
Test a context component by wrapping it in its provider, using a fixed value when isolation helps, and a reusable render wrapper to avoid repeating the setup. Interact through accessible queries and assert the visible result.
More in this topic
How to Build a Dropdown Menu in React
Build a React dropdown menu with the ARIA menu button pattern. Handle open and close, keyboard arrows, and clicks outside the menu.
How to Animate React Components with Motion
Animate React components with the Motion library. Set up motion, add enter, hover, and exit animations, and respect reduced motion.
Headless UI Components Explained: Logic Without Locked Styling
Understand headless UI components and how libraries like Radix give you unstyled, accessible behavior that you style yourself.