Используя withRouter и connect, как можно утверждать в ферменте, что был вызван файл history.pu sh? - PullRequest
0 голосов
/ 19 июня 2020

Я использую withRouter и подключаюсь к компоненту React без сохранения состояния. У меня есть кнопка в компоненте, который вызывает метод в props, который предоставляется mapDispatchToProps.

Я пытаюсь написать тест, который утверждает, что нажатие кнопки вызывает history.pu sh ().

Пока не могу найти способ это сделать. В некоторых местах говорят, что передача имитационного объекта истории вроде этого

const historyMock = { push: jest.fn() };
...
<MyComponent history={mockHistory}/>

сделает это, но это не сработает. Я думаю, что вызов withRouter перезаписывает его. Я также попытался разместить это в Provider и Router. Ничего не работает.

Я также пробовал издеваться над mapDispatchToProps или иным образом настраивать шпион на setHistory. Все это кажется невозможным.

Я также пробовал шпионить за функцией MyComponent, чтобы передать ей пропсы - тоже невозможно.

wrapper.setProps () - тоже не работает.

У меня есть эти файлы.

my.component.container.jsx

import React from 'react';
import { Button } from '@material-ui/core';

const MyComponent = (props) => {
    const {setHistory, id} = props;
    return (
        <React.Fragment>
            <Button id="history_button" onClick={() => {
                setHistory(id)
            }}>View</Button>
        </React.Fragment>
    )
};

export default MyComponent;

my.component. js

import { connect } from 'react-redux';
import { withRouter } from 'react-router';
import MyComponentContainer from './my.component.container';

export const mapStateToProps = (state) => {
    const id = state?.data?.id || null;
    return {id};
};

export const mapDispatchToProps = (dispatch, ownProps) => {
    return {
        setHistory: (id) => {
            const {history} = ownProps;
            history.push(`/path/${id}`);
        },
    };
};

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(MyComponentContainer));

my.component .test. js

import React from 'react';
import { BrowserRouter as Router } from "react-router-dom";
import MyComponent from './my.component';
import { Provider } from 'react-redux'
import configureStore from 'redux-mock-store'
import { mount } from 'enzyme';

describe('MyComponent', () => {

    afterEach(function() {
        jest.clearAllMocks();
        jest.restoreAllMocks();
    });

    const getNode = (wrapper, search) => {
        return wrapper.find(search).hostNodes();
    };

    it('history buttons calls history.push()', () => {
        const initialState = {data: {id: 'id-1'}};
        const mockStore = configureStore();
        const store = mockStore(initialState);
        const wrapper = mount(<Provider store={store}><Router><MyComponent/></Router></Provider>);
        const button = getNode(wrapper, '#history_button');
        button.simulate('click');
        // to do - assert that history.push was called with '/path/id-1'
    });
});

И я выброшу это как решение, которое мне не очень нравится. Я хочу шпионить за историческим объектом в целом.

expect(window.history.length).toEqual(1);
expect(window.location.href).toEqual('http://localhost/');

button.simulate('click');

expect(window.history.length).toEqual(2);
expect(window.location.href).toEqual('http://localhost/path/id-1');

1 Ответ

1 голос
/ 20 июня 2020

Я попытался передать историю в компонент Router, как и вы:

<Router history={historyMock}>

Когда я запустил тест, он сказал:

  console.warn node_modules/tiny-warning/dist/tiny-warning.cjs.js:13
    Warning: <BrowserRouter> ignores the history prop. To use a custom history, use `import { Router }` instead of `import { BrowserRouter as Router }`.

Как только я изменил импорт как он предложил, передавая Router, фиктивный объект истории работал.

my.component.test. js

import React from 'react';
// import { BrowserRouter as Router } from "react-router-dom"; // Warning: <BrowserRouter> ignores the history prop. To use a custom history, use `import { Router }` instead of `import { BrowserRouter as Router }`.
import { Router } from "react-router-dom";
import MyComponent from './my.component';
import { Provider } from 'react-redux'
import configureStore from 'redux-mock-store'
import { mount } from 'enzyme';

describe('MyComponent', () => {

    afterEach(function() {
        jest.clearAllMocks();
        jest.restoreAllMocks();
    });

    const getNode = (wrapper, search) => {
        return wrapper.find(search).hostNodes();
    };

    it('history buttons calls history.push()', () => {
        const initialState = {data: {id: 'id-1'}};
        const mockStore = configureStore();
        const store = mockStore(initialState);
        const historyMock = {
            listen: () => {},
            location: {
                pathname: 'fake-path-name',
            },
            push: jest.fn(),
        };
        const wrapper = mount(<Provider store={store}><Router history={historyMock}><MyComponent history={'this is ignored and useless'}/></Router></Provider>);
        const button = getNode(wrapper, '#history_button');

        button.simulate('click');

        expect(historyMock.push).toHaveBeenCalledTimes(1);
        expect(historyMock.push).toHaveBeenCalledWith('/path/id-1');
    });
});
...