4

I have a form that uses an Apollo mutation hook:

import React from 'react'
import { useFormik } from 'formik'
import { useLoginMutation } from '../generated'

const LoginContainer = () => {
  const [loginMutation, { data, loading, error }] = useLoginMutation()

  const formik = useFormik({
    initialValues: {
      email: '',
      password: '',
    },
    onSubmit: values => {
      loginMutation({
        variables: {
          input: {
            email: String(values.email).trim(),
            password: values.password,
          },
        },
      })
    },
  })

  return (
    <form
      onSubmit={event => {
        event.preventDefault()
        formik.handleSubmit(event)
      }}
    >
      <input
        data-testid="login-email-input"
        name="email"
        placeholder="Email address"
        //  label="Email"
        required
        type="email"
        value={formik.values.email}
        onChange={formik.handleChange}
      />
      <input
        data-testid="login-password-input"
        name="password"
        placeholder="password"
        //  label="Password"
        required
        type="password"
        value={formik.values.password}
        onChange={formik.handleChange}
      />
      <button data-testid="login-submit-input" type="submit">
        LOGIN
      </button>
    </form>
  )
}

export default LoginContainer

I am trying to make sure the login mutation is called when the user fills in the form and clicks the submit button.

The test runs successfully sometimes and fails other times. I suspect that the loginMutation promise is not being resolved before the expect block is run.

The console also has the following warning:

  Warning: An update to LoginContainer 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 */

Here is the test:

describe('login container', () => {
  let loginMutationCalled = false

  const variables = {
    input: {
      email: '[email protected]',
      password: '123',
    },
  }

  const result = () => {
    loginMutationCalled = true
    return {
      data: {
        Login: {
          accountId: '123',
        },
      },
    }
  }

  const mocks = [
    {
      request: {
        query: LOGIN_MUTATION,
        variables,
      },
      result,
    },
  ]

  it('should call the login mutation', async () => {
    await act(async () => {
      const { findByTestId } = render(
        <MockedProvider mocks={mocks} addTypename={false}>
          <LoginContainer />
        </MockedProvider>,
      )

      fireEvent.change(await findByTestId('login-email-input'), {
        target: {
          value: '[email protected]',
        },
      })

      fireEvent.change(await findByTestId('login-password-input'), {
        target: {
          value: '123',
        },
      })

      await wait(async () =>
        fireEvent.click(await findByTestId('login-submit-input')),
      )
    })

    expect(loginMutationCalled).toBe(true)
  })
})

How do I make sure the loginMutation promise has been resolved before running the assertions?

1 Answer 1

0

Please check out my GitHub https://github.com/Arit143/mytube-ui/blob/master/src/pages/List.spec.tsx for async act wait. Usually, I wrap the act and wait in a function and then just wait for it to fulfill. If you feel the login resolve is taking much time, you can increase the wait amount. Just have a look at the GitHub URL as an example and let me know in case you still face an issue.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.