如何作为一个单元正确测试 Redux Saga 中的 api 调用?
How to test api call in Redux Saga properly as a unit?
我想测试这个 saga API 函数:
export function* fetchEshopProjects(action: ProjectActionsGetEshopProjects) {
yield put(projectActions.currentEshopProjectsLoading(true))
const response: {
projects: string[],
error: Error
} = yield call(ajax.json, '/new-project/eshops-projects/?eshopId=' + action.eshopId)
if (response.error) {
yield put(projectActions.currentEshopProjectsFailed(response.error))
yield put(projectActions.currentEshopProjectsLoading(false))
} else {
yield put(projectActions.setCurrentEshopProjects(response.projects))
yield put(projectActions.currentEshopProjectsLoading(false))
}
}
我写了这个测试:
test('fetch projects', async() => {
mockParams({
locale: 'en-US',
});
ajax.json = jest.fn().mockResolvedValue(['kbp', 'tbp'])
const dispatched = []
await runSaga({
dispatch: (action) => dispatched.push(action),
},
fetchEshopProjects
)
expect(dispatched).toEqual([
{
type: 'CURRENT_ESHOP_PROJECTS_LOADING',
loadingState: true,
},
{
type: 'SET_CURRENT_ESHOP_PROJECTS',
payload: ['kbp', 'tbp'],
},
{
type: 'CURRENT_ESHOP_PROJECTS_LOADING',
loadingState: false,
},
])
})
似乎代码只到达 yield call(ajax.json...
部分然后 returns 返回到测试功能 - 因此只记录了第一次调度。我怎样才能更正测试以使其成功结束?
您忘记为 runSaga
返回的任务使用 task.toPromise。下面是一个工作示例:
saga.ts
:
import { call, put } from 'redux-saga/effects';
import { ajax } from './ajax';
export const projectActions = {
currentEshopProjectsLoading(loadingState) {
return { type: 'CURRENT_ESHOP_PROJECTS_LOADING', loadingState };
},
setCurrentEshopProjects(payload) {
return { type: 'SET_CURRENT_ESHOP_PROJECTS', payload };
},
currentEshopProjectsFailed(error) {
return { type: 'CURRENT_ESHOP_PROJECTS_FAILED', error };
},
};
export function* fetchEshopProjects(action) {
yield put(projectActions.currentEshopProjectsLoading(true));
const response: {
projects: string[];
error: Error;
} = yield call(ajax.json, '/new-project/eshops-projects/?eshopId=' + action.eshopId);
if (response.error) {
yield put(projectActions.currentEshopProjectsFailed(response.error));
yield put(projectActions.currentEshopProjectsLoading(false));
} else {
yield put(projectActions.setCurrentEshopProjects(response.projects));
yield put(projectActions.currentEshopProjectsLoading(false));
}
}
ajax.ts
:
export const ajax = {
async json(url) {},
};
saga.test.ts
:
import { runSaga } from 'redux-saga';
import { ajax } from './ajax';
import { fetchEshopProjects } from './saga';
test('fetch projects', async () => {
ajax.json = jest.fn().mockResolvedValue({ projects: ['kbp', 'tbp'] });
const dispatched: any[] = [];
await runSaga(
{
dispatch: (action) => dispatched.push(action),
},
fetchEshopProjects as any,
{ eshopId: '123' },
).toPromise();
expect(dispatched).toEqual([
{
type: 'CURRENT_ESHOP_PROJECTS_LOADING',
loadingState: true,
},
{
type: 'SET_CURRENT_ESHOP_PROJECTS',
payload: ['kbp', 'tbp'],
},
{
type: 'CURRENT_ESHOP_PROJECTS_LOADING',
loadingState: false,
},
]);
});
测试结果:
PASS redux-saga-examples packages/redux-saga-examples/src/Whosebug/71176872/saga.test.ts
✓ fetch projects (6 ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 81.25 | 75 | 60 | 81.25 |
ajax.ts | 100 | 100 | 0 | 100 |
saga.ts | 80 | 75 | 75 | 80 | 12,25-26
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 2.623 s, estimated 3 s
我想测试这个 saga API 函数:
export function* fetchEshopProjects(action: ProjectActionsGetEshopProjects) {
yield put(projectActions.currentEshopProjectsLoading(true))
const response: {
projects: string[],
error: Error
} = yield call(ajax.json, '/new-project/eshops-projects/?eshopId=' + action.eshopId)
if (response.error) {
yield put(projectActions.currentEshopProjectsFailed(response.error))
yield put(projectActions.currentEshopProjectsLoading(false))
} else {
yield put(projectActions.setCurrentEshopProjects(response.projects))
yield put(projectActions.currentEshopProjectsLoading(false))
}
}
我写了这个测试:
test('fetch projects', async() => {
mockParams({
locale: 'en-US',
});
ajax.json = jest.fn().mockResolvedValue(['kbp', 'tbp'])
const dispatched = []
await runSaga({
dispatch: (action) => dispatched.push(action),
},
fetchEshopProjects
)
expect(dispatched).toEqual([
{
type: 'CURRENT_ESHOP_PROJECTS_LOADING',
loadingState: true,
},
{
type: 'SET_CURRENT_ESHOP_PROJECTS',
payload: ['kbp', 'tbp'],
},
{
type: 'CURRENT_ESHOP_PROJECTS_LOADING',
loadingState: false,
},
])
})
似乎代码只到达 yield call(ajax.json...
部分然后 returns 返回到测试功能 - 因此只记录了第一次调度。我怎样才能更正测试以使其成功结束?
您忘记为 runSaga
返回的任务使用 task.toPromise。下面是一个工作示例:
saga.ts
:
import { call, put } from 'redux-saga/effects';
import { ajax } from './ajax';
export const projectActions = {
currentEshopProjectsLoading(loadingState) {
return { type: 'CURRENT_ESHOP_PROJECTS_LOADING', loadingState };
},
setCurrentEshopProjects(payload) {
return { type: 'SET_CURRENT_ESHOP_PROJECTS', payload };
},
currentEshopProjectsFailed(error) {
return { type: 'CURRENT_ESHOP_PROJECTS_FAILED', error };
},
};
export function* fetchEshopProjects(action) {
yield put(projectActions.currentEshopProjectsLoading(true));
const response: {
projects: string[];
error: Error;
} = yield call(ajax.json, '/new-project/eshops-projects/?eshopId=' + action.eshopId);
if (response.error) {
yield put(projectActions.currentEshopProjectsFailed(response.error));
yield put(projectActions.currentEshopProjectsLoading(false));
} else {
yield put(projectActions.setCurrentEshopProjects(response.projects));
yield put(projectActions.currentEshopProjectsLoading(false));
}
}
ajax.ts
:
export const ajax = {
async json(url) {},
};
saga.test.ts
:
import { runSaga } from 'redux-saga';
import { ajax } from './ajax';
import { fetchEshopProjects } from './saga';
test('fetch projects', async () => {
ajax.json = jest.fn().mockResolvedValue({ projects: ['kbp', 'tbp'] });
const dispatched: any[] = [];
await runSaga(
{
dispatch: (action) => dispatched.push(action),
},
fetchEshopProjects as any,
{ eshopId: '123' },
).toPromise();
expect(dispatched).toEqual([
{
type: 'CURRENT_ESHOP_PROJECTS_LOADING',
loadingState: true,
},
{
type: 'SET_CURRENT_ESHOP_PROJECTS',
payload: ['kbp', 'tbp'],
},
{
type: 'CURRENT_ESHOP_PROJECTS_LOADING',
loadingState: false,
},
]);
});
测试结果:
PASS redux-saga-examples packages/redux-saga-examples/src/Whosebug/71176872/saga.test.ts
✓ fetch projects (6 ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 81.25 | 75 | 60 | 81.25 |
ajax.ts | 100 | 100 | 0 | 100 |
saga.ts | 80 | 75 | 75 | 80 | 12,25-26
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 2.623 s, estimated 3 s