Как проверить обратный вызов компонента, вызванный обратным вызовом дочернего компонента в React with Enzyme?

Скажем, у меня есть следующее приложение:

class Child extends React.Component {
    render() {
        return <button onClick={this.handleChildOnClick}>{this.props.children}</button>;
    }

    handleChildOnClick() {
        this.props.onChildClick('foo');
    }
}

class Parent extends React.Component {
    render() {
        return <Child onChildClick={this.handleParentOnClick}>click me</Child>;
    }

    handleParentOnClick(text) {
        this.props.onParentClick(12345);
    }
}

class App extends React.Component {
    render() {
        return <Parent onParentClick={(num) => console.log(num)} />;
    }
}

Мне трудно понять, как правильно протестировать компонент Parent. Child и App не проблема, а _5 _...

Я имею в виду, как мне проверить, что щелчок по компоненту Child будет вызывать обратный вызов Parent без:

  1. ... рендеринг Child. Parent следует тестировать изолированно как неглубокий рендер. Child также будет протестирован изолированно, и если я сделаю рендеринг монтирования, я в основном дважды проверяю обратный вызов щелчка на Child.
  2. ... прямой вызов handleParentOnClick в экземпляре Parent. Я не должен полагаться в этом на точную реализацию Parent. Если я изменю имя функции обратного вызова, тест прервется, и это вполне может быть ложным срабатыванием.

Есть третий вариант?


person rfgamaral    schedule 26.01.2017    source источник


Ответы (2)


Во время тестирования Parent вы можете:

import { shallow } from 'enzyme';
import { stub } from 'sinon';

describe('<Parent/>', () => {
  it('should handle a child click', () => {
    const onParentClick = stub();
    const wrapper = shallow(<Parent onParentClick={onParentClick} />);
    wrapper.find("Child").prop('onChildClick')('foo');
    expect(onParentClick.callCount).to.be.equal(1);
    // You can also check if the 'foo' argument was passed to onParentClick
  });
});
person Andrei Baibaratsky    schedule 26.01.2017
comment
Метод Enzyme find принимает класс React в качестве селектора, поэтому вы, вероятно, захотите удалить кавычки вокруг Child (строка 8). Кроме того, это почти дословный ответ, который я бы дал - person Jordan Bonitatis; 26.01.2017
comment
Это был ответ, который я искал, большое спасибо =) @JordanBonitatis. Для этого потребуется дополнительный импорт, а в примере с цитатой - нет. Помимо того, что строка более подвержена ошибкам, есть ли другое преимущество в передаче класса по сравнению со строкой в ​​качестве селектора? - person rfgamaral; 26.01.2017
comment
У меня это не работает в случае, когда дочерний класс является компонентом MaterialUI. Любые идеи не приходят в голову, почему? - person TokyoMike; 25.08.2018

Я думаю, это может дать вам некоторое представление.

// Компонент

class Child extends React.Component {
  render() {
    return <button onClick={this.handleChildOnClick} className="t-btn">{this.props.children}</button>;
  }
  handleChildOnClick() {
    this.props.onChildClick('foo');
  }
}

// Контрольная работа

import { spy, stub } from 'sinon';
import { shallow } from 'enzyme';

describe('Child Component', () => {
  it('should check handle click', () => {
    spy(Child.prototype, 'handleChildOnClick');
    const onChildClick = stub();
    const wrapper = shallow(<Child onChildClick={onChildClick}>);
    wrapper.find(".t-btn").simulate('click');
    expect(Child.prototype.handleChildOnClick.callCount).to.equal(1);
  });

  it('should check onChildClick', () => {
    const onChildClick = stub();
    const wrapper = shallow(<Child onChildClick={onChildClick}>);
    wrapper.find(".t-btn").simulate('click');
    expect(onChildClick.callCount).to.equal(1);
  });
});

Чтобы проверить родительский элемент с дочерним компонентом

import { stub } from 'sinon';
import { shallow } from 'enzyme';
import Child from '../Components/Child';

describe('Parent Component', () => {
  it('should check handle click', () => {
    const onParentClick = stub();
    const wrapper = shallow(<Parent onParentClick={onParentClick} />);
    wrapper.find(".t-btn").simulate('click');
    expect(Child.prototype.handleChildOnClick.callCount).to.equal(1);
  });

  it('should check onChildClick', () => {
    const onChildClick = stub();
    const wrapper = shallow(<Child onChildClick={onChildClick}>);
    wrapper.find(Child).prop('onChildClick')('foo');
    expect(onParentClick.callCount).to.be.equal(1);
  });
});

Приведенный выше код обрабатывает только один компонент, но я надеюсь, что это может дать вам некоторую суть. Извините, если синтаксис где-то нарушается ..

person anoop    schedule 26.01.2017
comment
Это был не тот ответ, который я искал ... Вы просто тестируете компонент Child, а не компонент Parent (о котором был вопрос). Тем не менее, спасибо за ваш вклад. - person rfgamaral; 26.01.2017