From 178db0fa8688b0e8e91ead750a4ad53dbf881bf0 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Thu, 3 Oct 2019 09:19:58 +0300 Subject: [PATCH] test: fix tests --- .../tests/dynamic-layout.component.spec.ts | 57 +++++++------ .../lib/tests/router-outlet.component.spec.ts | 2 +- npm/ng-packs/packages/core/tsconfig.spec.json | 18 ++-- .../src/lib/handlers/error.handler.ts | 17 ++-- .../src/lib/tests/button.component.spec.ts | 9 +- .../src/lib/tests/error.handler.spec.ts | 83 +++++++++---------- .../src/lib/tests/state-overwrite.ts | 46 ++++++++++ 7 files changed, 136 insertions(+), 96 deletions(-) create mode 100644 npm/ng-packs/packages/theme-shared/src/lib/tests/state-overwrite.ts diff --git a/npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts index 0116d6ad59..bfd2762760 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts @@ -1,17 +1,19 @@ -import { ConfigState, CoreModule, DynamicLayoutComponent, eLayoutType, ABP, RouterOutletComponent } from '@abp/ng.core'; -import { Location } from '@angular/common'; import { Component } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; import { createRoutingFactory, SpectatorRouting, SpyObject } from '@ngneat/spectator'; import { NgxsModule, Store } from '@ngxs/store'; -import { LAYOUTS, ThemeBasicModule } from '../../../../theme-basic/src/public-api'; import { OAuthService } from 'angular-oauth2-oidc'; import { NgxsResetPluginModule, StateOverwrite } from 'ngxs-reset-plugin'; +import { LAYOUTS, ThemeBasicModule } from '../../../../theme-basic/src/public-api'; +import { eLayoutType } from '../enums'; +import { ABP } from '../models'; +import { RouterOutletComponent, CoreModule, DynamicLayoutComponent, ConfigState } from '@abp/ng.core'; import { ThemeSharedModule } from '../../../../theme-shared/src/public-api'; -import { ActivatedRoute } from '@angular/router'; +import { MessageService } from 'primeng/components/common/messageservice'; @Component({ selector: 'abp-dummy', - template: '{{route.snapshot.data?.name}} works!' + template: '{{route.snapshot.data?.name}} works!', }) class DummyComponent { constructor(public route: ActivatedRoute) {} @@ -25,12 +27,13 @@ describe('DynamicLayoutComponent', () => { CoreModule, NgxsModule.forRoot([ConfigState]), NgxsResetPluginModule.forRoot(), - ThemeSharedModule.forRoot(), - ThemeBasicModule + ThemeSharedModule, + ThemeBasicModule, ], declarations: [DummyComponent], + entryComponents: [], stubsEnabled: false, - providers: [{ provide: OAuthService, useValue: { getAccessToken: () => true } }], + providers: [MessageService, { provide: OAuthService, useValue: { getAccessToken: () => true } }], routes: [ { path: '', component: RouterOutletComponent }, { @@ -40,14 +43,14 @@ describe('DynamicLayoutComponent', () => { { path: 'childWithoutLayout', component: DummyComponent, - data: { name: 'childWithoutLayout' } + data: { name: 'childWithoutLayout' }, }, { path: 'childWithLayout', component: DummyComponent, - data: { name: 'childWithLayout' } - } - ] + data: { name: 'childWithLayout' }, + }, + ], }, { path: 'withData', @@ -56,10 +59,10 @@ describe('DynamicLayoutComponent', () => { { path: '', component: DummyComponent, - data: { name: 'withData' } - } + data: { name: 'withData' }, + }, ], - data: { layout: eLayoutType.empty } + data: { layout: eLayoutType.empty }, }, { path: 'withoutLayout', @@ -68,12 +71,12 @@ describe('DynamicLayoutComponent', () => { { path: '', component: DummyComponent, - data: { name: 'withoutLayout' } - } + data: { name: 'withoutLayout' }, + }, ], - data: { layout: null } - } - ] + data: { layout: null }, + }, + ], }); let spectator: SpectatorRouting; @@ -95,16 +98,16 @@ describe('DynamicLayoutComponent', () => { { path: 'parentWithLayout', layout: eLayoutType.application, - children: [{ path: 'childWithoutLayout' }, { path: 'childWithLayout', layout: eLayoutType.account }] - } - ] + children: [{ path: 'childWithoutLayout' }, { path: 'childWithLayout', layout: eLayoutType.account }], + }, + ], }, { path: 'withData', layout: eLayoutType.application }, , ] as ABP.FullRoute[], - environment: { application: {} } - } - ]) + environment: { application: {} }, + }, + ]), ); }); @@ -139,7 +142,7 @@ describe('DynamicLayoutComponent', () => { it('should not display any layout when layouts are empty', async () => { store.dispatch( - new StateOverwrite([ConfigState, { ...store.selectSnapshot(ConfigState), requirements: { layouts: [] } }]) + new StateOverwrite([ConfigState, { ...store.selectSnapshot(ConfigState), requirements: { layouts: [] } }]), ); spectator.detectChanges(); diff --git a/npm/ng-packs/packages/core/src/lib/tests/router-outlet.component.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/router-outlet.component.spec.ts index 42c5a0a9c6..6707432c03 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/router-outlet.component.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/router-outlet.component.spec.ts @@ -1,6 +1,6 @@ import { Spectator, createComponentFactory, createHostFactory } from '@ngneat/spectator'; -import { RouterOutletComponent } from '@abp/ng.core'; import { RouterTestingModule } from '@angular/router/testing'; +import { RouterOutletComponent } from '../components/router-outlet.component'; describe('RouterOutletComponent', () => { let spectator: Spectator; diff --git a/npm/ng-packs/packages/core/tsconfig.spec.json b/npm/ng-packs/packages/core/tsconfig.spec.json index 16da33db07..b86d4b4cce 100644 --- a/npm/ng-packs/packages/core/tsconfig.spec.json +++ b/npm/ng-packs/packages/core/tsconfig.spec.json @@ -2,16 +2,12 @@ "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "../../out-tsc/spec", - "types": [ - "jasmine", - "node" - ] + "types": ["jasmine", "node"], + "paths": { + "@abp/ng.core": ["packages/core/src/public-api.ts"], + "@abp/ng.core/*": ["packages/core/src/lib/*"] + } }, - "files": [ - "src/test.ts" - ], - "include": [ - "**/*.spec.ts", - "**/*.d.ts" - ] + "files": ["src/test.ts"], + "include": ["**/*.spec.ts", "**/*.d.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 d2b9bdb63f..7e4c11d666 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 @@ -6,15 +6,16 @@ import { EmbeddedViewRef, Injectable, Injector, + NgZone, RendererFactory2, } from '@angular/core'; -import { Navigate, RouterState } from '@ngxs/router-plugin'; +import { Router } from '@angular/router'; import { Actions, ofActionSuccessful, Store } from '@ngxs/store'; import { Observable } from 'rxjs'; +import snq from 'snq'; import { ErrorComponent } from '../components/error/error.component'; import { Toaster } from '../models/toaster'; import { ConfirmationService } from '../services/confirmation.service'; -import snq from 'snq'; export const DEFAULT_ERROR_MESSAGES = { defaultError: { @@ -47,6 +48,8 @@ export const DEFAULT_ERROR_MESSAGES = { export class ErrorHandler { constructor( private actions: Actions, + private router: Router, + private ngZone: NgZone, private store: Store, private confirmationService: ConfirmationService, private appRef: ApplicationRef, @@ -125,11 +128,11 @@ export class ErrorHandler { } private navigateToLogin() { - this.store.dispatch( - new Navigate(['/account/login'], null, { - state: { redirectUrl: this.store.selectSnapshot(RouterState).state.url }, - }), - ); + this.ngZone.run(() => { + this.router.navigate(['/account/login'], { + state: { redirectUrl: this.router.url }, + }); + }); } createErrorComponent(instance: Partial) { diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/button.component.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/button.component.spec.ts index b8682ae224..67526e271f 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/tests/button.component.spec.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/button.component.spec.ts @@ -1,11 +1,4 @@ -import { CoreModule } from '@abp/ng.core'; -import { - createComponentFactory, - createHostFactory, - Spectator, - SpectatorHost, - createTestComponentFactory -} from '@ngneat/spectator'; +import { createHostFactory, SpectatorHost } from '@ngneat/spectator'; import { ButtonComponent } from '../components'; describe('ButtonComponent', () => { 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 index 26e3753609..f64b7d73e2 100644 --- 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 @@ -3,9 +3,7 @@ import { Location } from '@angular/common'; import { HttpErrorResponse, HttpHeaders } from '@angular/common/http'; import { Component } from '@angular/core'; import { createRoutingFactory, SpectatorRouting } from '@ngneat/spectator'; -import { RouterState } from '@ngxs/router-plugin'; import { NgxsModule, Store } from '@ngxs/store'; -import { NgxsResetPluginModule, StateOverwrite } from 'ngxs-reset-plugin'; import { DEFAULT_ERROR_MESSAGES, ErrorHandler } from '../handlers'; import { ThemeSharedModule } from '../theme-shared.module'; @@ -14,96 +12,97 @@ class DummyComponent { constructor(public errorHandler: ErrorHandler, public store: Store) {} } -describe('With Custom Host Component', () => { - let component: SpectatorRouting; +describe('ErrorHandler', () => { + let spectator: SpectatorRouting; + let store: Store; + const createComponent = createRoutingFactory({ component: DummyComponent, - imports: [CoreModule, ThemeSharedModule.forRoot(), NgxsModule.forRoot([]), NgxsResetPluginModule.forRoot()], + imports: [CoreModule, ThemeSharedModule.forRoot(), NgxsModule.forRoot([])], stubsEnabled: false, - routes: [{ path: '', component: DummyComponent }, { path: 'account/login', component: RouterOutletComponent }] + routes: [{ path: '', component: DummyComponent }, { path: 'account/login', component: RouterOutletComponent }], }); beforeEach(() => { - component = createComponent(); + spectator = createComponent(); + store = spectator.component.store; + const abpError = document.querySelector('abp-error'); if (abpError) document.body.removeChild(abpError); }); it('should display the error component when server error occurs', () => { - component.component.store.dispatch(new RestOccurError(new HttpErrorResponse({ status: 500 }))); - component.detectChanges(); + store.dispatch(new RestOccurError(new HttpErrorResponse({ status: 500 }))); + spectator.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', () => { - component.component.store.dispatch(new RestOccurError(new HttpErrorResponse({ status: 403 }))); - component.detectChanges(); + store.dispatch(new RestOccurError(new HttpErrorResponse({ status: 403 }))); + spectator.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', () => { - component.component.store.dispatch( - new RestOccurError(new HttpErrorResponse({ status: 0, statusText: 'Unknown Error' })) - ); - component.detectChanges(); + store.dispatch(new RestOccurError(new HttpErrorResponse({ status: 0, statusText: 'Unknown Error' }))); + spectator.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', () => { - component.component.store.dispatch(new RestOccurError(new HttpErrorResponse({ status: 404 }))); - component.detectChanges(); - expect(component.query('.abp-confirm-summary')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultError404.title); - expect(component.query('.abp-confirm-body')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultError404.details); + store.dispatch(new RestOccurError(new HttpErrorResponse({ status: 404 }))); + spectator.detectChanges(); + expect(spectator.query('.abp-confirm-summary')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultError404.title); + expect(spectator.query('.abp-confirm-body')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultError404.details); }); it('should display the confirmation when default error occurs', () => { - component.component.store.dispatch(new RestOccurError(new HttpErrorResponse({ status: 412 }))); - component.detectChanges(); - expect(component.query('.abp-confirm-summary')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultError.title); - expect(component.query('.abp-confirm-body')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultError.details); + store.dispatch(new RestOccurError(new HttpErrorResponse({ status: 412 }))); + spectator.detectChanges(); + expect(spectator.query('.abp-confirm-summary')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultError.title); + expect(spectator.query('.abp-confirm-body')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultError.details); }); it('should display the confirmation when authenticated error occurs', async () => { - component.component.store.dispatch(new RestOccurError(new HttpErrorResponse({ status: 401 }))); - component.detectChanges(); + store.dispatch(new RestOccurError(new HttpErrorResponse({ status: 401 }))); + spectator.detectChanges(); - component.component.store.dispatch(new StateOverwrite([RouterState, { state: { url: '/' } }])); - component.click('#confirm'); - await component.fixture.whenStable(); - expect(component.get(Location).path()).toBe('/account/login'); + spectator.click('#confirm'); + await spectator.fixture.whenStable(); + expect(spectator.get(Location).path()).toBe('/account/login'); }); it('should display the confirmation when authenticated error occurs with _AbpErrorFormat header', async () => { let headers: HttpHeaders = new HttpHeaders(); headers = headers.append('_AbpErrorFormat', '_AbpErrorFormat'); - component.component.store.dispatch(new RestOccurError(new HttpErrorResponse({ status: 401, headers }))); - component.detectChanges(); - component.component.store.dispatch(new StateOverwrite([RouterState, { state: { url: '/' } }])); - component.click('#confirm'); - await component.fixture.whenStable(); - expect(component.get(Location).path()).toBe('/account/login'); + store.dispatch(new RestOccurError(new HttpErrorResponse({ status: 401, headers }))); + spectator.detectChanges(); + + spectator.click('#confirm'); + await spectator.fixture.whenStable(); + expect(spectator.get(Location).path()).toBe('/account/login'); }); it('should display the confirmation when error occurs with _AbpErrorFormat header', () => { let headers: HttpHeaders = new HttpHeaders(); headers = headers.append('_AbpErrorFormat', '_AbpErrorFormat'); - component.component.store.dispatch( + store.dispatch( new RestOccurError( new HttpErrorResponse({ error: { error: { message: 'test message', details: 'test detail' } }, status: 412, - headers - }) - ) + headers, + }), + ), ); - component.detectChanges(); + spectator.detectChanges(); - expect(component.query('.abp-confirm-summary')).toHaveText('test message'); - expect(component.query('.abp-confirm-body')).toHaveText('test detail'); + expect(spectator.query('.abp-confirm-summary')).toHaveText('test message'); + expect(spectator.query('.abp-confirm-body')).toHaveText('test detail'); }); }); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/state-overwrite.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/state-overwrite.ts new file mode 100644 index 0000000000..d46c91c2f5 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/state-overwrite.ts @@ -0,0 +1,46 @@ +import { Inject, Injectable, InjectionToken, Provider } from '@angular/core'; +import { getActionTypeFromInstance, InitState, NgxsPlugin, NGXS_PLUGINS, setValue } from '@ngxs/store'; + +export const NGXS_OVERWRITE_PLUGIN_VALUE = new InjectionToken('NGXS_OVERWRITE_PLUGIN_VALUE'); + +export class StateOverwrite { + static readonly type = '[StateOverwrite] Patch'; + constructor(public payload: { stateName: string; value: any }) {} +} + +@Injectable() +export class OverwritePlugin implements NgxsPlugin { + initialized: boolean; + + constructor(@Inject(NGXS_OVERWRITE_PLUGIN_VALUE) private options: any) {} + + handle(state, action, next) { + const type = getActionTypeFromInstance(action); + + if (action instanceof InitState && !this.initialized) { + state = { ...state, ...this.options }; + console.log(state); + this.initialized = true; + } + + if (action instanceof StateOverwrite) { + state = setValue(state, action.payload.stateName, action.payload.value); + } + + return next(state, action); + } +} + +export function stateOverwriteProviders(value = {}): Provider[] { + return [ + { + provide: NGXS_PLUGINS, + useClass: OverwritePlugin, + multi: true, + }, + { + provide: NGXS_OVERWRITE_PLUGIN_VALUE, + useValue: value, + }, + ]; +}