如何测试潜在的异步React渲染?

时间:2016-10-13 11:40:02

标签: javascript unit-testing testing reactjs chai

我最近决定开始为我所参与的项目编写测试,并且我们有一个React组件,我在确定如何正确测试方面遇到了一些麻烦。

该组件被称为FallbackedImage,它接受​​字符串或字符串数​​组并呈现第一个有效图像,正如您可能理解的那样,这是一个异步操作。

我想测试它是否确实如果提供了一个有效的字符串,实际上是渲染图像,但我不能只运行

it("renders img if src is valid string", () => {
  const wrapper = mount(<FallbackedImage src={validLink} />)
  expect(wrapper.find("img")).to.have.length(1)
})

因为图片尚未呈现,因此wrapper.find("img")length 0

我已经提出了两个“解决方案”,但它们很黑,而且我不想使用它们:

的setTimeout

这假设图像将在300毫秒内加载。如果图像加载时间较长,则测试将失败;如果花费的时间更少,那我浪费了宝贵的毫秒数。

it("renders img if src is valid string", done => {
  const wrapper = mount(<FallbackedImage src={validLink} />)
  window.setTimeout(() => {
    expect(wrapper.find("img")).to.have.length(1)
    done()
  }, 300)
})

使用组件的onLoad道具

这假设onLoad - 功能按预期工作,这感觉不对,因为这不在此特定测试的范围内。

it("renders img if src is valid string", done => {
  const onLoad = () => {
    expect(wrapper.find("img")).to.have.length(1)
    done()
  }

  const wrapper = mount(
    <FallbackedImage
      onLoad={onLoad}
      src={validLink} />
  )
})

我该如何测试? 我正在使用chaiEnzymeMocha,如果有帮助的话。 此外,这是FallbackedImage - 组件,因此您可以看到我正在使用的内容:

import React, { Component, PropTypes } from "react"
import { noop } from "../../utils"

export default class FallbackedImage extends Component {
  constructor(props) {
    super(props)
    this.componentDidMount = this.tryImage.bind(this)
    this.testImg = new window.Image()
    this.testImg.onerror = this.onError.bind(this)
    this.testImg.onload = this.onLoad.bind(this)
    this.photos = [].concat(props.src) // Make array from props.src if it's not
    this.state = { index: 0 }
  }

  static propTypes = {
    className: PropTypes.string,
    onLoad: PropTypes.func,
    src: PropTypes.oneOfType([
      PropTypes.array,
      PropTypes.string,
    ]),
  }

  static defaultProps = {
    onLoad: noop,
  }

  onError() {
    const nextIndex = this.state.index + 1
    if (nextIndex <= this.photos.length) {
      this.setState({ index: nextIndex }, this.tryImage)
    }
  }

  onLoad() {
    const { src } = this.testImg
    this.setState({ src })
    this.props.onLoad(src)
  }

  tryImage() {
    this.testImg.src = this.photos[this.state.index]
  }

  shouldComponentUpdate(_nextProps, nextState) {
    return !!nextState.src
  }

  render() {
    const { src } = this.state
    return src
      ? <img src={src} className={this.props.className} />
      : null
  }
}

0 个答案:

没有答案