首页 文章

模拟由Redux Provider组件包含的React组件函数

提问于
浏览
2

这是我的情况:我正在尝试对React组件(TodoList)进行单元测试,该组件在Render方法上不做任何事情,而不是映射项目并显示它们 . 它通过使用MapStateToProps从Redux商店获取项目(TodoItem) .

这是TodoList组件的javascript代码:

class TodoList extends React.Component {
    onRemoveClick = (id) => {
        diContainer.dataLayer.todo.remove(id);
    }

    render() {
        const todos = this.props.todos;
        if(!todos)
            return null;

        return (
            todos.map(todo => (
                <TodoItem key={todo.id} todo={todo} onRemove={this.onRemoveClick} />
            ))    
        );
    }
}

const mapStateToProps = (state) => ({
    todos: state.todos
});

export default connect(mapStateToProps)(TodoList);

我现在要测试的是,只要调用TodoItem(子对象)中的按钮,就会调用onRemoveClick委托方法 .

我尝试使用Jest提供的函数mocking与Enzyme一起使用 . 但是,因为TodoList从Redux获取数据,所以我必须使用Provider组件包围我的Enzyme mount()调用并模拟商店 .

这是我的测试代码:

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

import { Provider } from 'react-redux';
import configureStore from 'redux-mock-store';

import TodoList from '../../../../react/components/todo/TodoList';

describe('TodoList component', () => {
    //global arrange
    const storeState = {
       todos: [
                {
                    id: 'testId1',
                    title: 'testTitle1',
                    description: 'testDescription1'
                },
                {
                    id: 'testId2',
                    title: 'testTitle2',
                    description: 'testDescription2'
                },
        ]
    };

    const mockStore = configureStore();
    let store;

    beforeEach(() => {
        store = mockStore(storeState)
    });

    it('Removes a todo from the list if the remove button the todo was pressed', () => {
        //arrange
        //let mockFn = jest.fn();
        //TodoList.prototype.onRemoveClick = mockFn; => tried, doesn't work...

        const component = mount(
            <Provider store={store}>
                <TodoList />
            </Provider>
        );

        //component.instance() => tried working with this, but couldn't find it
        //component.instance().children() => is not the TodoList

        const items = component.find('.todoItem');

        //act
        const button = items.first().find('button');
        button.simulate('click');

        //assert
        //Todo: check function spy here
    });
});

我评论了一些我尝试过的东西 . 但我似乎无法在我的测试代码中访问TodoList组件,因为Provider包装器......

有线索吗?

1 回答

  • 2

    通过大量的试验和错误得到了解决 . 我能够通过酶查找功能访问TodoList,这显然也适用于ComponentNames(而不仅仅是纯HTML选择器) .

    第二个技巧是在TodoList组件上调用forceUpdate()并在父包装器上调用update() .

    it('Removes a todo from the list if the remove button on the todo was pressed', () => {
        //arrange
        const component = mount(
            <Provider store={store}>
                <TodoList />
            </Provider>
        );
    
        const list = component.find('TodoList').instance();
        let mockFn = jest.fn();
        list.onRemoveClick = mockFn;
    
        list.forceUpdate();
        component.update();
    
        //act
        const items = component.find('.todoItem');
        const button = items.first().find('button');
        button.simulate('click');
    
        //assert
        expect(mockFn).toHaveBeenCalled();
        expect(mockFn).toHaveBeenCalledTimes(1);
        expect(mockFn).toHaveBeenCalledWith('testId1');
    });
    

相关问题