简体   繁体   中英

React Context testing - mocking Consumer in HOC

I am trying to test my component which is consuming data from context via HOC.

Here is setup: Mocked context module /context/__mocks__

const context = { navOpen: false, toggleNav: jest.fn() } 

export const AppContext = ({
    Consumer(props) {
        return props.children(context)
    }
})

Higher OrderComponent /context/withAppContext

import React from 'react'
import { AppContext } from './AppContext.js'

/**
 * HOC with Context Consumer
 * @param {Component} Component 
 */
const withAppContext = (Component) => (props) => (
    <AppContext.Consumer>
        {state => <Component {...props} {...state}/>}
    </AppContext.Consumer>
) 

export default withAppContext

Component NavToggle

import React from 'react'
import withAppContext from '../../../context/withAppContext'

import css from './navToggle/navToggle.scss'

const NavToggle = ({ toggleNav, navOpen }) => (
    <div className={[css.navBtn, navOpen ? css.active : null].join(' ')} onClick={toggleNav}>
        <span />
        <span />
        <span />
    </div>
)

export default withAppContext(NavToggle)

And finally Test suite /navToggle/navToggle.test

import React from 'react'
import { mount } from 'enzyme'

beforeEach(() => {
  jest.resetModules()
}) 

jest.mock('../../../../context/AppContext')


describe('<NavToggle/>', () => { 
  it('Matches snapshot with default context', () => {    
        const NavToggle = require('../NavToggle')        
        const component = mount( <NavToggle/> )
        expect(component).toMatchSnapshot()
  })
})

Test is just to get going, but I am facing this error: Warning: Failed prop type: Component must be a valid element type! in WrapperComponent Warning: Failed prop type: Component must be a valid element type! in WrapperComponent Which I believe is problem with HOC, should I mock that somehow instead of the AppContext, because technically AppContext is not called directly by NavToggle component but is called in wrapping component.

Thanks in advance for any input.

So I solved it.

There were few issues with my attempt above.

  1. require does not understand default export unless you specify it
  2. mounting blank component returned error
  3. mocking AppContext with __mock__ file caused problem when I wanted to modify context for test

I have solved it following way. I created helper function mocking AppContext with custom context as parameter

export const defaultContext = { navOpen: false, toggleNav: jest.fn(), closeNav: jest.fn(), path: '/' } 

const setMockAppContext = (context = defaultContext) => {
    return jest.doMock('../context/AppContext', () => ({
        AppContext: {
            Consumer: (props) => props.children(context)
        }
    }))  
}
export default setMockAppContext

And then test file ended looking like this

import React from 'react'
import { shallow } from 'enzyme'
import NavToggle from '../NavToggle'
import setMockAppContext, { defaultContext } from '../../../../testUtils/setMockAppContext'

beforeEach(() => {
  jest.resetModules()
}) 

describe('<NavToggle/>', () => { 
  //...   
  it('Should have active class if context.navOpen is true', () => {
    setMockAppContext({...defaultContext, navOpen: true})
    const NavToggle = require('../NavToggle').default //here needed to specify default export
    const component = shallow(<NavToggle/>)
    expect(component.dive().dive().hasClass('active')).toBe(true) //while shallow, I needed to dive deeper in component because of wrapping HOC   
  })
  //...
})

Another approach would be to export the component twice, once as decorated with HOC and once as clean component and create test on it, just testing behavior with different props. And then test just HOC as unit that it actually passes correct props to any wrapped component.

I wanted to avoid this solution because I didn't want to modify project file(even if it's just one word) just to accommodate the tests.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM