如何在 React 中的 class 组件实例方法中模拟 fetch?

How can fetch be mocked in a class component's instance method in React?

我正在使用 create-react-app、jest 和 enzyme。

我有一个 class 组件,它在单击 table 行时加载 "detail" 数据,然后在可以编辑和保存详细信息的模式中显示一个表单:

import React, { Component } from "react";
import fetch from "isomorphic-fetch";
import Modal from "./Modal";

export default class RecordViewer extends Component {
  constructor(props) {
    super(props);
    this.state = {
        showModal: false,
        currentRecord: {}
    };
  }

  open(id) {
    fetch(`api/${id}`)
      .then(res => res.json())
      .then(data => {
        this.setState({
          ...this.state,
          currentRecord: data.record,
          showModal: true
        });
      });
  }

  render() {
    <div>
      <Modal visible={this.state.showModal} contents={this.state.currentRecord} />
      <table>
        <tr onClick={()=>this.open(1)}>
          <td>Record Overview for Item 1</td>
        </tr>
      </table>
    </div>
  }
}

我想模拟 fetch 函数以确定它是否被调用,但也只是为了防止组件试图点击 API。例如,我想测试传递给模态的内容。

将 fetch 作为 prop 传入会使这变得容易,但此组件的父级将需要知道它,这似乎没有意义。

有没有办法用这个设置来模拟抓取?

也许有更好的方法来一起测试这个?

有一种方法,但并不理想。看看 fetch-mock 包。

它不理想的原因是你不会完全隔离你的组件,所以从技术上讲它不再是单元测试但你没有指定你正在编写哪种测试。

实际上你应该创建一个 "container" 组件来连接业务规则和 "view" ex;

src/components
  -> RecordViewer.js
  -> RecordViewerContainer.js

因此,在 RecordViewer.js 中,您可以像 PURE 组件那样做,只需导出一个回调函数 ex。

RecordViewer.js

import React, { Component } from "react";
import Modal from "./Modal";

class RecordViewer extends Component {
  render() {
    <div>
      <Modal visible={this.props.showModal}
       contents={this.props.currentRecord} />
      <table>
        <tr onClick={() => this.props.onOpen(1)}>
          <td>Record Overview for Item 1</td>
        </tr>
      </table>
    </div>
  }
}

RecordViewer.propTypes = {
  showModal: React.PropTypes.bool,
  onOpen: React.PropTypes.func,
  currentRecord: React.PropTypes.object
}

RecordViewer.defaultProps = {
  showModal: false,
  currentRecord: {},
  onOpen: function(){}
}

export default RecordViewer;

RecordViewerContainer.js

import React, { Component } from "react";
import fetch from "isomorphic-fetch";
import RecordViewer from "./RecordViewer";

export default class RecordViewerContainer extends Component {
  constructor(props) {
    super(props);
    this.state = {
        showModal: false,
        currentRecord: {}
    };
  }

  open(id) {
    fetch(`api/${id}`)
      .then(res => res.json())
      .then(data => {
        this.setState({
          ...this.state,
          currentRecord: data.record,
          showModal: true
        });
      });
  }

  render() {
    <RecordViewer currentRecord={this.state.currentRecord} showModal={this.state.showModal} />
  }
}

然后您可以模拟组件参数并分离 API 调用和业务规则。

提示:我们有工具可以更好地做到这一点,例如 reduxaltjsreflux(通量实现)。