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而不是在异步操作创建者上返回诺言。