Ожидание двух отдельных обещаний для разрешения, поэтому состояние обновляется - PullRequest
0 голосов
/ 15 февраля 2019

Итак, я тестирую нажатие кнопки реагирующего компонента, которая меняет состояние.При рендеринге компонента мне нужно разрешить обещание, чтобы кнопка отображалась и, таким образом, нажималась.Я выполняю это, помещая нажатие кнопки внутри 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 голосов
/ 16 февраля 2019

В приведенном выше примере кода много ошибок, и я настоятельно рекомендую вам потратить некоторое время на создание простых руководств по 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);
    })
};

компоненты / приложение / приложение.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>
  );
}

компоненты / приложение / __ тест __ / приложение.test.js (mountWrap - это пользовательская функция, которую вы можете найти в test/utils/index.js, а WaitForExpect - более простой способ ожидания утверждения, равного true, в течение 5-секундного времени ожидания jest по умолчанию.)

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);
    });
  });
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...