При тестировании компонента React, который отображает извлеченные данные API, как лучше подождать этих данных, прежде чем делать какие-либо утверждения? - PullRequest
1 голос
/ 16 апреля 2020

У меня есть простой компонент «Редактировать пользователя», который содержит форму с полем «Имя». Когда компонент визуализируется впервые, это поле остается пустым до тех пор, пока не будет выполнен запрос API для данных пользователя. Как только данные извлекаются, состояние обновляется, и компонент перерисовывается, на этот раз с заполненным полем «Имя». (Для ясности, для этого не требуется никакого взаимодействия с пользователем.)

Мой тест, который ожидает, что поле «Имя» заполнено правильно, в настоящее время не проходит, потому что он только тестирует начальный рендер моего компонента, прежде чем пользовательская информация может быть получена.

Какой эффективный способ проверить это поведение, т. е. дождаться завершения (поддельного) запроса, прежде чем будут сделаны какие-либо утверждения?

FWIW, I ' используя React 16.12.0.

Вот сокращенный компонент:

import React, { useState, useEffect } from 'react'
import axios from 'axios'

const EditUser = (props) => {
  const [user, setUser] = useState({
    fname: "",
    lname: ""
  })

  const fetchUser = async () => {
    await axios.get(`/api/users/${props.userId}`)
    .then(response => {
      const data = response.data
      const user = {
        fname: data.attributes.fname,
        lname: data.attributes.lname
      }
      setUser(user)
    })
    .catch(error => console.log(error))
  }

  useEffect(() => {
    fetchUser()
  }, [])

  return (
    <div>
      <h2>Edit User</h2>
      <form>
        <div className="form-group">
          <label>First Name</label>
          <input
            name="fname"
            value={user.fname}
          />
        </div>
      </form>
    </div>
  )
}

export default EditUser

И тест:

import React from 'react'
import { mount } from 'enzyme'
import { act } from 'react-dom/test-utils'
import axios from 'axios'
import MockAdapter from 'axios-mock-adapter'
import EditUser from 'packs/editUser'

describe('editUser', () => {
  let wrapper
  const axiosMock = new MockAdapter(axios)

  axiosMock.onGet('/api/users/5').reply(200, {
    id: 5,
    attributes: {
      fname: 'Bradley',
      lname: 'King'
    }
  })

  it('shows the user edit form', async () => {
    await act(async () => {
      wrapper = await mount(<EditUser userId={5} />)
    })

    const firstNameInput = wrapper.find('input[name="fname"]')

    // the following FAILS because the first name input is blank
    // _until_ the user data is fetched and the component is
    // re-rendered with field populated
    expect(firstNameInput.props().value).toEqual('Bradley')
  })
})

Спасибо!

1 Ответ

1 голос
/ 16 апреля 2020

Поскольку вы ожидаете, что произошел рендер, вы можете использовать .update() метод от wrapper до

Syn c дерева компонентов фермента снимок с деревом реагирующих компонентов. Полезно запустить перед проверкой вывода рендеринга, если что-то внешнее может где-то обновлять состояние компонента.

it('shows the user edit form', async() => {
  await act(async() => {
    wrapper = await mount(<EditUser userId={5} />)
  })

  wrapper.update();

  const firstNameInput = wrapper.find('input[name="fname"]')

  expect(firstNameInput.props().value).toEqual('Bradley')
})
...