Как получить функцию обернутого компонента HOC от экземпляра фермента при монтаже? - PullRequest
0 голосов
/ 14 декабря 2018

У меня есть родительский компонент -> дочерние компоненты, а дочерний элемент запускает выборку внутри componentDidMount.Выборка устанавливает состояние в хранилище с избыточностью, которое находится выше родительского, и это заставляет дочерний компонент отображаться по-разному.

Дочерний объект также использует material-ui withStyles, поэтому он создает HOC вокруг компонента.

В моем тесте мне нужно смонтировать родительский компонент, найти дочерний компонент, а затем увидеть, что выборка правильно изменила состояние и вызвала обновление дочернего компонента.

Мое решение до сих порэто:

  • смонтировать родителя, найти дочернего элемента
  • call child.instance().fetchFunction().then(() => expect(..))

Однако, вызов instance() на child возвращает HOC, итаким образом я получаю ошибку:

child.instance (...). fetchFunction не является функцией

Все решения, которые я видел, используют shallow и dive чтобы обойти HOC, но если я использую shallow, мне нужно будет создать фиктивный магазин в тесте, и он на самом деле не будет тестировать это как интеграционный тест.

Я мог бы протестировать человекавызвать вызов, а затем протестировать компонент с помощью shallow и передать ему реквизиты, как если быЕли были изменены, но это не доказывает, что все это работает вместе.

Вот коды и поле, где я воспроизвел проблему:

Edit Testing Async componentDidMount

Вот пример кода (в основном это коды и поле):

App.js

import React from "react";
import Child from "./Child";

class App extends React.Component {
  render() {
    return <Child />;
  }
}

export default App;

Child.js

import React from "react";
import { withStyles } from "@material-ui/core/styles";

const childStyles = {
  margin: 0
};

class Child extends React.Component {
  state = {
    groceries: [],
    errorStatus: ""
  };

  componentDidMount() {
    console.log("calling fetch");

    this.fetchCall();
  }

  fetchCall = () => {
    return fetch("/api/v1/groceries")
      .then(this.checkStatus)
      .then(this.parseJSON)
      .then(this.setStateFromData)
      .catch(this.setError);
  };

  checkStatus = results => {
    if (results.status >= 400) {
      console.log("bad status");

      throw new Error("Bad Status");
    }

    return results;
  };

  setError = () => {
    console.log("error thrown");

    return this.setState({ errorStatus: "Error fetching groceries" });
  };

  parseJSON = results => {
    console.log("parse json");

    return results.json();
  };

  setStateFromData = data => {
    console.log("setting state");

    return this.setState({ groceries: data.groceries });
  };

  render() {
    const { groceries } = this.state;

    return (
      <div id="app">
        {groceries.map(grocery => {
          return <div key={grocery.id}>{grocery.item}</div>;
        })}
      </div>
    );
  }
}

export default withStyles(childStyles)(Child);

App.test.js

import Enzyme from "enzyme";
import Adapter from "enzyme-adapter-react-16";
import React from "react";
import { mount } from "enzyme";
import App from "./App";
import Child from "./Child";

Enzyme.configure({ adapter: new Adapter() });

const mockResponse = (status, statusText, response) => {
  return new window.Response(response, {
    status: status,
    statusText: statusText,
    headers: {
      "Content-type": "application/json"
    }
  });
};

describe("App", () => {
  describe("ChildApp componentDidMount", () => {
    it("sets the state componentDidMount", () => {
      console.log("starting test for 200");

      global.fetch = jest.fn().mockImplementation(() =>
        Promise.resolve(
          mockResponse(
            200,
            null,
            JSON.stringify({
              groceries: [{ item: "nuts", id: 10 }, { item: "greens", id: 3 }]
            })
          )
        )
      );

      const renderedComponent = mount(<App />);
      const childApp = renderedComponent.find(Child);

      childApp
        .instance()
        .fetchCall()
        .then(() => {
          console.log("finished test for 200");
          expect(childApp.state("groceries").length).toEqual(2);
        });
    });

    it("sets the state componentDidMount on error", () => {
      console.log("starting test for 500");

      window.fetch = jest
        .fn()
        .mockImplementation(() =>
          Promise.resolve(
            mockResponse(
              400,
              "Test Error",
              JSON.stringify({ status: 400, statusText: "Test Error!" })
            )
          )
        );

      const renderedComponent = mount(<App />);
      const childApp = renderedComponent.find(Child);
      childApp
        .instance()
        .fetchCall()
        .then(() => {
          console.log("finished test for 500");
          expect(childApp.state("errorStatus")).toEqual(
            "Error fetching groceries"
          );
        });
    });
  });
});

1 Ответ

0 голосов
/ 14 декабря 2018

После написания этого я нашел ответ, но мне кажется, что этим стоит поделиться, потому что я был очень смущен этим.

Вместо использования app.find(Child) (конструктор компонента), используйте app.find('Child')(отображаемое имя компонента).При этом будет найден фактический компонент, а не специальный компонент.

энзимодокументы для поиска (селектор)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...