【问题标题】:How to take a jest snapshot after axios fetched data in componentDidMount?axios在componentDidMount中获取数据后如何拍摄jest snapshot?
【发布时间】:2019-05-01 22:06:41
【问题描述】:

要测试的组件

class Carousel extends React.Component {
  state = {
    slides: null
  }

  componentDidMount = () => {
    axios.get("https://s3.amazonaws.com/rainfo/slider/data.json").then(res => {
      this.setState({ slides: res.data })
    })
  }

  render() {
    if (!slides) {
      return null
    }

    return (
      <div className="slick-carousel">
        ... markup trancated for bravity
      </div>
    )
  }
}

export default Carousel

测试

import React from "react"
import renderer from "react-test-renderer"
import axios from "axios"
import Carousel from "./Carousel"

const slides = [
  {
    ID: "114",
    REFERENCE_DATE: "2018-07-02",
    ...
  },
  {
    ID: "112",
    REFERENCE_DATE: "2018-07-06",
    ...
  },
  ...
]

jest.mock("axios")

it("", () => {
  axios.get.mockImplementationOnce(() => Promise.resolve({ data: slides }))

  const tree = renderer.create(<Carousel />).toJSON()
  expect(tree).toMatchSnapshot()
})

快照只记录null,因为在执行的那一刻我猜想state.slides = null

在 axios 完成获取数据后,我无法确定如何运行期望。

大多数在线示例要么使用酶,要么显示带有返回承诺的异步函数的测试。我找不到一个只使用 jest 和渲染组件来显示示例的示例。

我尝试制作测试函数async,也使用done 回调,但没有运气。

【问题讨论】:

    标签: javascript reactjs promise axios jestjs


    【解决方案1】:

    简而言之:

    it("", async () => {
      axios.get.mockImplementationOnce(() => Promise.resolve({ data: slides }))
    
      const tree = renderer.create(<Carousel />);
      await Promise.resolve();
      expect(tree.toJSON()).toMatchSnapshot()
    })
    

    应该做的工作

    详细说明:除了您已经模拟了对 API 数据的调用之外,它仍然以异步方式进行。所以我们需要toMatchSnapshot 调用到微任务队列的末尾。 setTimeout(..., 0)setImmediate 也可以,但我发现 await Promise.resolve() 更容易识别为“下面的所有内容都即将结束”

    [UPD] 修复 sn-p: .toJSON 必须在等待之后,它返回的对象永远不会被更新

    【讨论】:

    • 感谢您的帮助和良好的解释。我能够想出 `Promise.resolve(renderer.create()).then(tree => { expect(tree.toJSON()).toMatchSnapshot() })`,而我没有t get what is doing 似乎正在工作。我最终使用的您的代码更加清晰和美观。谢谢。
    • 如果你使用shallow而不是渲染器,这是否也有效?
    • @Zheng-rongCai 如果它是浅层渲染并且 XHR 调用应该发生在一些嵌套的孩子中......那将不会被渲染,因为它是浅层渲染 - 不是,它不会工作。但否则它应该工作
    【解决方案2】:

    接受的答案第二天开始失败。经过一些调整,这似乎工作:

    import React from "react"
    import renderer from "react-test-renderer"
    import axios from "axios"
    import Carousel from "./Carousel"
    
    jest.mock("axios")
    const slides = sampleApiResponse()
    const mockedAxiosGet = new Promise(() => ({ data: slides }))
    axios.get.mockImplementation(() => mockedAxiosGet)
    
    // eventhough axios.get was mocked, data still comes anychrnonously,
    // so during first pass state.slides will remain null
    it("returns null initally", () => {
      const tree = renderer.create(<Carousel />).toJSON()
      expect(tree).toMatchSnapshot()
    })
    
    it("uses fetched data to render carousel", () => {
      const tree = renderer.create(<Carousel />)
      mockedAxiosGet.then(() => {
        expect(tree.toJSON()).toMatchSnapshot()
      })
    })
    
    function sampleApiResponse() {
      return [
        {
          ID: "114",
          REFERENCE_DATE: "2018-07-02",
          ...
        },
        {
          ID: "114",
          REFERENCE_DATE: "2018-07-02",
          ...
        },
      ]
    }
    

    【讨论】:

    • promise new Promise(() =&gt; ({ data: slides })) 永远不会得到解决。你需要Promise.resolve() 工厂方法。使用构造函数 new Promise() 您需要将解析器作为参数并像 new Promise(resolver =&gt; resolver({ data: slides })) 一样调用它,但 Promise.resolve() 的作用完全相同,同时具有更好的可读性
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-07
    • 1970-01-01
    • 2021-04-14
    相关资源
    最近更新 更多