Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jest mock react context

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.

like image 752
artooras Avatar asked Jan 21 '19 14:01

artooras


People also ask

How do you test create context?

The best way to test Context is to make our tests unaware of its existence and avoiding mocks. We want to test our components in the same way that developers would use them (behavioral testing) and mimic the way they would run in our applications (integration testing).

How do you mock a react component in Jest?

To mock a React component, the most straightforward approach is to use the jest. mock function. You mock the file that exports the component and replace it with a custom implementation. Since a component is basically a function, the mock should also return a function.

How do you test a react component that is dependent on useContext hook?

A simple example: import React, { useContext } from 'react'; const MyComponent = () => { const name = useContext(NameContext); return <div>{name}</div>; }; When testing this component with the shallow renderer from react and jest snapshots.


2 Answers

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

like image 135
Giorgio Polvara - Gpx Avatar answered Sep 20 '22 12:09

Giorgio Polvara - Gpx


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) } 
like image 32
fjplaurr Avatar answered Sep 21 '22 12:09

fjplaurr