等待两个单独的承诺解决,以便更新状态

时间:2019-02-15 20:40:56

标签: javascript reactjs testing jestjs enzyme

因此,我正在测试可更改状态的反应组件按钮单击。渲染组件时,我需要承诺解决,以便渲染按钮并因此使其可单击。我通过在组件状态得到更新时将按钮单击放置在setTimeout内来完成此操作。但是,在单击按钮后,由于已解决承诺,因此需要更新组件状态。我在下面举一个例子

class App extends component {
     constructor(props){
     this.state ={
         hasError = false;
         loading = true;
   }
}

componentdidMount(){
    this.apiGetFunc();

apiGetFunc(){
  this.setState({hasError: false});
  this.setState({loading = false});
}

onClickFunc{
   this.middleWareCalltoAPI.then(
      respone =>{ this.setState({hasError: false})},
      errorRespone =>{ this.setState({hasError = true})};
   )
}


renderer(){
   return (
     <Card>
     {!this.state.hasError && !this.state.loading && (
     <div>
     <Button>
        onClick = {this.onClickfunc}
     </Button>
     </div>
     </Card>
     )}
   )
}

现在这是我的测试样子

test("Save user permissions", done => {
  mock.onGet("anAPI.php").reply(200, mockData); //THIS IS NEEDED TO RENDER THE BUTTON
  const wrapper = shallow(<App />);

  setTimeout(() => {
    wrapper.find("Button").simulate("click"); //THIS CLICK SHOULD CHANGE hasError to true
    expect(wrapper.state.hasError).toEqual(true) //THIS FAILS
    done();
  }, 0);
});

我尝试嵌套setTimeouts,以便单击的诺言可以解决,但似乎不起作用。我试图尽可能地减少代码,以便于阅读。让我知道是否需要我提供更多背景信息。

编辑:使代码更类似于我实际拥有的

1 个答案:

答案 0 :(得分:1)

上面的示例代码中有很多错误,我强烈建议您在尝试前进之前花一些时间做一些简单的React教程。

不过,这是一个有效的示例...

工作示例https://codesandbox.io/s/xj53m8lwvz(您可以通过点击屏幕左下方附近的Tests标签来运行测试)

api / fakeAPI.js

const data = [
  {
    userId: 1,
    id: 1,
    title: "delectus aut autem",
    completed: false
  },
  {
    userId: 1,
    id: 2,
    title: "quis ut nam facilis et officia qui",
    completed: false
  },
  {
    userId: 1,
    id: 3,
    title: "fugiat veniam minus",
    completed: false
  },
  {
    userId: 1,
    id: 4,
    title: "et porro tempora",
    completed: true
  },
  {
    userId: 1,
    id: 5,
    title: "laboriosam mollitia et enim quasi adipisci quia provident illum",
    completed: false
  }
];

export const fakeAPI = {
  failure: () =>
    new Promise((resolve, reject) => {
      setTimeout(() => {
        reject("No data was found!");
      }, 1000);
    }),
  success: () =>
    new Promise(resolve => {
      setTimeout(() => {
        resolve(data);
      }, 1000);
    })
};

components / App / App.js

import React, { Component } from "react";
import ShowData from "../ShowData/showData";
import ShowError from "../ShowError/showError";
import { fakeAPI } from "../../api/fakeAPI";

export default class App extends Component {
  state = {
    data: [],
    hasError: "",
    isLoading: true
  };

  componentDidMount = () => {
    this.fetchData();
  };

  fetchData = () => {
    fakeAPI
      .success()
      .then(data => this.setState({ isLoading: false, data: data }))
      .catch(err => this.setState({ isLoading: false, hasError: err }));
  };

  handleClick = () => {
    this.setState({ isLoading: true, data: [] }, () => {
      fakeAPI
        .failure()
        .then(res => this.setState({ isLoading: false, hasError: "" }))
        .catch(err => this.setState({ isLoading: false, hasError: err }));
    });
  };

  render = () => (
    <div className="app-container">
      {this.state.isLoading ? (
         <ShowLoading />
      ) : this.state.hasError ? (
        <ShowError error={this.state.hasError} />
      ) : (
        <ShowData data={this.state.data} handleClick={this.handleClick} />
      )}
    </div>
  );
}

components / App / __ test __ / App.test.js mountWrap是一个自定义函数,可以在test/utils/index.js中找到,而WaitForExpect是一种更简单的方法等待断言在玩笑的默认5秒超时时间内true}

import React from "react";
import { mountWrap } from "../../../test/utils";
import WaitForExpect from "wait-for-expect";
import App from "../App";

const initialState = {
  data: [],
  hasError: "",
  isLoading: true
};

const wrapper = mountWrap(<App />, initialState);
describe("App", () => {
  it("renders without errors", () => {
    expect(wrapper.find("div.app-container")).toHaveLength(1);
  });

  it("initally shows that it's loading", () => {
    expect(wrapper.state("isLoading")).toBeTruthy();
    expect(wrapper.find("div.loading")).toHaveLength(1);
  });

  it("renders data and shows an Update button", async () => {
    await WaitForExpect(() => {
      wrapper.update();
      expect(wrapper.state("isLoading")).toBeFalsy();
      expect(wrapper.find("div.data")).toHaveLength(5);
      expect(wrapper.find("button.update")).toHaveLength(1);
    });
  });

  it("shows an error once the button has been clicked", async () => {
    wrapper.find(".update").simulate("click");
    await WaitForExpect(() => {
      wrapper.update();
      expect(wrapper.state("isLoading")).toBeFalsy();
      expect(wrapper.state("hasError")).toBe("No data was found!");
      expect(wrapper.find("div.error")).toHaveLength(1);
    });
  });
});