From e464c0f8c7d44050fa22e32ec349894dffac9ea6 Mon Sep 17 00:00:00 2001 From: Yura Bondarenko Date: Thu, 25 Aug 2022 14:01:23 +0200 Subject: [PATCH] 92900: Move duplicate code to new InitService method --- src/app/init.service.spec.ts | 24 ++- src/app/init.service.ts | 15 ++ src/modules/app/browser-init.service.spec.ts | 155 ------------------- src/modules/app/browser-init.service.ts | 22 +-- src/modules/app/server-init.service.ts | 7 +- 5 files changed, 44 insertions(+), 179 deletions(-) delete mode 100644 src/modules/app/browser-init.service.spec.ts diff --git a/src/app/init.service.spec.ts b/src/app/init.service.spec.ts index 2c9edfd4e0..592abdfd42 100644 --- a/src/app/init.service.spec.ts +++ b/src/app/init.service.spec.ts @@ -5,7 +5,7 @@ import { inject, TestBed, waitForAsync } from '@angular/core/testing'; import { MetadataService } from './core/metadata/metadata.service'; import { BreadcrumbsService } from './breadcrumbs/breadcrumbs.service'; import { CommonModule } from '@angular/common'; -import { StoreModule } from '@ngrx/store'; +import { Store, StoreModule } from '@ngrx/store'; import { authReducer } from './core/auth/auth.reducer'; import { storeModuleConfig } from './app.reducer'; import { AngularticsProviderMock } from './shared/mocks/angulartics-provider.service.mock'; @@ -31,6 +31,7 @@ import { getMockThemeService } from './shared/mocks/theme-service.mock'; import objectContaining = jasmine.objectContaining; import createSpyObj = jasmine.createSpyObj; import SpyObj = jasmine.SpyObj; +import { getTestScheduler } from 'jasmine-marbles'; let spy: SpyObj; @@ -124,6 +125,15 @@ describe('InitService', () => { let metadataServiceSpy; let breadcrumbsServiceSpy; + const BLOCKING = { + t: { core: { auth: { blocking: true } } }, + f: { core: { auth: { blocking: false } } }, + }; + const BOOLEAN = { + t: true, + f: false, + }; + beforeEach(waitForAsync(() => { correlationIdServiceSpy = jasmine.createSpyObj('correlationIdServiceSpy', [ 'initCorrelationId', @@ -182,6 +192,18 @@ describe('InitService', () => { expect(breadcrumbsServiceSpy.listenForRouteChanges).toHaveBeenCalledTimes(1); })); }); + + describe('authenticationReady', () => { + it('should emit & complete the first time auth is unblocked', () => { + getTestScheduler().run(({ cold, expectObservable }) => { + TestBed.overrideProvider(Store, { useValue: cold('t--t--f--t--f--', BLOCKING) }); + const service = TestBed.inject(InitService); + + // @ts-ignore + expectObservable(service.authenticationReady$()).toBe('------(f|)', BOOLEAN); + }); + }); + }); }); }); diff --git a/src/app/init.service.ts b/src/app/init.service.ts index 30630e1d84..3af8b6ceb6 100644 --- a/src/app/init.service.ts +++ b/src/app/init.service.ts @@ -20,6 +20,9 @@ import { Angulartics2DSpace } from './statistics/angulartics/dspace-provider'; import { MetadataService } from './core/metadata/metadata.service'; import { BreadcrumbsService } from './breadcrumbs/breadcrumbs.service'; import { ThemeService } from './shared/theme-support/theme.service'; +import { isAuthenticationBlocking } from './core/auth/selectors'; +import { distinctUntilChanged, find } from 'rxjs/operators'; +import { Observable } from 'rxjs'; /** * Performs the initialization of the app. @@ -186,4 +189,16 @@ export abstract class InitService { this.breadcrumbsService.listenForRouteChanges(); this.themeService.listenForRouteChanges(); } + + /** + * Emits once authentication is ready (no longer blocking) + * @protected + */ + protected authenticationReady$(): Observable { + return this.store.pipe( + select(isAuthenticationBlocking), + distinctUntilChanged(), + find((b: boolean) => b === false) + ); + } } diff --git a/src/modules/app/browser-init.service.spec.ts b/src/modules/app/browser-init.service.spec.ts deleted file mode 100644 index 05da7d9d36..0000000000 --- a/src/modules/app/browser-init.service.spec.ts +++ /dev/null @@ -1,155 +0,0 @@ -import { InitService } from '../../app/init.service'; -import { APP_CONFIG } from 'src/config/app-config.interface'; -import { inject, TestBed, waitForAsync } from '@angular/core/testing'; -import { GoogleAnalyticsService } from '../../app/statistics/google-analytics.service'; -import { MetadataService } from '../../app/core/metadata/metadata.service'; -import { BreadcrumbsService } from '../../app/breadcrumbs/breadcrumbs.service'; -import { CommonModule } from '@angular/common'; -import { Store, StoreModule } from '@ngrx/store'; -import { authReducer } from '../../app/core/auth/auth.reducer'; -import { storeModuleConfig } from '../../app/app.reducer'; -import { AngularticsProviderMock } from '../../app/shared/mocks/angulartics-provider.service.mock'; -import { Angulartics2DSpace } from '../../app/statistics/angulartics/dspace-provider'; -import { AuthService } from '../../app/core/auth/auth.service'; -import { AuthServiceMock } from '../../app/shared/mocks/auth.service.mock'; -import { ActivatedRoute, Router } from '@angular/router'; -import { RouterMock } from '../../app/shared/mocks/router.mock'; -import { MockActivatedRoute } from '../../app/shared/mocks/active-router.mock'; -import { MenuService } from '../../app/shared/menu/menu.service'; -import { LocaleService } from '../../app/core/locale/locale.service'; -import { environment } from '../../environments/environment'; -import { provideMockStore } from '@ngrx/store/testing'; -import { AppComponent } from '../../app/app.component'; -import { RouteService } from '../../app/core/services/route.service'; -import { getMockLocaleService } from '../../app/app.component.spec'; -import { MenuServiceStub } from '../../app/shared/testing/menu-service.stub'; -import { CorrelationIdService } from '../../app/correlation-id/correlation-id.service'; -import { KlaroService } from '../../app/shared/cookies/klaro.service'; -import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; -import { TranslateLoaderMock } from '../../app/shared/mocks/translate-loader.mock'; -import { getTestScheduler } from 'jasmine-marbles'; -import { ThemeService } from '../../app/shared/theme-support/theme.service'; -import { getMockThemeService } from '../../app/shared/mocks/theme-service.mock'; -import { BrowserInitService } from './browser-init.service'; -import { TransferState } from '@angular/platform-browser'; - -const initialState = { - core: { - auth: { - loading: false, - blocking: true, - } - } -}; - -describe('BrowserInitService', () => { - describe('browser-specific initialization steps', () => { - let correlationIdServiceSpy; - let dspaceTransferStateSpy; - let transferStateSpy; - let metadataServiceSpy; - let breadcrumbsServiceSpy; - let klaroServiceSpy; - let googleAnalyticsSpy; - - beforeEach(waitForAsync(() => { - correlationIdServiceSpy = jasmine.createSpyObj('correlationIdServiceSpy', [ - 'initCorrelationId', - ]); - dspaceTransferStateSpy = jasmine.createSpyObj('dspaceTransferStateSpy', [ - 'transfer', - ]); - transferStateSpy = jasmine.createSpyObj('dspaceTransferStateSpy', [ - 'get', 'hasKey' - ]); - breadcrumbsServiceSpy = jasmine.createSpyObj('breadcrumbsServiceSpy', [ - 'listenForRouteChanges', - ]); - metadataServiceSpy = jasmine.createSpyObj('metadataService', [ - 'listenForRouteChange', - ]); - klaroServiceSpy = jasmine.createSpyObj('klaroServiceSpy', [ - 'initialize', - ]); - googleAnalyticsSpy = jasmine.createSpyObj('googleAnalyticsService', [ - 'addTrackingIdToPage', - ]); - - - TestBed.resetTestingModule(); - TestBed.configureTestingModule({ - imports: [ - CommonModule, - StoreModule.forRoot(authReducer, storeModuleConfig), - TranslateModule.forRoot({ - loader: { - provide: TranslateLoader, - useClass: TranslateLoaderMock - } - }), - ], - providers: [ - { provide: InitService, useClass: BrowserInitService }, - { provide: CorrelationIdService, useValue: correlationIdServiceSpy }, - { provide: APP_CONFIG, useValue: environment }, - { provide: LocaleService, useValue: getMockLocaleService() }, - { provide: Angulartics2DSpace, useValue: new AngularticsProviderMock() }, - { provide: MetadataService, useValue: metadataServiceSpy }, - { provide: BreadcrumbsService, useValue: breadcrumbsServiceSpy }, - { provide: AuthService, useValue: new AuthServiceMock() }, - { provide: Router, useValue: new RouterMock() }, - { provide: ActivatedRoute, useValue: new MockActivatedRoute() }, - { provide: MenuService, useValue: new MenuServiceStub() }, - { provide: KlaroService, useValue: klaroServiceSpy }, - { provide: GoogleAnalyticsService, useValue: googleAnalyticsSpy }, - { provide: ThemeService, useValue: getMockThemeService() }, - provideMockStore({ initialState }), - AppComponent, - RouteService, - { provide: TransferState, useValue: undefined }, - ] - }); - })); - - describe('initGoogleÀnalytics', () => { - it('should call googleAnalyticsService.addTrackingIdToPage()', inject([InitService], (service) => { - // @ts-ignore - service.initGoogleAnalytics(); - expect(googleAnalyticsSpy.addTrackingIdToPage).toHaveBeenCalledTimes(1); - })); - }); - - describe('initKlaro', () => { - const BLOCKING = { - t: { core: { auth: { blocking: true } } }, - f: { core: { auth: { blocking: false } } }, - }; - - it('should not initialize Klaro while auth is blocking', () => { - getTestScheduler().run(({ cold, flush}) => { - TestBed.overrideProvider(Store, { useValue: cold('t--t--t--', BLOCKING) }); - const service = TestBed.inject(InitService); - - // @ts-ignore - service.initKlaro(); - flush(); - expect(klaroServiceSpy.initialize).not.toHaveBeenCalled(); - }); - }); - - - it('should only initialize Klaro the first time auth is unblocked', () => { - getTestScheduler().run(({ cold, flush}) => { - TestBed.overrideProvider(Store, { useValue: cold('t--t--f--t--f--', BLOCKING) }); - const service = TestBed.inject(InitService); - - // @ts-ignore - service.initKlaro(); - flush(); - expect(klaroServiceSpy.initialize).toHaveBeenCalledTimes(1); - }); - }); - }); - }); -}); - diff --git a/src/modules/app/browser-init.service.ts b/src/modules/app/browser-init.service.ts index 2d49870d58..05c591b0c6 100644 --- a/src/modules/app/browser-init.service.ts +++ b/src/modules/app/browser-init.service.ts @@ -6,7 +6,7 @@ * http://www.dspace.org/license/ */ import { InitService } from '../../app/init.service'; -import { select, Store } from '@ngrx/store'; +import { Store } from '@ngrx/store'; import { AppState } from '../../app/app.reducer'; import { TransferState } from '@angular/platform-browser'; import { APP_CONFIG, APP_CONFIG_STATE, AppConfig } from '../../config/app-config.interface'; @@ -21,15 +21,13 @@ import { Angulartics2DSpace } from '../../app/statistics/angulartics/dspace-prov import { GoogleAnalyticsService } from '../../app/statistics/google-analytics.service'; import { MetadataService } from '../../app/core/metadata/metadata.service'; import { BreadcrumbsService } from '../../app/breadcrumbs/breadcrumbs.service'; -import { CSSVariableService } from '../../app/shared/sass-helper/sass-helper.service'; import { KlaroService } from '../../app/shared/cookies/klaro.service'; import { AuthService } from '../../app/core/auth/auth.service'; import { ThemeService } from '../../app/shared/theme-support/theme.service'; import { StoreAction, StoreActionTypes } from '../../app/store.actions'; import { coreSelector } from '../../app/core/core.selectors'; -import { distinctUntilChanged, filter, find, map, take } from 'rxjs/operators'; +import { find, map } from 'rxjs/operators'; import { isNotEmpty } from '../../app/shared/empty.util'; -import { isAuthenticationBlocking } from '../../app/core/auth/selectors'; /** * Performs client-side initialization. @@ -91,12 +89,7 @@ export class BrowserInitService extends InitService { this.initKlaro(); - // wait for auth to be ready - await this.store.pipe( - select(isAuthenticationBlocking), - distinctUntilChanged(), - find((b: boolean) => b === false) - ).toPromise(); + await this.authenticationReady$().toPromise(); return true; }; @@ -124,16 +117,11 @@ export class BrowserInitService extends InitService { } /** - * Initialize Klaro + * Initialize Klaro (once authentication is resolved) * @protected */ protected initKlaro() { - this.store.pipe( - select(isAuthenticationBlocking), - distinctUntilChanged(), - filter((isBlocking: boolean) => isBlocking === false), - take(1) - ).subscribe(() => { + this.authenticationReady$().subscribe(() => { this.klaroService.initialize(); }); } diff --git a/src/modules/app/server-init.service.ts b/src/modules/app/server-init.service.ts index fb3539ecfa..2e35083bf4 100644 --- a/src/modules/app/server-init.service.ts +++ b/src/modules/app/server-init.service.ts @@ -67,12 +67,7 @@ export class ServerInitService extends InitService { this.initRouteListeners(); this.themeService.listenForThemeChanges(false); - // wait for auth to be ready - await this.store.pipe( - select(isAuthenticationBlocking), - distinctUntilChanged(), - find((b: boolean) => b === false) - ).toPromise(); + await this.authenticationReady$().toPromise(); return true; };