Тестирование компонента, подключенного к редуксу

У меня есть следующий подключенный компонент в React-Redux

export class IncrementalSearch extends React.Component {

    constructor(props) {
        super(props);
        this.onSearch$ = new Subject();
        this.onChange = this.onChange.bind(this);
    }

    componentDidMount() {
        this.subscription = this.onSearch$
            .debounceTime(300)
            .subscribe(debounced => {
                this.props.onPerformIncrementalSearch(debounced);
            });
    }

    componentWillUnmount() {
        if (this.subscription) {
            this.subscription.unsubscribe();
        }
    }

    onChange(e) {
        const newText = e.target.value;
        this.onSearch$.next(newText);
    }

    render() {
        return (
            <div className={styles.srchBoxContaner}>
                <input
                    className={styles.incSrchTextBox}
                    type="text" name="search" id="searchInput" placeholder="Search.."
                    onChange={this.onChange}
                />
            </div>
        );
    }
}

const mapDispatchToProps = (dispatch) => ({
    onPerformIncrementalSearch: (searchText) => {
        dispatch(performIncrementalStoreSearch(searchText));
    }
});

const IncrementalSearchComponent = connect(null, mapDispatchToProps)(IncrementalSearch);
export default IncrementalSearchComponent;

Сейчас я пытаюсь написать модульные тесты для подключенного компонента. Я использую Jest, Enzyme и Sinon. Пока так выглядит мой модульный тест

it('calls \'onPerformIncrementalSearch\' when the user types in something', () => {
    const mockStore = configureStore();

    const onPerformIncrementalSearchSpy = sinon.spy();
    const mapStateToProps = null;
    const mapDispatchToProps = {
        onPerformIncrementalSearch: onPerformIncrementalSearchSpy
    };

    const mappedProps = { mapStateToProps, mapDispatchToProps };

    const incrementalSearchWrapper =
        mount(
            <Provider store={mockStore}>
                <IncrementalSearchComponent
                    onPerformIncrementalSearch={onPerformIncrementalSearchSpy}
                    props={mappedProps}
                    store={mockStore}
                />
            </Provider>
        );


    //find the input element
    const searchInput = incrementalSearchWrapper.find('#searchInput');
    searchInput.node.value = 'David';
    searchInput.simulate('change', searchInput);
    expect(onPerformIncrementalSearchSpy.called).toEqual(true);
    // onChangeSpy.restore();
});

Однако, когда я запускаю этот тест, я получаю следующую ошибку

TypeError: Не удается прочитать свойство 'bind' неопределенного

Как я могу это исправить?


person tmp dev    schedule 10.08.2017    source источник


Ответы (1)


Тестирование подключенных компонентов может быть очень болезненным. Я считаю, что пытаться обернуть ваши компоненты с помощью Provider, чтобы дать им доступ к хранилищу, больше проблем, чем того стоит.

Вместо этого я бы просто экспортировал компонент, mapStateToProps и mapDispatchToProps и протестировал их по отдельности. Ваше приложение будет работать так же, если вы экспортируете подключенный компонент по умолчанию.

Дэн Абрамов (соавтор Redux) предлагает этот подход в этом комментарии

Я бы также посоветовал изучить поверхностный рендеринг ферментов. использования mount при тестировании подключенных компонентов.

person bill    schedule 10.08.2017
comment
Но подключенный компонент — это больше, чем просто mapStateToprops и mapDispatchToProps, в компоненте есть другая логика, которую мне нужно протестировать. Поэтому, как мне проверить это? - person tmp dev; 11.08.2017
comment
Вы все еще можете проверить логику в компоненте с помощью этого подхода. У вас будет только два exports. Один из них — экспортировать подключенный компонент export default connect ..., а затем импортировать его в свое приложение через import { default as myComponent }. Вы также можете экспортировать несвязанный компонент, например export class myComponent, и импортировать в свой тест, например import { myComponent }. Затем вы можете протестировать всю логику компонента, не беспокоясь о доступе к хранилищу и тестировании подключенного компонента. - person bill; 11.08.2017
comment
Этот ответ может помочь в дальнейшем объяснении. - person bill; 11.08.2017
comment
может быть, я чего-то не понимаю, я экспортировал как подключенный, так и неподключенный компонент, проблема возникает, когда я просто пытаюсь смонтировать или отшлифовать подключенный компонент, просто чтобы проверить его логику. Есть ли рабочий пример, который я мог бы использовать? - person tmp dev; 11.08.2017
comment
У вас все еще будет та же проблема, если вы попытаетесь смонтировать (или поверхностно смонтировать) подключенный компонент. Экспорт подключенного компонента предназначен исключительно для доступа к нему в вашем приложении, а не в ваших тестах. Я бы просто импортировал несвязанный компонент и проверил его. Вы по-прежнему сможете протестировать всю логику компонента, за исключением того, что connect работает. Если есть какая-то другая логика, которую нужно протестировать через монтирование подключаемого компонента, то этот подход вам не подходит. - person bill; 11.08.2017
comment
Да, это вся моя забота, у меня есть некоторая логика в подключенном компоненте, который я хочу протестировать, и по какой-то причине я не могу его смонтировать. - person tmp dev; 12.08.2017
comment
Смысл Билла в том, что вам не нужно тестировать функцию connect, так как это не ваш код. Весь ваш код находится в несвязанном компоненте и mapState/DispatchToProps. Если вы проверите их, то вы проверили всю свою логику. - person stone; 12.12.2017