I'm trying to write a jasmine test for an @Effect that has chained rxjs catchError
operators, but am struggling to test any observables beyond the first catchError
.
here's the effect:
@Effect() submitEndsheets$ = this.actions$.pipe(
ofType<SubmitEndSheets>(SpreadActionTypes.SUBMIT_ENDSHEETS),
withLatestFrom(this.store.pipe(select(fromAppStore.fromOrder.getDocumentId))),
concatMap(([action, documentId]) =>
this.spreadService.submitEndSheets(documentId).pipe(
map((response: ActionProcessorDto) => new SubmitEndSheetsSuccess(response.data)),
catchError((error) => of(undo(action))),
catchError((error) => of(new MessageModal({
message: error.message,
title: 'Submission Error!'
})
))
)
)
);
and the corresponding test:
it('handles errors by sending an undo action', () => {
const action = {
type: SpreadActionTypes.SUBMIT_ENDSHEETS,
};
const source = cold('a', { a: action });
const error = new Error('Error occurred!');
const service = createServiceStub(error);
const store = createStoreState();
const effects = new Effects(service, new Actions(source), store);
const expected = cold('ab', {
a: undo(action),
b: new MessageModal({
message: 'Sorry, something went wrong with your request. Please try again or contact support.',
title: 'Update Error!'
}),
});
expect(effects.submitEndsheets$).toBeObservable(expected);
});
for reference, here are the createServiceStub
that mocks the service and createStoreState
that, you guessed it, creates a mock store.
function createServiceStub(response: any) {
const service = jasmine.createSpyObj('spreadService', [
'load',
'update',
'updateSpreadPosition',
'submitEndSheets'
]);
const isError = response instanceof Error;
const serviceResponse = isError ? throwError(response) : of(response);
service.load.and.returnValue(serviceResponse);
service.update.and.returnValue(serviceResponse);
service.updateSpreadPosition.and.returnValue(serviceResponse);
service.submitEndSheets.and.returnValue(serviceResponse);
return service;
}
function createStoreState() {
const store = jasmine.createSpyObj('store', ['pipe']);
store.pipe.and.returnValue(of({ documentId: 123 }));
return store;
}
here's the test output:
FAILED TESTS:
✖ handles errors by sending an undo action
HeadlessChrome 0.0.0 (Mac OS X 10.14.2)
Expected $.length = 1 to equal 2.
Expected $[1] = undefined to equal Object({ frame: 10, notification: Notification({ kind: 'N', value: MessageModal({ payload: Object({ message: 'Sorry, something went wrong with your request. Please try again or contact support.', title: 'Update Error!' }), type: 'MESSAGE_MODAL' }), error: undefined, hasValue: true }) }).
at pare node_modules/jasmine-marbles/bundles/jasmine-marbles.umd.js:389:1)
at UserContext.<anonymous> src/app/book/store/spread/spread.effects.spec.ts:197:46)
at ZoneDelegate../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke node_modules/zone.js/dist/zone.js:388:1)
Thanks in advance for any help!
Update:
catchError
can send an array of actions back out of the effect like so:
@Effect() submitEndsheets$ = this.actions$.pipe(
ofType<SubmitEndSheets>(SpreadActionTypes.SUBMIT_ENDSHEETS),
withLatestFrom(this.store.pipe(select(fromAppStore.fromOrder.getDocumentId))),
concatMap(([action, documentId]) =>
this.spreadService.submitEndSheets(documentId).pipe(
map((response: ActionProcessorDto) => new SubmitEndSheetsSuccess(response.data)),
catchError(error => [
new PopSingleToast({
severity: ToastSeverity.error,
summary: 'Failure',
detail: `Some error occurred: \n Error: ${error}`
}),
undo(action)
])
)
)
);
The corresponding test looks like so:
it('handles errors by sending an undo action', () => {
const action = {
type: SpreadActionTypes.SUBMIT_ENDSHEETS
};
const source = cold('a', { a: action });
const error = new Error('Error occurred!');
const service = createServiceStub(error);
const store = createStoreState();
const effects = new Effects(service, new Actions(source), store);
const expectedAction = new PopSingleToast({
severity: ToastSeverity.error,
summary: 'Failure',
detail: `Some error occurred: \n Error: ${error}`
});
const expected = cold('(ab)', {
a: expectedAction,
b: undo(action)
});
expect(effects.submitEndsheets$).toBeObservable(expected);
});
Thanks for to all for the help!
I'm trying to write a jasmine test for an @Effect that has chained rxjs catchError
operators, but am struggling to test any observables beyond the first catchError
.
here's the effect:
@Effect() submitEndsheets$ = this.actions$.pipe(
ofType<SubmitEndSheets>(SpreadActionTypes.SUBMIT_ENDSHEETS),
withLatestFrom(this.store.pipe(select(fromAppStore.fromOrder.getDocumentId))),
concatMap(([action, documentId]) =>
this.spreadService.submitEndSheets(documentId).pipe(
map((response: ActionProcessorDto) => new SubmitEndSheetsSuccess(response.data)),
catchError((error) => of(undo(action))),
catchError((error) => of(new MessageModal({
message: error.message,
title: 'Submission Error!'
})
))
)
)
);
and the corresponding test:
it('handles errors by sending an undo action', () => {
const action = {
type: SpreadActionTypes.SUBMIT_ENDSHEETS,
};
const source = cold('a', { a: action });
const error = new Error('Error occurred!');
const service = createServiceStub(error);
const store = createStoreState();
const effects = new Effects(service, new Actions(source), store);
const expected = cold('ab', {
a: undo(action),
b: new MessageModal({
message: 'Sorry, something went wrong with your request. Please try again or contact support.',
title: 'Update Error!'
}),
});
expect(effects.submitEndsheets$).toBeObservable(expected);
});
for reference, here are the createServiceStub
that mocks the service and createStoreState
that, you guessed it, creates a mock store.
function createServiceStub(response: any) {
const service = jasmine.createSpyObj('spreadService', [
'load',
'update',
'updateSpreadPosition',
'submitEndSheets'
]);
const isError = response instanceof Error;
const serviceResponse = isError ? throwError(response) : of(response);
service.load.and.returnValue(serviceResponse);
service.update.and.returnValue(serviceResponse);
service.updateSpreadPosition.and.returnValue(serviceResponse);
service.submitEndSheets.and.returnValue(serviceResponse);
return service;
}
function createStoreState() {
const store = jasmine.createSpyObj('store', ['pipe']);
store.pipe.and.returnValue(of({ documentId: 123 }));
return store;
}
here's the test output:
FAILED TESTS:
✖ handles errors by sending an undo action
HeadlessChrome 0.0.0 (Mac OS X 10.14.2)
Expected $.length = 1 to equal 2.
Expected $[1] = undefined to equal Object({ frame: 10, notification: Notification({ kind: 'N', value: MessageModal({ payload: Object({ message: 'Sorry, something went wrong with your request. Please try again or contact support.', title: 'Update Error!' }), type: 'MESSAGE_MODAL' }), error: undefined, hasValue: true }) }).
at pare node_modules/jasmine-marbles/bundles/jasmine-marbles.umd.js:389:1)
at UserContext.<anonymous> src/app/book/store/spread/spread.effects.spec.ts:197:46)
at ZoneDelegate../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke node_modules/zone.js/dist/zone.js:388:1)
Thanks in advance for any help!
Update:
catchError
can send an array of actions back out of the effect like so:
@Effect() submitEndsheets$ = this.actions$.pipe(
ofType<SubmitEndSheets>(SpreadActionTypes.SUBMIT_ENDSHEETS),
withLatestFrom(this.store.pipe(select(fromAppStore.fromOrder.getDocumentId))),
concatMap(([action, documentId]) =>
this.spreadService.submitEndSheets(documentId).pipe(
map((response: ActionProcessorDto) => new SubmitEndSheetsSuccess(response.data)),
catchError(error => [
new PopSingleToast({
severity: ToastSeverity.error,
summary: 'Failure',
detail: `Some error occurred: \n Error: ${error}`
}),
undo(action)
])
)
)
);
The corresponding test looks like so:
it('handles errors by sending an undo action', () => {
const action = {
type: SpreadActionTypes.SUBMIT_ENDSHEETS
};
const source = cold('a', { a: action });
const error = new Error('Error occurred!');
const service = createServiceStub(error);
const store = createStoreState();
const effects = new Effects(service, new Actions(source), store);
const expectedAction = new PopSingleToast({
severity: ToastSeverity.error,
summary: 'Failure',
detail: `Some error occurred: \n Error: ${error}`
});
const expected = cold('(ab)', {
a: expectedAction,
b: undo(action)
});
expect(effects.submitEndsheets$).toBeObservable(expected);
});
Thanks for to all for the help!
Share edited Jan 22, 2019 at 15:15 mpaarating asked Jan 19, 2019 at 14:54 mpaaratingmpaarating 532 silver badges8 bronze badges 2-
Placing
catchError
two times in a row doesn't make sense, only* the first handler will be used. Are you trying to emit/perform 2 actions in row if an error occurs? – Oles Savluk Commented Jan 19, 2019 at 21:23 -
@OlesSavluk you are 100% correct. For some reason, I was forgetting to throw the error to fire the second
catchError
. I updated my post with the solution that worked for my use case. – mpaarating Commented Jan 20, 2019 at 4:40
1 Answer
Reset to default 6Having two catchErrors
in a row like this means the second one will never trigger because the first one will eat the error.
You would need to rethrow the error in the first catchError
to get inside the second one:
catchError(error => throw new Error()),
catchError(error => console.log('now I trigger'))
So I am afraid your questions doesn't make really sense.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744914315a4600740.html
评论列表(0条)