简体   繁体   English

在测试呈现提取的 API 数据的 React 组件时,如何在做出任何断言之前最好地等待该数据?

[英]When testing a React component that renders fetched API data, how best to wait for that data before making any assertions?

I have a simple "Edit User" component which contains a form with a "First Name" field.我有一个简单的“编辑用户”组件,其中包含一个带有“名字”字段的表单。 When the component first renders, that field is blank until an API request for the user's data is completed.当组件首次呈现时,该字段为空白,直到完成对用户数据的 API 请求。 Once the data is fetched, the state gets updated and the component re-renders, this time with the "First Name" field populated.获取数据后,state 将得到更新并重新渲染组件,这次填充了“名字”字段。 (To be clear, no user interaction is required for this to happen.) (需要明确的是,发生这种情况不需要用户交互。)

My test, which expects the "First Name" field to be correctly populated, is currently failing because it's only testing the initial render of my component, before the user info can be fetched.我的测试希望正确填充“名字”字段,但目前失败了,因为它只是在获取用户信息之前测试我的组件的初始渲染。

What's an efficient way to test this behavior ie wait until the (mocked) request is completed before any assertions are made?什么是测试这种行为的有效方法,即在做出任何断言之前等到(模拟的)请求完成?

FWIW, I'm using React 16.12.0. FWIW,我使用的是 React 16.12.0。

Here's the abbreviated component:这是缩写的组件:

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

And the test:和测试:

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')
  })
})

Thanks!谢谢!

Since you are expecting a render to have occurred, you can use the .update() method of the wrapper to由于您期望渲染已经发生,您可以使用wrapper.update()方法来

Sync the enzyme component tree snapshot with the react component tree.将酶成分树快照与反应成分树同步。 Useful to run before checking the render output if something external may be updating the state of the component somewhere.如果外部某些东西可能在某处更新组件的 state,则在检查渲染 output 之前运行很有用。

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')
})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM