From 0bcd977d1df796f6fed38ea2f40f87eaa6591237 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Sat, 28 Sep 2019 14:30:40 +0300 Subject: [PATCH] feature: error handler tests --- .../src/lib/handlers/error.handler.ts | 53 ++++++++------- .../src/lib/tests/error.handler.spec.ts | 64 +++++++++++++++++++ 2 files changed, 95 insertions(+), 22 deletions(-) create mode 100644 npm/ng-packs/packages/theme-shared/src/lib/tests/error.handler.spec.ts diff --git a/npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts b/npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts index 0baff0da8f..d18cd45bf1 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts @@ -16,26 +16,31 @@ import { Toaster } from '../models/toaster'; import { ConfirmationService } from '../services/confirmation.service'; import snq from 'snq'; -const DEFAULTS = { +export const DEFAULT_ERROR_MESSAGES = { defaultError: { - message: 'An error has occurred!', + title: 'An error has occurred!', details: 'Error detail not sent by server.', }, - defaultError401: { - message: 'You are not authenticated!', + title: 'You are not authenticated!', details: 'You should be authenticated (sign in) in order to perform this operation.', }, - defaultError403: { - message: 'You are not authorized!', + title: 'You are not authorized!', details: 'You are not allowed to perform this operation.', }, - defaultError404: { - message: 'Resource not found!', + title: 'Resource not found!', details: 'The resource requested could not found on the server.', }, + defaultError500: { + title: '500', + details: 'AbpAccount::InternalServerErrorMessage', + }, + defaultErrorUnknown: { + title: 'Unknown Error', + details: 'AbpAccount::InternalServerErrorMessage', + }, }; @Injectable({ providedIn: 'root' }) @@ -51,7 +56,7 @@ export class ErrorHandler { ) { actions.pipe(ofActionSuccessful(RestOccurError)).subscribe(res => { const { payload: err = {} as HttpErrorResponse | any } = res; - const body = snq(() => (err as HttpErrorResponse).error.error, DEFAULTS.defaultError.message); + const body = snq(() => (err as HttpErrorResponse).error.error, DEFAULT_ERROR_MESSAGES.defaultError.title); if (err instanceof HttpErrorResponse && err.headers.get('_AbpErrorFormat')) { const confirmation$ = this.showError(null, null, body); @@ -64,35 +69,39 @@ export class ErrorHandler { } else { switch ((err as HttpErrorResponse).status) { case 401: - this.showError(DEFAULTS.defaultError401.details, DEFAULTS.defaultError401.message).subscribe(() => - this.navigateToLogin(), - ); + this.showError( + DEFAULT_ERROR_MESSAGES.defaultError401.details, + DEFAULT_ERROR_MESSAGES.defaultError401.title, + ).subscribe(() => this.navigateToLogin()); break; case 403: this.createErrorComponent({ - title: DEFAULTS.defaultError403.message, - details: DEFAULTS.defaultError403.details, + title: DEFAULT_ERROR_MESSAGES.defaultError403.title, + details: DEFAULT_ERROR_MESSAGES.defaultError403.details, }); break; case 404: - this.showError(DEFAULTS.defaultError404.details, DEFAULTS.defaultError404.message); + this.showError( + DEFAULT_ERROR_MESSAGES.defaultError404.details, + DEFAULT_ERROR_MESSAGES.defaultError404.title, + ); break; case 500: this.createErrorComponent({ - title: '500', - details: 'AbpAccount::InternalServerErrorMessage', + title: DEFAULT_ERROR_MESSAGES.defaultError500.title, + details: DEFAULT_ERROR_MESSAGES.defaultError500.details, }); break; case 0: if ((err as HttpErrorResponse).statusText === 'Unknown Error') { this.createErrorComponent({ - title: 'Unknown Error', - details: 'AbpAccount::InternalServerErrorMessage', + title: DEFAULT_ERROR_MESSAGES.defaultErrorUnknown.title, + details: DEFAULT_ERROR_MESSAGES.defaultErrorUnknown.details, }); } break; default: - this.showError(DEFAULTS.defaultError.details, DEFAULTS.defaultError.message); + this.showError(DEFAULT_ERROR_MESSAGES.defaultError.details, DEFAULT_ERROR_MESSAGES.defaultError.title); break; } } @@ -105,7 +114,7 @@ export class ErrorHandler { message = body.details; title = body.message; } else { - message = body.message || DEFAULTS.defaultError.message; + message = body.message || DEFAULT_ERROR_MESSAGES.defaultError.title; } } @@ -125,7 +134,7 @@ export class ErrorHandler { createErrorComponent(instance: Partial) { const renderer = this.rendererFactory.createRenderer(null, null); - const host = renderer.selectRootElement('app-root', true); + const host = renderer.selectRootElement(document.body, true); const componentRef = this.cfRes.resolveComponentFactory(ErrorComponent).create(this.injector); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/error.handler.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/error.handler.spec.ts new file mode 100644 index 0000000000..0f64652cfe --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/error.handler.spec.ts @@ -0,0 +1,64 @@ +import { createHostFactory, SpectatorHost } from '@ngneat/spectator'; +import { Component } from '@angular/core'; +import { ErrorHandler, DEFAULT_ERROR_MESSAGES } from '../handlers'; +import { CoreModule, RestOccurError } from '@abp/ng.core'; +import { ThemeSharedModule } from '../theme-shared.module'; +import { NgxsModule, Store } from '@ngxs/store'; +import { RouterModule } from '@angular/router'; +import { HttpErrorResponse } from '@angular/common/http'; + +@Component({ selector: 'dummy', template: 'dummy works! ' }) +class DummyComponent { + constructor(public errorHandler: ErrorHandler, public store: Store) {} +} + +describe('With Custom Host Component', function() { + let host: SpectatorHost; + const createHost = createHostFactory({ + component: DummyComponent, + imports: [CoreModule, ThemeSharedModule.forRoot(), NgxsModule.forRoot([]), RouterModule.forRoot([])], + }); + + beforeEach(() => { + host = createHost(``); + const abpError = document.querySelector('abp-error'); + if (abpError) document.body.removeChild(abpError); + }); + + it('should display the error component when server error occurs', () => { + host.component.store.dispatch(new RestOccurError(new HttpErrorResponse({ status: 500 }))); + host.detectChanges(); + expect(document.querySelector('.error-template')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultError500.title); + expect(document.querySelector('.error-details')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultError500.details); + }); + + it('should display the error component when authorize error occurs', () => { + host.component.store.dispatch(new RestOccurError(new HttpErrorResponse({ status: 403 }))); + host.detectChanges(); + expect(document.querySelector('.error-template')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultError403.title); + expect(document.querySelector('.error-details')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultError403.details); + }); + + it('should display the error component when unknown error occurs', () => { + host.component.store.dispatch( + new RestOccurError(new HttpErrorResponse({ status: 0, statusText: 'Unknown Error' })), + ); + host.detectChanges(); + expect(document.querySelector('.error-template')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultErrorUnknown.title); + expect(document.querySelector('.error-details')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultErrorUnknown.details); + }); + + it('should display the confirmation when not found error occurs', () => { + host.component.store.dispatch(new RestOccurError(new HttpErrorResponse({ status: 404 }))); + host.detectChanges(); + expect(host.query('.abp-confirm-summary')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultError404.title); + expect(host.query('.abp-confirm-body')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultError404.details); + }); + + it('should display the confirmation when default error occurs', () => { + host.component.store.dispatch(new RestOccurError(new HttpErrorResponse({ status: 412 }))); + host.detectChanges(); + expect(host.query('.abp-confirm-summary')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultError.title); + expect(host.query('.abp-confirm-body')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultError.details); + }); +});