如何使用Jest通过Axios(异步/等待)和Redux Thunk测试异步Redux Action Creators?

时间:2020-06-29 19:46:13

标签: reactjs redux react-redux jestjs axios

TL; DR:当异步操作创建者不返回承诺而是使用异步/等待时,如何使用Jest测试异步Redux操作创建者,以使用Axios从API提取数据? < / p>

export const getConfig = () => async (dispatch: Dispatch): Promise<void> => {
    dispatch(requestConfig());

    const { data } = await axios.get(endpoints.config);

    dispatch(requestConfigFinished(data.data.items));

    // ...
};

为了执行异步调度,我使用Redux Thunk中间件。例如,我有一个名为getConfig的动作创建者,该动作创建者调度一个动作requestConfig,然后使用Axios从API中获取一些配置,然后在API返回错误或数据时调度另一个动作。 / p>

请注意,对于异步代码,我更喜欢async / await而不是Promise。在下面的代码中,对于该项目,我使用TypeScript。

Redux动作(actions.ts):

export const getConfig = () => async (dispatch: Dispatch): Promise<void> => {
    dispatch(requestConfig());

    try {
        const { data } = await axios.get('api/config');

        if (data.status === 200 && data.data && data.data.items) {
            dispatch(requestConfigFinished(data.data.items));
        } else {
            dispatch(requestConfigFinished(data.error, true));
        }
    } catch (error) {
        const { response } = error;
        dispatch(requestConfigFinished(response.data.error, true));
    }
};

export const requestConfig = (): ConfigActionTypes => {
    return {
        type: REQUEST_CONFIG,
    };
};

export const requestConfigFinished = (payload?: object, error?: boolean): ConfigActionTypes => {
    return {
        type: REQUEST_CONFIG_FINISHED,
        payload,
        error,
    };
};

然后可以从组件中调用getConfig动作创建者。例如:

function App(props: Props) {
    const { getConfig: dispatchGetConfig } = props;

    useEffect(() => {
        dispatchGetConfig();
    }, [dispatchGetConfig]);

    // ...
}

const mapDispatch = {
    getConfig
};

export default connect(null, mapDispatch)(Foo);

所有代码都适用。

现在,我想使用Jest测试Redux动作。

测试同步动作创建者非常简单。我已经成功测试了两个requestConfig and requestConfigFinished`:

describe('requestConfig', () => {
    it('dispatches REQUEST_CONFIG before fetching config', () => {
        const expectedAction = {
            type: REQUEST_CONFIG,
        };

        expect(actions.requestConfig()).toEqual(expectedAction);
    });
});

describe('requestConfigFinished', () => {
    it('dispatches REQUEST_CONFIG_FINISHED when fetching config has been done', () => {
        const expectedAction = {
            type: REQUEST_CONFIG_FINISHED,
            payload: mockData.data.items,
        };

        expect(actions.requestConfigFinished(mockData.data.items)).toEqual(expectedAction);
    });
});

对于异步动作创建者,有一个关于Redux (see here)官方文档的出色教程。但是,此示例不使用异步/等待。文档中的fetchTodos动作创建者直接返回了Promise。我尝试了几次(很多小时!)来更改我的代码,但是测试失败了。

N.B .:我尝试使用和不使用jest-mock-axios(repository here)来模拟Axios。如果我可以编写第一个Jest测试来测试动作创建者而不模拟Axios调用,那么我可能是第一步...

我最后一次尝试:

import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import mockAxios from 'jest-mock-axios';

const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);

const mockData = {
    status: 200,
    data: {
        items: {
            'foo': 'bar'
        },
    },
    error: {
        message: null,
        items: [],
    },
};

afterEach(() => {
    mockAxios.reset();
});

describe('getConfig', () => {
    it('dispatches REQUEST_CONFIG and REQUEST_CONFIG_FINISHED from mock data', async () => {
        const expectedActions = [
            { type: REQUEST_CONFIG }, 
            { type: REQUEST_CONFIG_FINISHED, payload: mockData.data.items }
        ];

        const store = mockStore({});

        await actions.getConfig();

        expect(store.getActions()).toEqual(expectedActions);
    });
});

笑话输出:

FAIL  src/__tests__/actions.ts
  ● getConfig › dispatches REQUEST_CONFIG and REQUEST_CONFIG_FINISHED from mock data

    expect(received).toEqual(expected) // deep equality

    - Expected
    + Received

    - Array [
    -   Object {
    -     "type": "REQUEST_CONFIG",
    -   },
    -   Object {
    -     "payload": Object {
    -       "foo": "bar"
    -     },
    -     "type": "REQUEST_CONFIG_FINISHED",
    -   },
    - ]
    + Array []

      39 |             await actions.getConfig();
      40 | 
    > 41 |             expect(store.getActions()).toEqual(expectedActions);
         |                                        ^

任何帮助将不胜感激!谢谢。

PS:我的问题是不是this question的副本,因为我使用了一个不同的模拟库和async / await而不是在异步操作创建者上返回诺言。

0 个答案:

没有答案