reactjs - 如何开玩笑地测试 redux-observable 史诗?
问题描述
所以,我在 redux 中有以下史诗般的设置:
export const getNotificationsEpic = (action$: ActionsObservable<any>): any =>
action$
.pipe(
ofType(POLLING_START),
switchMap(() =>
timer(0, 3000)
.pipe(
takeUntil(action$.ofType(POLLING_STOP)),
exhaustMap(() => from(NOTIFICATIONS_API.returnNotifications(0, 10))),
map((response: PageResponseNotificationDTO) => getNotificationsSuccess(response)),
catchError((error: FailureReason) => of([
errorToastrAction('Error occurred when fetching notifications.'),
getNotificationsFailure(error.reason),
])),
),
),
);
其中 NOTIFICATIONS_API.returnNotifications 是转换为可观察的 Promise。我想为这部史诗写一个单元测试,但我不知道如何正确模拟 API 请求。我尝试过使用以下代码:
describe('getNotificationsEpic', () => {
it('should call getNotificationsSuccess with correct argument', (done: any) => {
const response: PageResponseNotificationDTO = createNotificationPage();
NOTIFICATIONS_API.returnNotifications = jest.fn().mockResolvedValueOnce(response);
const action$ = ActionsObservable.of({
type: POLLING_START,
});
const expectedResult =
{
type: GET_NOTIFICATIONS_SUCCESS,
value: response,
} ;
const result$: Observable<AnyAction[]> = getNotificationsEpic(action$).pipe(toArray());
result$
.subscribe((actions: AnyAction[]) => {
expect(actions).toContainEqual(expectedResult);
done();
});
});
});
但不幸的是,代码不正确,SUCCESS 和 ERROR 动作都进入了动作流。当我控制台记录 errorHandler 时,我可以看到以下消息:
at SafeSubscriber._next (src/epics/getNotificationsEpic.spec.tsx:29:27)
at SafeSubscriber.Object.<anonymous>.SafeSubscriber.__tryOrUnsub (node_modules/rxjs/src/internal/Subscriber.ts:267:10)
at SafeSubscriber.Object.<anonymous>.SafeSubscriber.next (node_modules/rxjs/src/internal/Subscriber.ts:209:14)
at Subscriber.Object.<anonymous>.Subscriber._next (node_modules/rxjs/src/internal/Subscriber.ts:139:22)
at Subscriber.Object.<anonymous>.Subscriber.next (node_modules/rxjs/src/internal/Subscriber.ts:99:12)
at DefaultIfEmptySubscriber.Object.<anonymous>.DefaultIfEmptySubscriber._next (node_modules/rxjs/src/internal/operators/defaultIfEmpty.ts:75:22)
at DefaultIfEmptySubscriber.Object.<anonymous>.Subscriber.next (node_modules/rxjs/src/internal/Subscriber.ts:99:12)
at TakeLastSubscriber.Object.<anonymous>.TakeLastSubscriber._complete (node_modules/rxjs/src/internal/operators/takeLast.ts:108:21)
at TakeLastSubscriber.Object.<anonymous>.Subscriber.complete (node_modules/rxjs/src/internal/Subscriber.ts:126:12)
at ScanSubscriber.Object.<anonymous>.Subscriber._complete (node_modules/rxjs/src/internal/Subscriber.ts:148:22)
at ScanSubscriber.Object.<anonymous>.Subscriber.complete (node_modules/rxjs/src/internal/Subscriber.ts:126:12)
at SwitchMapSubscriber.Object.<anonymous>.Subscriber._complete (node_modules/rxjs/src/internal/Subscriber.ts:148:22)
at SwitchMapSubscriber.Object.<anonymous>.SwitchMapSubscriber.notifyComplete (node_modules/rxjs/src/internal/operators/switchMap.ts:142:22)
at InnerSubscriber.Object.<anonymous>.InnerSubscriber._complete (node_modules/rxjs/src/internal/InnerSubscriber.ts:26:17)
at InnerSubscriber.Object.<anonymous>.Subscriber.complete (node_modules/rxjs/src/internal/Subscriber.ts:126:12)
at CatchSubscriber.Object.<anonymous>.OuterSubscriber.notifyComplete (node_modules/rxjs/src/internal/OuterSubscriber.ts:21:22)
at InnerSubscriber.Object.<anonymous>.InnerSubscriber._complete (node_modules/rxjs/src/internal/InnerSubscriber.ts:26:17)
at InnerSubscriber.Object.<anonymous>.Subscriber.complete (node_modules/rxjs/src/internal/Subscriber.ts:126:12)
at node_modules/rxjs/src/internal/util/subscribeTo.ts:19:20
at Object.subscribeToResult (node_modules/rxjs/src/internal/util/subscribeToResult.ts:25:29)
at CatchSubscriber.Object.<anonymous>.CatchSubscriber.error (node_modules/rxjs/src/internal/operators/catchError.ts:140:7)
at MapSubscriber.Object.<anonymous>.Subscriber._error (node_modules/rxjs/src/internal/Subscriber.ts:143:22)
at MapSubscriber.Object.<anonymous>.Subscriber.error (node_modules/rxjs/src/internal/Subscriber.ts:113:12)
at ExhaustMapSubscriber.Object.<anonymous>.ExhaustMapSubscriber.tryNext (node_modules/rxjs/src/internal/operators/exhaustMap.ts:117:24)
at ExhaustMapSubscriber.Object.<anonymous>.ExhaustMapSubscriber._next (node_modules/rxjs/src/internal/operators/exhaustMap.ts:107:12)
at ExhaustMapSubscriber.Object.<anonymous>.Subscriber.next (node_modules/rxjs/src/internal/Subscriber.ts:99:12)
at TakeUntilSubscriber.Object.<anonymous>.Subscriber._next (node_modules/rxjs/src/internal/Subscriber.ts:139:22)
at TakeUntilSubscriber.Object.<anonymous>.Subscriber.next (node_modules/rxjs/src/internal/Subscriber.ts:99:12)
at AsyncAction.dispatch (node_modules/rxjs/src/internal/observable/timer.ts:91:14)
at AsyncAction.Object.<anonymous>.AsyncAction._execute (node_modules/rxjs/src/internal/scheduler/AsyncAction.ts:122:12)
at AsyncAction.Object.<anonymous>.AsyncAction.execute (node_modules/rxjs/src/internal/scheduler/AsyncAction.ts:97:24)
at AsyncScheduler.Object.<anonymous>.AsyncScheduler.flush (node_modules/rxjs/src/internal/scheduler/AsyncScheduler.ts:58:26)
at Timeout.callback (node_modules/jsdom/lib/jsdom/browser/Window.js:678:19)
解决方案
推荐阅读
- haskell - Haskell - 将玫瑰树的深度优先遍历表示为展开的实例,以代数方式推导它
- python - 如何正确连接python中的两个函数?
- powershell - 按数字前导数对文件版本进行排序
- c# - 按日期更改一行代码?
- wordpress - wordpress 4.9.6 可视化编辑器添加跨度代码
- vue.js - 我如何填充 axios 获取数据数组并将其传递给 Vuejs 组件道具以在组件中进行列表渲染
- postgresql - 我如何使用 pg_trgm 更允许
- r - 检查值是否在单独数据框的特定范围内
- sql - 对别名使用 Case 语句
- python - 卸载 pip 不使用的软件包