Mock Speci c Перехватчики React в обещаниях с библиотекой react-testing-library и ts-jest - PullRequest
0 голосов
/ 07 мая 2020

Я пытаюсь протестировать 2 useState хуков, которые запускаются во время цепочки обещаний после отправки формы.

Все хуки, прикрепленные к элементу (например, электронная почта, кнопка отправки) работают нормально , но это те, которые обновляют состояние в цепочке обещаний, к которым я не знаю, как получить доступ для имитации / тестирования.

    // submit function in ContactForm.tsx
    const handleSubmit = (e: React.FormEvent) => {
        e.preventDefault()
        const data = { firstName, lastName, email, message, subscribe }

        setLoading(true)
        fetchWrapper('/', encode(data))
            .then(() => {
                setStatus(true) // <= throws 'act(() => {...)' error
                props.onSubmit(data) // mock function passed in to check data submitted matches
            })
            .catch(error => {
                setStatus(false) // <= throws 'act(() => {...)' error
            })
            .finally(() => setLoading(false))
    }
    // ContactForm.spec.tsx
    import React from 'react'
    import { mocked } from 'ts-jest/utils'
    import { render, fireEvent } from '@testing-library/react'
    import ContactForm, { ContactFormProps } from './ContactForm'
    import { fetchWrapper } from '../../../utils/fetchWrapper'

    jest.mock('../../../utils/fetchWrapper')

    let mockedFetch

    beforeEach(() => {
        jest.clearAllMocks()
        mockedFetch = mocked(fetchWrapper)
    })

    it('should submit with firstName, lastName, email, message and subscribe', () => {
        // ASSEMBLE
        const onSubmit = jest.fn()

        const utils = renderContactForm({
            subscribe: false,
            onSubmit,
        })

        const firstName = utils.getByTestId('firstName')
        const lastName = utils.getByTestId('lastName')
        const email = utils.getByTestId('email')
        const message = utils.getByTestId('message')
        const subscribe = utils.getByTestId('subscribe')
        const submit = utils.getByTestId('SEND MESSAGE')

        mockedFetch.mockImplementationOnce(() => Promise.resolve())

        // ACT
        fireEvent.change(firstName, { target: { value: 'Clark' } })
        fireEvent.change(lastName, { target: { value: 'Kent' } })
        fireEvent.change(email, { target: { value: 'lastson@krypton.com' } })
        fireEvent.change(message, { target: { value: 'I like the sun' } })
        fireEvent.click(subscribe)
        fireEvent.click(submit)

        // ASSERT
        expect(onSubmit).toHaveBeenCalledWith({
            firstName: 'Clark',
            lastName: 'Kent',
            email: 'lastson@krypton.com',
            message: 'I like the sun',
            subscribe: true,
        })
    })

Я вижу ошибку:

    Warning: An update to ContactForm inside a test was not wrapped in act(...).

    When testing, code that causes React state updates should be wrapped into act(...):

    act(() => {
        /* fire events that update state */
    });
    /* assert on the output */

    This ensures that you're testing the behavior the user would see in the browser

Документация не кажется особенно полезной, поскольку в ней используется простой пример, а не тестирование побочных эффектов.

ПРИМЕЧАНИЕ: я бы предпочел избегать использования ферментов, если это возможно.

Спасибо заранее

1 Ответ

0 голосов
/ 08 мая 2020

Ответ заключался в том, чтобы обернуть fireEvent.click(submit) в act() из 'react-dom / test-utils`

it('should submit with firstName, lastName, email, message and subscribe', async () => {
    // ASSEMBLE
    const onSubmit = jest.fn()
    const handleCallback = jest.fn()

    const utils = renderContactForm({
        subscribe: false,
        onSubmit,
        handleCallback,
    })

    const firstName = utils.getByTestId('firstName')
    const lastName = utils.getByTestId('lastName')
    const email = utils.getByTestId('email')
    const message = utils.getByTestId('message')
    const subscribe = utils.getByTestId('subscribe')
    const submit = utils.getByTestId('SEND MESSAGE')

    mockedFetch.mockImplementationOnce(() => Promise.resolve())

    // ACT
    fireEvent.change(firstName, { target: { value: 'Clark' } })
    fireEvent.change(lastName, { target: { value: 'Kent' } })
    fireEvent.change(email, {
        target: { value: 'lastson@krypton.com' },
    })
    fireEvent.change(message, { target: { value: 'I like the sun' } })
    fireEvent.click(subscribe)

    await act(async () => { // the await / async here is important
        fireEvent.click(submit)
    })

    // ASSERT
    expect(onSubmit).toHaveBeenCalledWith({
        firstName: 'Clark',
        lastName: 'Kent',
        email: 'lastson@krypton.com',
        message: 'I like the sun',
        subscribe: true,
    })
})
...