Как выполнить модульное тестирование пользовательской функции визуализации табличных ячеек с использованием реакции, шутки и энзима? - PullRequest
0 голосов
/ 26 марта 2020

Я хотел протестировать функцию компонента класса React, которая возвращает содержимое JSX. Ниже мой код:

Продукты компонент

export default class Products extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      products: [],
    };
  }

  iconRenderer = (data) => {
    return (
      <i
        className="fa fa-qrcode fa-3x"
      >
      </i>
    );
  };

  getDisplayColumns = () => {
    return [
      {
        fieldName: 'producticon',
        displayText: 'Name',
        isEditable: false,
        visible: true,
        columnSize: 2,
        renderer: this.iconRenderer
      }
    ];
  };

  render() {
    const displayColumns = this.getDisplayColumns();
    return (
      <div className=''>
            {this.state.products && this.state.products.length > 0 &&
            <CustomTableGeneric
              tableId="item-list-table"
              data={this.state.products}
              columns={displayColumns}
            >
            </CustomTableGeneric>
            }
          </div>
    );
  }
}

CustomTableGeneri c компонент (я пытался упростить код)

export default class CustomTableGeneric extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            currentTableData: [],
            columnsToDisplay: [],
        };

        this.renderRows = this.renderRows.bind(this);
        this.renderIndividualRow = this.renderIndividualRow.bind(this);
    }

    renderIndividualRow(data, dataKeys) {
        return dataKeys.map((item, index) => {
            let currentRowId = data['id'];
            let columnWidth = this.state.columnsToDisplay[index].columnSize;
            if (item.renderer) {
                    return (
                        <Col md={columnWidth} className="table-column-cell"
                             key={index}>
                            {item.renderer(data, item.fieldName)}
                        </Col>
                    );
                } else {
                    return (
                        <Col md={columnWidth} className="table-column-cell" key={index}>{data[item.fieldName]}</Col>
                    );
                }
        });
    }

    renderRows() {
        let dataKeys = clonedeep(this.state.columnsToDisplay);
        let dataRows = clonedeep(this.state.currentTableData);
        if (dataRows.length > 0) {
            return dataRows.map((row, index) => {
                return (
                        <Row key={index} className="table-row">
                            {this.renderIndividualRow(row, dataKeys)}
                        </Row>
                    );
            });
        }
    }

    render() {
        return (
            <Row id={this.props.tableId}>
                <Col className="custom-table">
                    <Row className="table-header">
                        {this.renderHeaders()}
                    </Row>
                    {this.renderRows()}
                </Col>
            </Row>
        );
    }
}

CustomTableGeneric.propTypes = {
    tableId: PropTypes.string,
    data: PropTypes.arrayOf(PropTypes.object).isRequired,
    columns: PropTypes.arrayOf(PropTypes.shape({
        fieldName: PropTypes.string,
        displayText: PropTypes.string,
        renderer: PropTypes.func,
    })).isRequired,
};

Products.test. js

import React from 'react';
import {shallow, mount} from 'enzyme';

import CustomTableGeneric from '../../components/CustomTableGeneric';
import Products from './Products';

const props = {
  id: '123'
};

describe('Products function tests', () => {
  it('should call the iconRenderer function', () => {
    const wrapper = shallow(<Products {...props} />);
    const result = wrapper
        .instance()
        .iconRenderer();
    console.log(result);

  });
});

и ниже - вывод консоли, когда я запускаю тест.

{ '$$typeof': Symbol(react.element),
      type: 'i',
      key: null,
      ref: null,
      props: { className: 'fa fa-qrcode fa-3x' },
      _owner: null,
      _store: {} }

Как вы можете видеть, если я вызываю iconRenderer () явно из теста, он выполняется. Но я пытаюсь проверить, вызывается ли iconRenderer () при вызове компонента Products . Посмотрите, пожалуйста, как я вызываю ее внутри функции render , например Products render () -> getDisplayColumns () -> CustomTableGeneri c () -> iconRenderer ().

Ниже приведен фактический тест, который я хочу запустить

describe('Products function tests', () => {
  it('should call the iconRenderer function', () => {
    const wrapper = shallow(<Products {...props} />);
    jest.spyOn(wrapper.instance(), 'iconRenderer');
    expect(wrapper.instance().iconRenderer()).toHaveBeenCalled();
  });
});

, но я получаю ошибку ниже

Error: expect(jest.fn())[.not].toHaveBeenCalled()

jest.fn() value must be a mock function or spy.
Received:
  object: <i className="fa fa-qrcode fa-3x" />

Любое предложение высоко ценится.

1 Ответ

0 голосов
/ 26 марта 2020

На мой взгляд, у вашего кода есть две проблемы:

  1. Вы случайно вызываете макетированную функцию в expect, что приводит к ошибке: expect получает возврат значение издевательства iconRenderer, а не само издевательство. Измените expect строку на:

    expect(wrapper.instance().iconRenderer).toHaveBeenCalled();
    
  2. Вам необходимо смоделировать iconRenderer перед рендерингом Product, поэтому он вызывается при рендеринге Product. Таким образом, перед этой строкой нужно его посмеяться:

    const wrapper = shallow(<Products {...props} />);
    

    Вы можете увидеть пример того, как это сделать, в этом вопросе .

...