如何在Jest中使用async/await对Promise catch()方法行为进行单元测试?

Ric*_*ral 8 unit-testing async-await reactjs es6-promise jestjs

说我有这个简单的React组件:

class Greeting extends React.Component {
    constructor() {
        fetch("https://api.domain.com/getName")
            .then((response) => {
                return response.text();
            })
            .then((name) => {
                this.setState({
                    name: name
                });
            })
            .catch(() => {
                this.setState({
                    name: "<unknown>"
                });
            });
    }

    render() {
        return <h1>Hello, {this.state.name}</h1>;
    }
}
Run Code Online (Sandbox Code Playgroud)

鉴于以下答案以及对该主题的更多研究,我已经提出了最终解决方案来测试resolve()案例:

test.only("greeting name is 'John Doe'", async () => {
    const fetchPromise = Promise.resolve({
        text: () => Promise.resolve("John Doe")
    });

    global.fetch = () => fetchPromise;

    const app = await shallow(<Application />);

    expect(app.state("name")).toEqual("John Doe");
});
Run Code Online (Sandbox Code Playgroud)

哪个工作正常.我的问题现在正在测试catch()案例.以下不起作用,因为我期望它工作:

test.only("greeting name is 'John Doe'", async () => {
    const fetchPromise = Promise.reject(undefined);

    global.fetch = () => fetchPromise;

    const app = await shallow(<Application />);

    expect(app.state("name")).toEqual("<unknown>");
});
Run Code Online (Sandbox Code Playgroud)

断言失败,name是空的:

expect(received).toEqual(expected)

Expected value to equal:
    "<unknown>"
Received:
    ""

    at tests/components/Application.spec.tsx:51:53
    at process._tickCallback (internal/process/next_tick.js:103:7)
Run Code Online (Sandbox Code Playgroud)

我错过了什么?

TLa*_*add 9

这条线

const app = await shallow(<Application />);
Run Code Online (Sandbox Code Playgroud)

在两个测试中都不正确.这意味着浅薄的回归承诺,而不是.因此,您并不是真的在等待构造函数中的promise链来根据需要进行解析.首先,将获取请求移动到componentDidMount,其中React文档建议触发网络请求,如下所示:

import React from 'react'

class Greeting extends React.Component {
  constructor() {
    super()
    this.state = {
      name: '',
    }
  }

  componentDidMount() {
    return fetch('https://api.domain.com/getName')
      .then((response) => {
        return response.text()
      })
      .then((name) => {
        this.setState({
          name,
        })
      })
      .catch(() => {
        this.setState({
          name: '<unknown>',
        })
      })
  }

  render() {
    return <h1>Hello, {this.state.name}</h1>
  }
}

export default Greeting
Run Code Online (Sandbox Code Playgroud)

现在我们可以通过直接调用componentDidMount来测试它.由于ComponentDidMount返回promise,await将等待promise链解析.

import Greeting from '../greeting'
import React from 'react'
import { shallow } from 'enzyme'

test("greeting name is 'John Doe'", async () => {
  const fetchPromise = Promise.resolve({
    text: () => Promise.resolve('John Doe'),
  })

  global.fetch = () => fetchPromise

  const app = shallow(<Greeting />)
  await app.instance().componentDidMount()

  expect(app.state('name')).toEqual('John Doe')
})

test("greeting name is '<unknown>'", async () => {
  const fetchPromise = Promise.reject(undefined)

  global.fetch = () => fetchPromise

  const app = shallow(<Greeting />)
  await app.instance().componentDidMount()

  expect(app.state('name')).toEqual('<unknown>')
})
Run Code Online (Sandbox Code Playgroud)