简体   繁体   中英

How to take a jest snapshot after axios fetched data in componentDidMount?

Component to test

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

Test

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

snapshot only records null , since at the moment of execution I suppose state.slides = null .

Can't put my finger on how to run expectations after axios done fetching the data.

Most of the samples online either use enzyme, or show tests with async functions that return promises. I couldn't find one that would show example only using jest and rendered component.

I tried making test function async , also using done callback, but no luck.

in short:

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

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

should do the job

in details: besides you have mocked call to API data is still coming in async way. So we need toMatchSnapshot call goes to end of microtasks' queue. setTimeout(..., 0) or setImmediate will work too but I've found await Promise.resolve() being better recognizable as "everything below is coming to end of queue"

[UPD] fixed snippet: .toJSON must be after awaiting, object it returns will never be updated

The accepted answer started to fail the next day. After some tweaking, this seems to be working:

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",
      ...
    },
  ]
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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