AdamGold
AdamGold

Reputation: 5051

React Native asynchronous Jest component testing

I have a component that dispatches a fetch request on mount, and displays the results.

I am trying to create a test snapshot of this component after the request is completed. I've been banging my head at this for quite some time now, here are the related question on SO that gave me no luck:

  1. Async component snapshot using Jest and Redux
  2. How do test async components with Jest?
  3. React+Jest - Testing async components and waiting for mount
  4. How to take a jest snapshot after axios fetched data in componentDidMount?

This is my fetch mock:

// Mocking the global.fetch included in React Native
global.fetch = jest.fn()

// Helper to mock a success response (only once)
fetch.mockResponseSuccess = (body, status = 200) => {
    fetch.mockImplementationOnce(() =>
        Promise.resolve({
            status,
            json: () => Promise.resolve(JSON.parse(body))
        })
    )
}

// Helper to mock a failure response (only once)
fetch.mockResponseFailure = error => {
    fetch.mockImplementationOnce(() => Promise.reject(error))
}

The component (simplified):

export class Posts extends Component {
    constructor(props) {
        super(props)
        this.state = {
            items: [],
            loading: false
        }
        this._getItems()
    }

    async _getItems() {
        const resp = await fetch(
                "/user/recent_posts",
                {
                    method: "GET"
                }
            )
        this.setState({
            items: resp.json["data"],
        })
    }

    render() {
        // renders this.state.items
    }

This is the test:

    test("view renders correctly", async done => {
        fetch.mockResponseSuccess(
            JSON.stringify({
                data: [
                    { caption: "test", likes: 100 },
                    { caption: "test2", likes: 200 }
                ]
            })
        )
        // also tried with setTimeout and setImidiate
        const wrapper = await shallow(<Posts />) // also tried with react-test-renderer
        await wrapper.update() // didn't work with or without
        // await waitForState(wrapper, state => state.loading === false) --> didn't work
        // process.nextTick(() => {.... --> didn't work
        // jest.runTimersToTime(1) --> didn't work
        expect(wrapper).toMatchSnapshot()
        done()
    })

The problem is that this.state.items in the snapshot is always empty.

Upvotes: 0

Views: 374

Answers (1)

AdamGold
AdamGold

Reputation: 5051

For future reference, here is what solved it for me:

test("view renders correctly", done => {
    // mock response here...
    const wrapper = shallow(<Posts />)
    setImmediate(() => {
        wrapper.update()
        try {
            expect(wrapper).toMatchSnapshot()
        } catch (e) {
            console.log(e)
        }

        done()
    })
})

Upvotes: 1

Related Questions