如何使用 jest 和 enzyme 测试 redux saga
How to test redux saga using jest and enzyme
我有一个 saga 函数,我正在尝试使用 jest 和 enzyme 进行测试,但出现错误。这是我第一次测试 saga 文件,所以我不知道为什么我会收到错误,即使预期值和接收值是相同的 saga 文件如下:
export const getToken = (state) => state.dextaAuth.token;
export function* setPost(action) {
try {
const token = yield select(getToken);
const data = yield call(
dextaApiService.post,
"/api/savedAdvices",
action.payload,
token
);
yield put(
openNotification({
messageType: MessageBarType.success,
message: "Advice saved successfully",
})
);
} catch (err) {
yield put(
openNotification({
messageType: MessageBarType.error,
message: `Notification: ${err.message}`,
})
);
}
}
export function* savedAdvicesaga() {
yield takeLatest(POST_SAVED_ADVICE, setPost);
yield takeLatest(FETCH_SAVED_ADVICE, fetchSavedAsviceAsync);
}
这是我写的测试用例:
describe("savedAdviceSaga", () => {
const genObject = savedAdvicesaga();
describe("setpost", () => {
it("should check for post ", async () => {
const apiResponse = jest
.spyOn(dextaApiService, "post")
.mockImplementation(() => Promise.resolve());
const dispatched = [];
const action: types.SavedAdviceActionType = {
type: types.POST_SAVED_ADVICE,
payload: {
Title: "test",
Description: "test dec",
},
};
const iterator = setPost(action);
const effect = iterator.next().value;
const expected = select(getToken);
const result = await runSaga(
{
dispatch: (action) => dispatched.push(action),
},
setPost,
action
);
expect(effect).toContainEqual(expected);
expect(apiResponse).toHaveBeenCalledTimes(1);
});
});
});
这是我在控制台中遇到的错误:
expect(received).toContainEqual(expected) // deep equality
Expected value: {"@@redux-saga/IO": true, "combinator": false, "payload": {"args": [],
"selector": [Function anonymous]}, "type": "SELECT"}
Received object: {"@@redux-saga/IO": true, "combinator": false, "payload": {"args": [], "selector":
[Function anonymous]}, "type": "SELECT"}
27 | dispatch: (action) => dispatched.push(action),
28 | }, setPost, action);
> 29 | expect(effect).toContainEqual(expected)
| ^
30 | expect(apiResponse).toHaveBeenCalledTimes(1);
31 |
32 | })
您正在使用 Testing the full Saga 测试策略。不需要检查 saga 的每一步。
run the whole saga and assert that the expected effects have occurred.
runSaga(options, saga, ...args) 接受 getState()
选项,以便您提供模拟状态。 getToken
选择器将使用它。
例如
saga.ts
:
import { call, put, select, takeLatest } from 'redux-saga/effects';
import { dextaApiService } from './dextaApiService';
export const MessageBarType = {
success: 'success',
error: 'error',
};
export function openNotification({ messageType, message }) {
return { type: messageType, payload: message };
}
export const getToken = (state) => state.dextaAuth.token;
export function* setPost(action) {
try {
const token = yield select(getToken);
const data = yield call(dextaApiService.post, '/api/savedAdvices', action.payload, token);
yield put(
openNotification({
messageType: MessageBarType.success,
message: 'Advice saved successfully',
}),
);
} catch (err) {
yield put(
openNotification({
messageType: MessageBarType.error,
message: `Notification: ${err.message}`,
}),
);
}
}
export function* savedAdvicesaga() {
yield takeLatest('POST_SAVED_ADVICE', setPost);
}
dextaApiService.ts
:
export const dextaApiService = {
async post(path, payload, token) {
return 'real implementation';
},
};
saga.test.ts
:
import { setPost } from './saga';
import { dextaApiService } from './dextaApiService';
import { runSaga } from 'redux-saga';
import { Action } from 'redux';
describe('67444295', () => {
it('should pass', async () => {
const dispatched: Action[] = [];
const postSpy = jest.spyOn(dextaApiService, 'post').mockResolvedValueOnce('mocked response');
const actual = await runSaga(
{
dispatch: (action: Action) => dispatched.push(action),
getState: () => ({ dextaAuth: { token: 'abc123' } }),
},
setPost,
{ payload: 'mocked payload' },
).toPromise();
expect(postSpy).toBeCalledWith('/api/savedAdvices', 'mocked payload', 'abc123');
expect(dispatched).toEqual([{ type: 'success', payload: 'Advice saved successfully' }]);
postSpy.mockRestore();
});
});
测试结果:
PASS src/Whosebug/67444295/saga.test.ts
67444295
✓ should pass (5 ms)
--------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------------|---------|----------|---------|---------|-------------------
All files | 85.71 | 0 | 60 | 80 |
dextaApiService.ts | 50 | 100 | 0 | 50 | 3
saga.ts | 89.47 | 0 | 75 | 84.62 | 26,36
--------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 2.567 s
我有一个 saga 函数,我正在尝试使用 jest 和 enzyme 进行测试,但出现错误。这是我第一次测试 saga 文件,所以我不知道为什么我会收到错误,即使预期值和接收值是相同的 saga 文件如下:
export const getToken = (state) => state.dextaAuth.token;
export function* setPost(action) {
try {
const token = yield select(getToken);
const data = yield call(
dextaApiService.post,
"/api/savedAdvices",
action.payload,
token
);
yield put(
openNotification({
messageType: MessageBarType.success,
message: "Advice saved successfully",
})
);
} catch (err) {
yield put(
openNotification({
messageType: MessageBarType.error,
message: `Notification: ${err.message}`,
})
);
}
}
export function* savedAdvicesaga() {
yield takeLatest(POST_SAVED_ADVICE, setPost);
yield takeLatest(FETCH_SAVED_ADVICE, fetchSavedAsviceAsync);
}
这是我写的测试用例:
describe("savedAdviceSaga", () => {
const genObject = savedAdvicesaga();
describe("setpost", () => {
it("should check for post ", async () => {
const apiResponse = jest
.spyOn(dextaApiService, "post")
.mockImplementation(() => Promise.resolve());
const dispatched = [];
const action: types.SavedAdviceActionType = {
type: types.POST_SAVED_ADVICE,
payload: {
Title: "test",
Description: "test dec",
},
};
const iterator = setPost(action);
const effect = iterator.next().value;
const expected = select(getToken);
const result = await runSaga(
{
dispatch: (action) => dispatched.push(action),
},
setPost,
action
);
expect(effect).toContainEqual(expected);
expect(apiResponse).toHaveBeenCalledTimes(1);
});
});
});
这是我在控制台中遇到的错误:
expect(received).toContainEqual(expected) // deep equality
Expected value: {"@@redux-saga/IO": true, "combinator": false, "payload": {"args": [],
"selector": [Function anonymous]}, "type": "SELECT"}
Received object: {"@@redux-saga/IO": true, "combinator": false, "payload": {"args": [], "selector":
[Function anonymous]}, "type": "SELECT"}
27 | dispatch: (action) => dispatched.push(action),
28 | }, setPost, action);
> 29 | expect(effect).toContainEqual(expected)
| ^
30 | expect(apiResponse).toHaveBeenCalledTimes(1);
31 |
32 | })
您正在使用 Testing the full Saga 测试策略。不需要检查 saga 的每一步。
run the whole saga and assert that the expected effects have occurred.
runSaga(options, saga, ...args) 接受 getState()
选项,以便您提供模拟状态。 getToken
选择器将使用它。
例如
saga.ts
:
import { call, put, select, takeLatest } from 'redux-saga/effects';
import { dextaApiService } from './dextaApiService';
export const MessageBarType = {
success: 'success',
error: 'error',
};
export function openNotification({ messageType, message }) {
return { type: messageType, payload: message };
}
export const getToken = (state) => state.dextaAuth.token;
export function* setPost(action) {
try {
const token = yield select(getToken);
const data = yield call(dextaApiService.post, '/api/savedAdvices', action.payload, token);
yield put(
openNotification({
messageType: MessageBarType.success,
message: 'Advice saved successfully',
}),
);
} catch (err) {
yield put(
openNotification({
messageType: MessageBarType.error,
message: `Notification: ${err.message}`,
}),
);
}
}
export function* savedAdvicesaga() {
yield takeLatest('POST_SAVED_ADVICE', setPost);
}
dextaApiService.ts
:
export const dextaApiService = {
async post(path, payload, token) {
return 'real implementation';
},
};
saga.test.ts
:
import { setPost } from './saga';
import { dextaApiService } from './dextaApiService';
import { runSaga } from 'redux-saga';
import { Action } from 'redux';
describe('67444295', () => {
it('should pass', async () => {
const dispatched: Action[] = [];
const postSpy = jest.spyOn(dextaApiService, 'post').mockResolvedValueOnce('mocked response');
const actual = await runSaga(
{
dispatch: (action: Action) => dispatched.push(action),
getState: () => ({ dextaAuth: { token: 'abc123' } }),
},
setPost,
{ payload: 'mocked payload' },
).toPromise();
expect(postSpy).toBeCalledWith('/api/savedAdvices', 'mocked payload', 'abc123');
expect(dispatched).toEqual([{ type: 'success', payload: 'Advice saved successfully' }]);
postSpy.mockRestore();
});
});
测试结果:
PASS src/Whosebug/67444295/saga.test.ts
67444295
✓ should pass (5 ms)
--------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------------|---------|----------|---------|---------|-------------------
All files | 85.71 | 0 | 60 | 80 |
dextaApiService.ts | 50 | 100 | 0 | 50 | 3
saga.ts | 89.47 | 0 | 75 | 84.62 | 26,36
--------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 2.567 s