Jest mock react context

ReactjsUnit TestingJestjsReact ContextReact Testing-Library

Reactjs Problem Overview


I need some help understanding how one can test an application using React Context.

Here's my sample setup.

context.js

import React from 'react'

export const AppContext = React.createContext()

App.js

import React from 'react'

import MyComponent from './MyComponent'
import {AppContext} from './context'

const App extends React.Component {

  state = {
    items: []
  }

  handleItemAdd = newItem => {
    const {items} = this.state
    items.push(newItem)
    this.setState(items)
  }

  render() {
    return (
      <AppContext.Provider value={{
        addItem: this.handleItemAdd
      }}>
        <MyComponent />
      </AppContext.Provider>
    )
  }
}

export default App

MyComponent.js

import React from 'react'

import {AppContext} from './context'

const MyComponent extends React.Component {    
  render() {
    return (
      <AppContext.Consumer>
        {addItem => 
          <button onClick={() => addItem('new item')}>
            Click me
          </button>
        }
      </AppContext.Consumer>
    )
  }
}

export default MyComponent

This is a simplified example. Imagine that there are more layers between App and MyComponent, hence the use of React Context.

And here's my test file for MyComponent.

MyComponent.test.js

import React from 'react'
import {render, fireEvent} from 'react-testing-library'

test('component handles button click', () => {
  const {getByText} = render(
    <MyComponent />
  )
  const button = getByText('Click me')
  fireEvent.click(button)
  expect...?
}

The thing is, AppContext.Consumer is part of the implementation of MyComponent, so in this test I don't have direct access to it. How do I mock AppContext.Consumer so I am actually able to verify that clicking a button fires a function call?

I know that in theory I can test this by rendering MyComponent in my App, but I want to write a unit test for MyComponent only.

Reactjs Solutions


Solution 1 - Reactjs

You just render the context with your component.

const addItem = jest.fn()
render(
  <AppContext.Provider value={{ addItem }}>
    <MyComponent />
  </AppContext.Provider>
)

See Mocking context with react-testing-library

Solution 2 - Reactjs

I want to add a complete test example by using the solution from @Giorgio. Here we are testing that MyComponent is rendered and that its button will be clicked once.

MyComponent.test.js

import React from 'react'
import { render, fireEvent } from 'react-testing-library'

test('component handles button click', () => {
  const addItem = jest.fn()
  render(
    <AppContext.Provider value={{ addItem }}>
      <MyComponent />
    </AppContext.Provider>
  )
  fireEvent.click(screen.getByText(/click me/))
  expect(addItem).toHaveBeenCalledTimes(1)
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionartoorasView Question on Stackoverflow
Solution 1 - ReactjsGiorgio Polvara - GpxView Answer on Stackoverflow
Solution 2 - ReactjsfjplaurrView Answer on Stackoverflow