简体   繁体   English

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

[英]Waiting for two separate promises to resolve so state is updated

So I'm testing a react component button click that changes a state.所以我正在测试一个改变状态的反应组件按钮点击。 When rendering the component I need a promise to resolve so the button is rendered and thus clickable.在呈现组件时,我需要一个承诺来解决,以便呈现按钮并因此可点击。 I accomplish this by placing the button click inside of a setTimeout as the component states get updated.我通过在组件状态更新时将按钮单击放置在 setTimeout 内来完成此操作。 However after clicking the button a component state needs to be updated due to a promise being resolved.但是,在单击按钮后,由于要解决承诺,需要更新组件状态。 I'll give an example below下面我举个例子

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

Now here is what my test looks like现在这是我的测试的样子

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

I've tried nesting setTimeouts so the promise from the click can resolve but that doesn't seem to work.我试过嵌套 setTimeouts 以便点击的承诺可以解决,但这似乎不起作用。 I tried to pare down my code as much as possible so it's readable.我试图尽可能地精简我的代码,以便它具有可读性。 Let me know if you need me to provide more context.如果您需要我提供更多背景信息,请告诉我。

EDIT: Made the code more closely resemble what I actually have编辑:使代码更接近我实际拥有的

There are many mistakes in your example code above that I'd highly suggest you invest some time in doing some simple React tutorials before attempting to move forward.上面的示例代码中有很多错误,我强烈建议您在尝试继续之前花一些时间做一些简单的 React 教程。

Nevertheless, here's a working example...尽管如此,这里有一个工作示例......

Working example : https://codesandbox.io/s/xj53m8lwvz (you can run the test by clicking the Tests tab near the bottom-left of the screen)工作示例https : //codesandbox.io/s/xj53m8lwvz (您可以通过单击屏幕左下角附近的“ Tests选项卡来运行测试)

api/fakeAPI.js 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组件/应用程序/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 is a custom function you can find in test/utils/index.js and WaitForExpect is an easier way to wait for an assertion to be true within jest's default 5 second timeout) components/App/__test__/App.test.jsmountWrap是一个自定义函数,您可以在test/utils/index.js找到, WaitForExpect是一种更简单的方法,可以在 jest 的默认 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);
    });
  });
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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