Search code examples
reactjsfunctional-programmingjestjsenzymerecompose

How to Execute a Function Inside a Stateless Component for Testing in Jest and Enzyme


I've got a parent component that I've wrapped with Recompose withHandlers HOC. I've got a function called removeGiftHandler that I want to pass down to the child component as a callback that will change the state kept in the props in the parent component (using withState).

I'm currently testing the parent component, specifically the removeGiftHandler function. The problem is that because the function is being passed down to the child component, there's no event for me to simulate. Also if it was a class component I could use wrapper.instance().removeGift(id) and there would be no issue. Given that it is a stateless functional component, this isn't the case.

Here's the code for the component:

const App = ({ addGiftHandler, state: { gifts } }) => (
    <div>
        <h1>Gift Giver</h1>
        <ListGroup>
            {map(
                ({ id }) => (
                    <ListGroupItem key={id}>
                        <Gift />
                    </ListGroupItem>
                ),
                gifts
            )}
        </ListGroup>
        <Button outline onClick={addGiftHandler}>
            Add Gift
        </Button>
    </div>
)

export default compose(
    withEnhancedState(INITIAL_STATE),
    withHandlers({
        addGiftHandler: ({ state: { gifts }, updateState }) => () =>
            updateState({ gifts: [...gifts, { id: inc(length(gifts)) }] }),
        removeGiftHandler: ({ state: { gifts }, updateState }) => id => () =>
            updateState({ gifts: filter(gift => gift.id !== id, gifts) }),
    })
)(App)

Once removeGiftHandler is properly tested, the plan is to pass it down to the Gift component.

And here's the relevant code for the tests:

import React from 'react'
import { shallow } from 'enzyme'
import { length } from 'ramda'

import App from '.'

const getBaseApp = app =>
    app
        .dive()
        .dive()
        .dive()

describe('App', () => {
    const app = shallow(<App />)
    const baseApp = getBaseApp(app)

        //...

        describe('and the user wants to remove the added gift', () => {
            beforeEach(() => {
                //-----> trigger removeGiftHandler somehow <-----
            })

            it('removes the gift from `state`', () => {
                expect(app.props().state.gifts).toEqual([])
            })
        })
    })
})

Note baseApp is the base component without the Recompose HOCs.

Can someone please help me with this issue?


Solution

  • You need to dive 2 times instead of 3 to reach the withHandlers HOC. On the props there you can call the function and check the state was updated correctly.