Sinon.spy()

#javascript #reactjs #redux #jestjs #enzyme

#javascript #reactjs #redux #jestjs #фермент

Вопрос:

Я пытаюсь подсмотреть метод «getTableData» или любой другой метод компонента класса, используя jest «spyOn» или sinon «spy». Все время получать:

Cannot spy the getTableData property because it is not a function; undefined given instead с помощью jest spyOn и

TypeError: Attempted to wrap undefined property getTableData as function с помощью sinon spy.

Также компонент, метод которого я тестирую, обернут специальным компонентом, который использует redux connect. Затем я попытался экспортировать его без HOC, но тест по-прежнему не работает с той же ошибкой

Обратите внимание, что const spy = jest.spyOn(wrapper.instance(), "getTableData"); это нормально работает только с компонентом, экспортируемым без HOC!

Что я уже пробовал:

 const spy = sinon.spy(MonthlyProjectPlan.prototype, 'getTableData');

//const spy = jest.spyOn(MonthlyProjectPlan.prototype, 'getTableData');

    const wrapper = mount(
      //<Provider store={store}>
            <MonthlyProjectPlan {...propsPanel} />
      //</Provider>
    );
 
 export class MonthlyProjectPlan extends React.Component {
  groupBy = (list, keyGetter) => {
    //some secret magic
  };

  getTableData = () => {
    let result = [];
    if (this.props.data) {
      let groupedData = this.groupBy(this.props.data, item => item.commodity);
      // magic
    }
    return result
  };

  getTableColumns = () => {
    let tableData = this.getTableData();
    let columns = [
      {Header: 'Commodities', accessor: 'commodity', width: 300}
    ];

    if (tableData.length > 0) {
      let months = tableData[0].data.map(item => item.year_month_date);
      let monthsColumns = months.map((item, key) => {
        //magic
      });
      columns.push(...monthsColumns)
    }
    return columns
  };

  render() {
    if (!this.props.data)
      return (<LoadingBar/>);
    if (this.props.data.length < 1)
      return (<NoData/>);

    return (
      <div>
        <ReactTable data={this.getTableData()}
                    className="monthly-pipeline__table"
                    columns={this.getTableColumns()}
                    defaultSorted={[{id: "commodity", desc: false}]}
                    showPageSizeOptions={false}
                    showPagination={false}
                    minRows={false}/>

        <div className="monthly-pipeline-help">
          <div className="monthly-pipeline-help__title">
            Monthly Pipeline Shortfalls Percent
          </div>

          <table className="monthly-pipeline-help__table">
            <tbody>
            <tr>
              <td style={{backgroundColor: colors.darkGreen}}>0% - 25%</td>
              <td style={{backgroundColor: colors.yellow}}>26% - 50%</td>
              <td style={{backgroundColor: colors.orange}}>51% - 75%</td>
              <td style={{backgroundColor: colors.red}}>76% - 100%</td>
            </tr>
            </tbody>
          </table>

        </div>
      </div>
    )
  }
}

export default Panel(MonthlyProjectPlan)
 

Приведенный ниже тест не работает

 it("should render MonthlyProjectPlan Global component correctly", () => {
    const spy = sinon.spy(MonthlyProjectPlan.prototype, 'getTableData');
    //const spy = jest.spyOn(MonthlyProjectPlan.prototype, 'getTableData');
    const wrapper = mount(
      //<Provider store={store}>
      <MonthlyProjectPlan {...propsPanel} />
      //</Provider>
    );
 

ошибки:

«Невозможно просмотреть свойство getTableData, потому что оно не является функцией; вместо этого задано неопределенное» с помощью jest spyOn

и

«Ошибка типа: попытка обернуть неопределенное свойство getTableData как функцию» с помощью sinon spy.

Это работает нормально, но только с компонентом, экспортируемым без HOC

   it("should render MonthlyProjectPlan Global component correctly", () => {
    const wrapper = mount(
      //<Provider store={store}>
      <MonthlyProjectPlan {...propsPanel} />
      //</Provider>
    );
    // const spy = jest.spyOn(wrapper.instance(), "getTableData");
    // wrapper.instance().forceUpdate();
    // expect(spy).toHaveBeenCalled();
    // expect(spy.mock.calls.length).toBe(5);
 

Ответ №1:

Вы определяете метод getTableData как свойство класса. Следовательно, метод не определен в прототипе. Вместо этого это свойство созданного вами экземпляра.

Это означает, что код (упрощенная версия предоставленного вами кода):

 export class MonthlyProjectPlan {
    getTableData = () => {
        let result = [];
        if (this.props.data) {
            let groupedData = this.groupBy(this.props.data, item => item.commodity);
            // magic
        }
        return result
    };

    render() {

    }
}
 

такое же, как:

 function MonthlyProjectPlan() {
    this.getTableData = function() {
        let result = [];
        if (this.props.data) {
            let groupedData = this.groupBy(this.props.data, item => item.commodity);
            // magic
        }
        return result
    };
}

MonthlyProjectPlan.prototype.render = function() {};
 

Обратите внимание, что метод getTableData не определен в прототипе класса MonthlyProjectPlan, а новый метод создается для каждого экземпляра создаваемого вами класса.

Из-за этого MonthlyProjectPlan.prototype.getTableData оно не определено, и вы не можете его отслеживать.

Комментарии:

1. можете ли вы объяснить это, пожалуйста: «Вы определяете метод getTableData как свойство класса. Следовательно, метод не определен в прототипе. Вместо этого это свойство созданного вами экземпляра. » Почему это происходит и что я должен сделать, чтобы мой тест работал?

2. Я отредактировал свой ответ, чтобы подробнее объяснить, что я имел в виду. Надеюсь, это поможет!