HomeAbout Me

React Testing: Testing with context and a custom render method

By Daniel Nguyen
Published in React JS
July 27, 2025
2 min read
React Testing: Testing with context and a custom render method

🎨 Testing React Components with Context & Custom Render Methods

React context is a powerful feature for sharing values across your component tree—like themes, authentication status, or router state. But once you start writing tests for components that use context, things can get repetitive fast.

😩 “Why do I have to wrap my component with the provider every time I test?”

Let’s solve that problem by learning how to test context-driven components efficiently using a custom render method with React Testing Library.


🧠 The Context Problem in Tests

Let’s say you’re testing a component that uses a ThemeContext. To render it properly, you need to wrap it in the ThemeProvider.

import {render} from '@testing-library/react'
import {ThemeProvider} from '../context/theme'
render(
<ThemeProvider>
<ComponentToTest />
</ThemeProvider>,
)

That works! But what if you want to rerender the component with updated props? You’ll have to repeat the wrapper again:

const {rerender} = render(
<ThemeProvider>
<ComponentToTest />
</ThemeProvider>
)
rerender(
<ThemeProvider>
<ComponentToTest newProp={true} />
</ThemeProvider>
)

📉 This creates boilerplate and tightly couples your test logic to the implementation.


🧪 Solution: Use the wrapper Option

React Testing Library allows you to pass a wrapper component when calling render. This ensures both the initial render and all rerenders are wrapped consistently.

function Wrapper({children}) {
return <ThemeProvider>{children}</ThemeProvider>
}
const {rerender} = render(<ComponentToTest />, {wrapper: Wrapper})
rerender(<ComponentToTest newProp={true} />)

✨ This way, your tests become simpler and more maintainable.

📚 Learn more: React Testing Library – wrapper


🛠 Going Further: Custom Render Function

We can take this idea further by creating our own render function that automatically wraps components with all necessary providers—just like your app does.

// test-utils.js
import {render as rtlRender} from '@testing-library/react'
import {ThemeProvider} from '../context/theme'
function Wrapper({children, theme = 'light'}) {
return <ThemeProvider initialTheme={theme}>{children}</ThemeProvider>
}
function render(ui, {theme, ...options} = {}) {
return rtlRender(ui, {
wrapper: ({children}) => <Wrapper theme={theme}>{children}</Wrapper>,
...options,
})
}
export * from '@testing-library/react'
export {render}

Now you can write clean tests like this:

import {render, screen} from '../test/test-utils'
import EasyButton from '../components/easy-button'
test('renders with light theme styles', () => {
render(<EasyButton />, {theme: 'light'})
expect(screen.getByRole('button')).toHaveStyle({
backgroundColor: 'white',
color: 'black',
})
})

And test the dark theme with minimal changes:

test('renders with dark theme styles', () => {
render(<EasyButton />, {theme: 'dark'})
expect(screen.getByRole('button')).toHaveStyle({
backgroundColor: 'black',
color: 'white',
})
})

💯 Extra Credit

1. ✅ Test the dark theme

Duplicate your light theme test, swap out theme: 'dark', and update the style assertions. This ensures your context logic behaves correctly across variations.

2. ✅ Create a render helper

Create a render method in your own test-utils.js file that automatically wraps components with the needed context providers. This centralizes setup logic, making all future tests easier to write.

3. ✅ Use shared test utilities

If you’re working in a larger app, you likely already have a shared render helper in a file like test/test-utils.js. Just import from there instead of @testing-library/react:

// ❌ Don't do this
import {render} from '@testing-library/react'
// ✅ Do this
import {render} from '../test/test-utils'

This ensures every test uses the same app-wide providers—like router, theme, or authentication—without extra boilerplate.


🔁 Recap

ConceptBenefit
Wrap components with contextEnsures components function as they do in production
Use wrapper optionAllows rerendering without duplicating providers
Create a test-utils.js fileDRYs up test setup across your test suite
Support theme/auth/router contextFully simulates real-world usage for more accurate tests
Add options like {theme: 'dark'}Makes tests easier to read and adapt

📋 Elaboration and Feedback

If you want to reflect on what you’ve learned and reinforce your understanding, take a moment to fill out this quick feedback form:

👉 Testing with Context & Custom Render – Feedback Form


👋 Final Thoughts

Writing tests that resemble how your app is used in the real world is always a win. With context, that means rendering your components with the right providers, but doing it in a way that’s clean, DRY, and expressive.

Your tests should focus on behavior—not implementation details. A custom render utility lets you do just that.


Tags

#ReactTesting

Share

Previous Article
React Testing: Mocking Browser APIs and modules

Table Of Contents

1
🧠 The Context Problem in Tests
2
🧪 Solution: Use the wrapper Option
3
🛠 Going Further: Custom Render Function
4
💯 Extra Credit
5
🔁 Recap
6
📋 Elaboration and Feedback
7
👋 Final Thoughts

Related Posts

React Testing: Testing custom hook
July 28, 2025
2 min
© 2025, All Rights Reserved.
Powered By

Quick Links

About Me

Legal Stuff

Social Media