axios在componentDidMount中获取数据后如何拍摄jest snapshot?

Posted

技术标签:

【中文标题】axios在componentDidMount中获取数据后如何拍摄jest snapshot?【英文标题】:How to take a jest snapshot after axios fetched data in componentDidMount? 【发布时间】: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 回调,但没有运气。

【问题讨论】:

【参考方案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() 的作用完全相同,同时具有更好的可读性

以上是关于axios在componentDidMount中获取数据后如何拍摄jest snapshot?的主要内容,如果未能解决你的问题,请参考以下文章

async/await 不适用于 ComponentDidMount 中的 react.js

如何在多个文件中分解 REACTJS 中的 Axios 调用?

Axios.get 返回纯 html 而不是 JSON 返回数据

为啥在 componentDidMount 中取消异步/ajax 请求

React componentDidMount() 初始化状态

axios 获取实时数据请求