From 0ae61d8f6566abccd7640b5598b78e9c721a4f7e Mon Sep 17 00:00:00 2001 From: Florent Gravin Date: Mon, 27 Nov 2023 15:54:54 +0100 Subject: [PATCH] test(platform): adapt new imports from tests move from AuthService to PlatformeService --- .../home-header/home-header.component.spec.ts | 24 +-- .../home/home-header/home-header.component.ts | 4 +- .../search-filters.component.spec.ts | 11 +- apps/metadata-editor/src/app/app.module.ts | 2 + .../search-header.component.html | 2 +- .../search-header.component.spec.ts | 68 ++------ .../search-header/search-header.component.ts | 8 +- .../my-org-users/my-org-users.component.ts | 4 +- .../my-org-records.component.ts | 4 +- .../my-records/my-records.component.spec.ts | 10 +- .../my-records/my-records.component.ts | 5 +- .../src/lib/gn4/auth/auth.service.spec.ts | 41 ----- .../gn4/favorites/favorites.service.spec.ts | 24 +-- ...rganizations-from-metadata.service.spec.ts | 18 +- .../organizations-from-metadata.service.ts | 6 +- .../gn4/platform/gn4-platform.service.spec.ts | 162 ++++++++++++++++++ .../lib/gn4/platform/gn4-platform.service.ts | 18 +- .../src/lib/platform.service.interface.ts | 5 +- libs/common/fixtures/src/lib/user.fixtures.ts | 8 +- .../src/lib/my-org/my-org.service.spec.ts | 30 ++-- .../favorite-star.component.spec.ts | 23 ++- .../search/src/lib/state/effects.spec.ts | 14 +- libs/feature/search/src/lib/state/effects.ts | 6 +- 23 files changed, 300 insertions(+), 197 deletions(-) create mode 100644 libs/api/repository/src/lib/gn4/platform/gn4-platform.service.spec.ts diff --git a/apps/datahub/src/app/home/home-header/home-header.component.spec.ts b/apps/datahub/src/app/home/home-header/home-header.component.spec.ts index 0978824eef..75ac62a7ab 100644 --- a/apps/datahub/src/app/home/home-header/home-header.component.spec.ts +++ b/apps/datahub/src/app/home/home-header/home-header.component.spec.ts @@ -2,8 +2,8 @@ import { NO_ERRORS_SCHEMA } from '@angular/core' import { ComponentFixture, TestBed } from '@angular/core/testing' import { By } from '@angular/platform-browser' import { - RouterFacade, ROUTER_ROUTE_SEARCH, + RouterFacade, } from '@geonetwork-ui/feature/router' import { FieldsService, @@ -15,10 +15,10 @@ import { BehaviorSubject, firstValueFrom, of } from 'rxjs' import { ROUTER_ROUTE_NEWS } from '../../router/constants' import { HeaderBadgeButtonComponent } from '../header-badge-button/header-badge-button.component' import { HomeHeaderComponent } from './home-header.component' -import resetAllMocks = jest.resetAllMocks import { SortByEnum } from '@geonetwork-ui/common/domain/model/search' -import { AuthService } from '@geonetwork-ui/api/repository/gn4' import { _setLanguages } from '@geonetwork-ui/util/app-config' +import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface' +import resetAllMocks = jest.resetAllMocks jest.mock('@geonetwork-ui/util/app-config', () => { let _languages = ['pt', 'de'] @@ -71,6 +71,11 @@ class searchServiceMock { setFilters = jest.fn() } +const isAnonymous$ = new BehaviorSubject(false) +class PlatformServiceMock { + isAnonymous = jest.fn(() => isAnonymous$) +} + class AuthServiceMock { authReady = jest.fn(() => this._authSubject$) _authSubject$ = new BehaviorSubject({}) @@ -83,7 +88,6 @@ class FieldsServiceMock { describe('HeaderComponent', () => { let component: HomeHeaderComponent let fixture: ComponentFixture - let authService: AuthService let searchService: SearchService let searchFacade: SearchFacade let routerFacade: RouterFacade @@ -108,8 +112,8 @@ describe('HeaderComponent', () => { useClass: searchServiceMock, }, { - provide: AuthService, - useClass: AuthServiceMock, + provide: PlatformServiceInterface, + useClass: PlatformServiceMock, }, { provide: FieldsService, @@ -117,7 +121,6 @@ describe('HeaderComponent', () => { }, ], }).compileComponents() - authService = TestBed.inject(AuthService) searchService = TestBed.inject(SearchService) searchFacade = TestBed.inject(SearchFacade) routerFacade = TestBed.inject(RouterFacade) @@ -140,10 +143,7 @@ describe('HeaderComponent', () => { describe('isAuthenticated$', () => { describe('user is authenticated', () => { beforeEach(() => { - ;(authService as any)._authSubject$.next({ - id: 'user-id', - name: 'testuser', - }) + isAnonymous$.next(false) }) it('displays favoriteBadge when authenticated', async () => { const isAuthenticated = await firstValueFrom( @@ -154,7 +154,7 @@ describe('HeaderComponent', () => { }) describe('user is NOT authenticated', () => { beforeEach(() => { - ;(authService as any)._authSubject$.next(null) + isAnonymous$.next(true) }) it('does NOT display favoriteBadge when NOT authenticated', async () => { const isAuthenticated = await firstValueFrom( diff --git a/apps/datahub/src/app/home/home-header/home-header.component.ts b/apps/datahub/src/app/home/home-header/home-header.component.ts index 29bde73af6..959596af08 100644 --- a/apps/datahub/src/app/home/home-header/home-header.component.ts +++ b/apps/datahub/src/app/home/home-header/home-header.component.ts @@ -66,8 +66,8 @@ export class HomeHeaderComponent { ) isAuthenticated$ = this.platformService - .getMe() - .pipe(map((user) => !!user?.id)) + .isAnonymous() + .pipe(map((isAnonymous) => !isAnonymous)) onFuzzySearchSelection(record: CatalogRecord) { this.routerFacade.goToMetadata(record) diff --git a/apps/datahub/src/app/home/search/search-filters/search-filters.component.spec.ts b/apps/datahub/src/app/home/search/search-filters/search-filters.component.spec.ts index 4b997048fd..95b4bc3bb7 100644 --- a/apps/datahub/src/app/home/search/search-filters/search-filters.component.spec.ts +++ b/apps/datahub/src/app/home/search/search-filters/search-filters.component.spec.ts @@ -22,6 +22,7 @@ import { FormsModule } from '@angular/forms' import { FieldFilters } from '@geonetwork-ui/common/domain/model/search' import { USER_FIXTURE } from '@geonetwork-ui/common/fixtures' import { AuthService } from '@geonetwork-ui/api/repository/gn4' +import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface' jest.mock('@geonetwork-ui/util/app-config', () => ({ getOptionalSearchConfig: () => ({ @@ -103,10 +104,8 @@ class FieldsServiceMock { } } -class AuthServiceMock { - user$ = new BehaviorSubject(user) - authReady = jest.fn(() => this._authSubject$) - _authSubject$ = new BehaviorSubject({}) +class PlatformServiceMock { + getMe = jest.fn(() => new BehaviorSubject(user)) } describe('SearchFiltersComponent', () => { @@ -138,8 +137,8 @@ describe('SearchFiltersComponent', () => { useClass: FieldsServiceMock, }, { - provide: AuthService, - useClass: AuthServiceMock, + provide: PlatformServiceInterface, + useClass: PlatformServiceMock, }, ], }) diff --git a/apps/metadata-editor/src/app/app.module.ts b/apps/metadata-editor/src/app/app.module.ts index dca34bf612..ebb9d99e7c 100644 --- a/apps/metadata-editor/src/app/app.module.ts +++ b/apps/metadata-editor/src/app/app.module.ts @@ -25,6 +25,7 @@ import { extModules } from './build-specifics' import { DashboardPageComponent } from './dashboard/dashboard-page.component' import { EditorRouterService } from './router.service' import { provideRepositoryUrl } from '@geonetwork-ui/api/repository' +import { provideGn4 } from '@geonetwork-ui/api/repository/gn4' @NgModule({ declarations: [AppComponent], @@ -58,6 +59,7 @@ import { provideRepositoryUrl } from '@geonetwork-ui/api/repository' importProvidersFrom(TranslateModule.forRoot(TRANSLATE_DEFAULT_CONFIG)), provideRepositoryUrl(() => getGlobalConfig().GN4_API_URL), importProvidersFrom(EffectsModule.forRoot()), + provideGn4(), ], bootstrap: [AppComponent], }) diff --git a/apps/metadata-editor/src/app/dashboard/search-header/search-header.component.html b/apps/metadata-editor/src/app/dashboard/search-header/search-header.component.html index f64b9b66e2..2326ec526b 100644 --- a/apps/metadata-editor/src/app/dashboard/search-header/search-header.component.html +++ b/apps/metadata-editor/src/app/dashboard/search-header/search-header.component.html @@ -16,7 +16,7 @@ - + this._authSubject$) - _authSubject$ = new BehaviorSubject({}) -} +import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface' +import { AvatarServiceInterface } from '@geonetwork-ui/api/repository/gn4' class AvatarServiceInterfaceMock { placeholder = 'http://placeholder.com' getProfileIcon = (hash: string) => `${hash}` } -class OrganisationsServiceMock { - organisationsCount$ = of(456) -} -class SearchFacadeMock { - init = jest.fn() - results$ = of(summaryHits) - setPagination = jest.fn(() => this) - setSortBy = jest.fn(() => this) - setConfigRequestFields = jest.fn(() => this) - setResultsLayout = jest.fn(() => this) - searchFilters$ = new BehaviorSubject(user) - authReady = jest.fn(() => this.searchFilters$) -} - -class searchServiceMock { - updateSearchFilters = jest.fn() - setSearch = jest.fn() - setSortBy = jest.fn() - setSortAndFilters = jest.fn() +const me$ = new BehaviorSubject(USER_FIXTURE()) +class PlatformServiceMock { + getMe = jest.fn(() => me$) } describe('SearchHeaderComponent', () => { @@ -63,28 +39,22 @@ describe('SearchHeaderComponent', () => { ], schemas: [NO_ERRORS_SCHEMA], providers: [ - provideRepositoryUrl('/geonetwork/srv/api'), - { provide: AuthService, useClass: AuthServiceMock }, { provide: AvatarServiceInterface, useClass: AvatarServiceInterfaceMock, }, { - provide: OrganizationsServiceInterface, - useClass: OrganisationsServiceMock, - }, - { - provide: SearchFacade, - useClass: SearchFacadeMock, - }, - { - provide: SearchService, - useClass: searchServiceMock, + provide: PlatformServiceInterface, + useClass: PlatformServiceMock, }, ], }) .overrideComponent(SearchHeaderComponent, { - set: { changeDetection: ChangeDetectionStrategy.Default }, + set: { + changeDetection: ChangeDetectionStrategy.Default, + imports: [], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + }, }) .compileComponents() diff --git a/apps/metadata-editor/src/app/dashboard/search-header/search-header.component.ts b/apps/metadata-editor/src/app/dashboard/search-header/search-header.component.ts index c339c74fcc..7ce966490d 100644 --- a/apps/metadata-editor/src/app/dashboard/search-header/search-header.component.ts +++ b/apps/metadata-editor/src/app/dashboard/search-header/search-header.component.ts @@ -4,10 +4,8 @@ import { MatIconModule } from '@angular/material/icon' import { LetDirective } from '@ngrx/component' import { FeatureSearchModule } from '@geonetwork-ui/feature/search' import { UiElementsModule } from '@geonetwork-ui/ui/elements' -import { - AuthService, - AvatarServiceInterface, -} from '@geonetwork-ui/api/repository/gn4' +import { AvatarServiceInterface } from '@geonetwork-ui/api/repository/gn4' +import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface' @Component({ selector: 'md-editor-search-header', @@ -27,7 +25,7 @@ export class SearchHeaderComponent { public placeholder = this.avatarService.placeholder constructor( - public authService: AuthService, + public platformService: PlatformServiceInterface, private avatarService: AvatarServiceInterface ) {} } diff --git a/apps/metadata-editor/src/app/my-org-users/my-org-users.component.ts b/apps/metadata-editor/src/app/my-org-users/my-org-users.component.ts index aae4f1a49f..2ff8d66819 100644 --- a/apps/metadata-editor/src/app/my-org-users/my-org-users.component.ts +++ b/apps/metadata-editor/src/app/my-org-users/my-org-users.component.ts @@ -5,7 +5,7 @@ import { TranslateModule } from '@ngx-translate/core' import { CommonModule } from '@angular/common' import { MyOrgService } from '@geonetwork-ui/feature/catalog' import { SearchFacade } from '@geonetwork-ui/feature/search' -import { UserApiModel } from '@geonetwork-ui/data-access/gn4' +import { UserModel } from '@geonetwork-ui/common/domain/model/user/user.model' @Component({ selector: 'md-editor-my-org-users', @@ -25,7 +25,7 @@ export class MyOrgUsersComponent implements OnDestroy { logoUrl: string recordCount: number userCount: number - userList: UserApiModel[] + userList: UserModel[] } private myOrgDataSubscription diff --git a/apps/metadata-editor/src/app/records/my-org-records/my-org-records.component.ts b/apps/metadata-editor/src/app/records/my-org-records/my-org-records.component.ts index 032d367268..be7294e334 100644 --- a/apps/metadata-editor/src/app/records/my-org-records/my-org-records.component.ts +++ b/apps/metadata-editor/src/app/records/my-org-records/my-org-records.component.ts @@ -6,8 +6,8 @@ import { MyOrgService } from '@geonetwork-ui/feature/catalog' import { SearchFacade } from '@geonetwork-ui/feature/search' import { Organization } from '@geonetwork-ui/common/domain/model/record' import { OrganizationsServiceInterface } from '@geonetwork-ui/common/domain/organizations.service.interface' -import { UserApiModel } from '@geonetwork-ui/data-access/gn4' import { EditorRouterService } from '../../router.service' +import { UserModel } from '@geonetwork-ui/common/domain/model/user/user.model' @Component({ selector: 'md-editor-my-org-records', @@ -22,7 +22,7 @@ export class MyOrgRecordsComponent implements OnDestroy { logoUrl: string recordCount: number userCount: number - userList: UserApiModel[] + userList: UserModel[] } public myOrgDataSubscription diff --git a/apps/metadata-editor/src/app/records/my-records/my-records.component.spec.ts b/apps/metadata-editor/src/app/records/my-records/my-records.component.spec.ts index f1fbc3d519..4c67889604 100644 --- a/apps/metadata-editor/src/app/records/my-records/my-records.component.spec.ts +++ b/apps/metadata-editor/src/app/records/my-records/my-records.component.spec.ts @@ -8,6 +8,7 @@ import { BehaviorSubject, of } from 'rxjs' import { USER_FIXTURE } from '@geonetwork-ui/common/fixtures' import { AuthService } from '@geonetwork-ui/api/repository/gn4' import { EditorRouterService } from '../../router.service' +import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface' @Component({ // eslint-disable-next-line @@ -38,6 +39,11 @@ class FieldsServiceMock { buildFiltersFromFieldValues = jest.fn((val) => of(val)) } +const me$ = new BehaviorSubject(USER_FIXTURE()) +class PlatformServiceMock { + getMe = jest.fn(() => me$) +} + describe('MyRecordsComponent', () => { let component: MyRecordsComponent let fixture: ComponentFixture @@ -56,8 +62,8 @@ describe('MyRecordsComponent', () => { useClass: SearchFacadeMock, }, { - provide: AuthService, - useClass: AuthServiceMock, + provide: PlatformServiceInterface, + useClass: PlatformServiceMock, }, { provide: EditorRouterService, diff --git a/apps/metadata-editor/src/app/records/my-records/my-records.component.ts b/apps/metadata-editor/src/app/records/my-records/my-records.component.ts index cd12f08f91..fa1cf714d4 100644 --- a/apps/metadata-editor/src/app/records/my-records/my-records.component.ts +++ b/apps/metadata-editor/src/app/records/my-records/my-records.component.ts @@ -6,6 +6,7 @@ import { FieldsService, SearchFacade } from '@geonetwork-ui/feature/search' import { AuthService } from '@geonetwork-ui/api/repository/gn4' import { EditorRouterService } from '../../router.service' import { Subscription } from 'rxjs' +import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface' @Component({ selector: 'md-editor-my-records', @@ -21,13 +22,13 @@ export class MyRecordsComponent implements OnInit, OnDestroy { constructor( public fieldsService: FieldsService, public searchFacade: SearchFacade, - private authService: AuthService, + private platformService: PlatformServiceInterface, private router: EditorRouterService ) {} ngOnInit() { this.searchFacade.resetSearch() - this.sub = this.authService.user$.subscribe((user) => { + this.sub = this.platformService.getMe().subscribe((user) => { this.ownerId = user.id this.fieldsService .buildFiltersFromFieldValues({ owner: user.id }) diff --git a/libs/api/repository/src/lib/gn4/auth/auth.service.spec.ts b/libs/api/repository/src/lib/gn4/auth/auth.service.spec.ts index c587381c57..56890beab9 100644 --- a/libs/api/repository/src/lib/gn4/auth/auth.service.spec.ts +++ b/libs/api/repository/src/lib/gn4/auth/auth.service.spec.ts @@ -74,33 +74,6 @@ describe('AuthService', () => { expect(service).toBeTruthy() }) - describe('authentication', () => { - beforeEach(() => { - service = TestBed.inject(AuthService) - }) - describe('#authReady', () => { - it('emits a value on subscribe after auth was queried', () => { - let emitted = false - service.authReady().subscribe(() => (emitted = true)) - me$.next(null) - expect(emitted).toBeTruthy() - }) - }) - describe('#isAnonymous', () => { - it('returns true for anonymous user', () => { - let isAnonymous = false - service.isAnonymous$.subscribe((anonymous) => (isAnonymous = anonymous)) - me$.next(null) - expect(isAnonymous).toBeTruthy() - }) - it('returns false for authenticated user', () => { - let isAnonymous = true - service.isAnonymous$.subscribe((anonymous) => (isAnonymous = anonymous)) - me$.next(userMock) - expect(isAnonymous).toBeFalsy() - }) - }) - }) describe('login URL (default)', () => { beforeEach(() => { loginUrlTokenMock = undefined @@ -143,18 +116,4 @@ describe('AuthService', () => { ) }) }) - describe('#mapToUserModel', () => { - it('maps to UserModel', () => { - expect(service['mapToUserModel'](userMock)).toEqual({ - id: '21737', - profile: 'Administrator', - username: 'C2C-gravin', - name: 'Florent', - surname: 'Gravin', - email: 'florent.gravin@camptocamp.com', - profileIcon: 'http://icon_service.com/girafe', - organisation: null, - }) - }) - }) }) diff --git a/libs/api/repository/src/lib/gn4/favorites/favorites.service.spec.ts b/libs/api/repository/src/lib/gn4/favorites/favorites.service.spec.ts index e9184daf64..9b69a93a60 100644 --- a/libs/api/repository/src/lib/gn4/favorites/favorites.service.spec.ts +++ b/libs/api/repository/src/lib/gn4/favorites/favorites.service.spec.ts @@ -1,5 +1,4 @@ import { FavoritesService } from './favorites.service' -import { AuthService } from '../auth/auth.service' import { MeResponseApiModel, UserselectionsApiService, @@ -7,9 +6,10 @@ import { import { firstValueFrom, of, throwError } from 'rxjs' import { delay } from 'rxjs/operators' import { fakeAsync, tick } from '@angular/core/testing' +import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface' -class AuthServiceMock { - authReady = jest.fn(() => +class Gn4PlatformServiceMock { + getMe = jest.fn(() => of({ id: '1234', name: 'fakeuser', @@ -26,12 +26,12 @@ class UserSelectionsServiceMock { describe('FavoritesService', () => { let service: FavoritesService let userSelectionsService: UserselectionsApiService - let authService: AuthService + let platform: PlatformServiceInterface beforeEach(() => { userSelectionsService = new UserSelectionsServiceMock() as any - authService = new AuthServiceMock() as any - service = new FavoritesService(userSelectionsService, authService) + platform = new Gn4PlatformServiceMock() as any + service = new FavoritesService(userSelectionsService, platform) }) it('should be created', () => { @@ -41,8 +41,8 @@ describe('FavoritesService', () => { describe('myFavorites$', () => { describe('when not authenticated', () => { beforeEach(() => { - authService.authReady = () => of(null) - service = new FavoritesService(userSelectionsService, authService) + platform.getMe = () => of(null) + service = new FavoritesService(userSelectionsService, platform) }) it('returns an empty array', async () => { const uuids = await firstValueFrom(service.myFavoritesUuid$) @@ -98,8 +98,8 @@ describe('FavoritesService', () => { let favorites describe('when not authenticated', () => { beforeEach(() => { - authService.authReady = () => of(null) - service = new FavoritesService(userSelectionsService, authService) + platform.getMe = () => of(null) + service = new FavoritesService(userSelectionsService, platform) }) it('throws an error', async () => { expect.assertions(1) @@ -160,8 +160,8 @@ describe('FavoritesService', () => { let favorites describe('when not authenticated', () => { beforeEach(() => { - authService.authReady = () => of(null) - service = new FavoritesService(userSelectionsService, authService) + platform.getMe = () => of(null) + service = new FavoritesService(userSelectionsService, platform) }) it('throws an error', async () => { expect.assertions(1) diff --git a/libs/api/repository/src/lib/gn4/organizations/organizations-from-metadata.service.spec.ts b/libs/api/repository/src/lib/gn4/organizations/organizations-from-metadata.service.spec.ts index 8a6343bf18..9678169e26 100644 --- a/libs/api/repository/src/lib/gn4/organizations/organizations-from-metadata.service.spec.ts +++ b/libs/api/repository/src/lib/gn4/organizations/organizations-from-metadata.service.spec.ts @@ -2,7 +2,6 @@ import { TestBed } from '@angular/core/testing' import { GroupsApiService, SearchApiService, - SiteApiService, } from '@geonetwork-ui/data-access/gn4' import { firstValueFrom, lastValueFrom, of } from 'rxjs' import { take } from 'rxjs/operators' @@ -16,6 +15,7 @@ import { GROUPS_FIXTURE, } from '@geonetwork-ui/common/fixtures' import { LangService } from '@geonetwork-ui/util/i18n' +import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface' const sampleOrgA: Organization = { description: 'A description for ARE', @@ -145,12 +145,8 @@ class GoupsApiServiceMock { getGroups = jest.fn(() => of(GROUPS_FIXTURE)) } -class SiteApiServiceMock { - getSiteOrPortalDescription = jest.fn(() => - of({ - 'system/platform/version': geonetworkVersion, - }) - ) +class Gn4PlatformServiceMock { + getApiVersion = jest.fn(() => of(geonetworkVersion)) } class LangServiceMock { @@ -179,14 +175,14 @@ describe.each(['4.2.2-00', '4.2.3-xx', '4.2.5-xx'])( provide: SearchApiService, useClass: SearchApiServiceMock, }, - { - provide: SiteApiService, - useClass: SiteApiServiceMock, - }, { provide: LangService, useClass: LangServiceMock, }, + { + provide: PlatformServiceInterface, + useClass: Gn4PlatformServiceMock, + }, ], }) service = TestBed.inject(OrganizationsFromMetadataService) diff --git a/libs/api/repository/src/lib/gn4/organizations/organizations-from-metadata.service.ts b/libs/api/repository/src/lib/gn4/organizations/organizations-from-metadata.service.ts index c47f5124e0..504412fb37 100644 --- a/libs/api/repository/src/lib/gn4/organizations/organizations-from-metadata.service.ts +++ b/libs/api/repository/src/lib/gn4/organizations/organizations-from-metadata.service.ts @@ -58,7 +58,7 @@ export class OrganizationsFromMetadataService shareReplay() ) private organisationsAggs$: Observable = - this.platformService.apiVersion$.pipe( + this.platformService.getApiVersion().pipe( switchMap((version) => this.searchApiService.search( 'bucket', @@ -229,7 +229,7 @@ export class OrganizationsFromMetadataService } getFiltersForOrgs(organisations: Organization[]): Observable { - return this.platformService.apiVersion$.pipe( + return this.platformService.getApiVersion().pipe( map((gnVersion) => { const fieldName = gnVersion.startsWith('4.2.2') ? 'OrgForResource' @@ -245,7 +245,7 @@ export class OrganizationsFromMetadataService } getOrgsFromFilters(filters: FieldFilters): Observable { - return this.platformService.apiVersion$.pipe( + return this.platformService.getApiVersion().pipe( switchMap((gnVersion) => { const fieldName = gnVersion.startsWith('4.2.2') ? 'OrgForResource' diff --git a/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.spec.ts b/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.spec.ts new file mode 100644 index 0000000000..74dccf646a --- /dev/null +++ b/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.spec.ts @@ -0,0 +1,162 @@ +import { + MeApiService, + SiteApiService, + UsersApiService, +} from '@geonetwork-ui/data-access/gn4' +import { TestBed } from '@angular/core/testing' +import { Gn4PlatformService } from './gn4-platform.service' +import { firstValueFrom, lastValueFrom, of, Subject } from 'rxjs' +import { AvatarServiceInterface } from '../auth/avatar.service.interface' +import { Gn4PlatformMapper } from './gn4-platform.mapper' + +let geonetworkVersion: string + +const userMock = { + id: '21737', + profile: 'Administrator', + username: 'C2C-gravin', + name: 'Florent', + surname: 'Gravin', + email: 'florent.gravin@camptocamp.com', + hash: 'girafe', + organisation: null, + admin: true, + groupsWithRegisteredUser: [], + groupsWithEditor: [], + groupsWithReviewer: [], + groupsWithUserAdmin: [], +} + +const me$ = new Subject() +class MeApiMock { + getMe() { + return me$ + } +} + +class AvatarServiceInterfaceMock { + placeholder = 'http://placeholder.com' + getProfileIcon = jest.fn((hash: string) => `http://icon_service.com/${hash}`) +} + +class SiteApiServiceMock { + getSiteOrPortalDescription = jest.fn(() => + of({ + 'system/platform/version': geonetworkVersion, + }) + ) +} +class UsersApiServiceMock { + getUsers() { + return of([ + { + username: 'ken', + email: 'ken@sf2.com', + id: 1, + }, + { + username: 'ryu', + email: 'ryu@sf2.com', + id: 2, + }, + ]) + } +} + +describe('Gn4PlatformService', () => { + let service: Gn4PlatformService + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + Gn4PlatformService, + Gn4PlatformMapper, + { + provide: SiteApiService, + useClass: SiteApiServiceMock, + }, + { + provide: UsersApiService, + useClass: UsersApiServiceMock, + }, + { + provide: MeApiService, + useClass: MeApiMock, + }, + { + provide: AvatarServiceInterface, + useClass: AvatarServiceInterfaceMock, + }, + ], + }) + service = TestBed.inject(Gn4PlatformService) + }) + + it('creates', () => { + expect(service).toBeTruthy() + }) + + it('fetches version from settings', async () => { + geonetworkVersion = '4.2.0' + const version = await firstValueFrom(service.getApiVersion()) + expect(version).toEqual('4.2.0') + }) + it('fetches users from api', async () => { + const users = await firstValueFrom(service.getUsers()) + expect(users).toEqual([ + { + username: 'ken', + email: 'ken@sf2.com', + id: 1, + }, + { + username: 'ryu', + email: 'ryu@sf2.com', + id: 2, + }, + ]) + }) + it('is of type GeoNetwork', async () => { + expect(service.getTye()).toEqual('GeoNetwork') + }) + describe('MeService', () => { + let me + beforeEach(() => { + service.getMe().subscribe((response) => (me = response)) + }) + describe('When user is logged in', () => { + beforeEach(() => { + me$.next(userMock) + }) + it('returns mapped user ', async () => { + expect(me).toEqual({ + id: '21737', + profile: 'Administrator', + username: 'C2C-gravin', + name: 'Florent', + surname: 'Gravin', + email: 'florent.gravin@camptocamp.com', + profileIcon: 'http://icon_service.com/girafe', + organisation: null, + }) + }) + it('is not anonymous ', async () => { + const isAnonymous = await firstValueFrom(service.isAnonymous()) + expect(isAnonymous).toBe(false) + }) + }) + describe('When no user is logged in', () => { + beforeEach(() => { + me$.next({}) + }) + it('returns no user ', async () => { + const me = await firstValueFrom(service.getMe()) + expect(me).toEqual({ profileIcon: 'http://icon_service.com/undefined' }) + }) + it('is anonymous ', async () => { + const isAnonymous = await firstValueFrom(service.isAnonymous()) + expect(isAnonymous).toBe(true) + }) + }) + }) +}) diff --git a/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts b/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts index f77edab58d..59fcda460b 100644 --- a/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +++ b/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts @@ -17,21 +17,22 @@ import { Gn4PlatformMapper } from './gn4-platform.mapper' const minApiVersion = '4.2.0' @Injectable() export class Gn4PlatformService implements PlatformServiceInterface { + private readonly type = 'GeoNetwork' private me$: Observable private users$: Observable isAnonymous$: Observable - settings$ = of(true).pipe( + private settings$ = of(true).pipe( switchMap(() => this.siteApiService.getSiteOrPortalDescription()), shareReplay(1) ) - readonly apiVersion$ = this.settings$.pipe( + private readonly apiVersion$ = this.settings$.pipe( map((info) => info['system/platform/version'] as string), shareReplay(1) ) - readonly isApiCompatible$ = this.apiVersion$.pipe( + private readonly isApiCompatible$ = this.apiVersion$.pipe( tap( (version) => version < minApiVersion && @@ -54,6 +55,17 @@ export class Gn4PlatformService implements PlatformServiceInterface { this.users$ = this.usersApi.getUsers().pipe(shareReplay()) } + getTye(): string { + return this.type + } + + getApiVersion(): Observable { + return this.apiVersion$ + } + isApiCompatible(): Observable { + return this.isApiCompatible$ + } + getMe(): Observable { return this.me$ } diff --git a/libs/common/domain/src/lib/platform.service.interface.ts b/libs/common/domain/src/lib/platform.service.interface.ts index 3f79a4c52f..6d84d9fa90 100644 --- a/libs/common/domain/src/lib/platform.service.interface.ts +++ b/libs/common/domain/src/lib/platform.service.interface.ts @@ -3,8 +3,9 @@ import { MeUserModel, UserModel } from './model/user/user.model' import { Organization } from './model/record/organization.model' export abstract class PlatformServiceInterface { - abstract readonly apiVersion$: Observable - abstract readonly isApiCompatible$: Observable + abstract getTye(): string + abstract getApiVersion(): Observable + abstract isApiCompatible(): Observable abstract getMe(): Observable abstract isAnonymous(): Observable diff --git a/libs/common/fixtures/src/lib/user.fixtures.ts b/libs/common/fixtures/src/lib/user.fixtures.ts index 9d55502797..81183be9d9 100644 --- a/libs/common/fixtures/src/lib/user.fixtures.ts +++ b/libs/common/fixtures/src/lib/user.fixtures.ts @@ -1,6 +1,6 @@ -import { UserModel } from '@geonetwork-ui/common/domain/model/user/user.model' +import { MeUserModel } from '@geonetwork-ui/common/domain/model/user/user.model' -export const USER_FIXTURE = (): UserModel => ({ +export const USER_FIXTURE = (): MeUserModel => ({ id: '46798', profile: 'Administrator', username: 'Gravin', @@ -12,7 +12,7 @@ export const USER_FIXTURE = (): UserModel => ({ 'https://www.gravatar.com/avatar/dbdffd183622800bcf8587328daf43a6?d=mp', }) -export const USER_FIXTURE_ANON = (): UserModel => ({ +export const USER_FIXTURE_ANON = (): MeUserModel => ({ id: '161', profile: 'Administrator', username: 'ghost16', @@ -24,7 +24,7 @@ export const USER_FIXTURE_ANON = (): UserModel => ({ 'https://www.gravatar.com/avatar/dbdffd183622800bcf8587328daf43a6?d=mp', }) -export const USERS_FIXTURE = (): UserModel[] => [ +export const USERS_FIXTURE = (): MeUserModel[] => [ USER_FIXTURE(), USER_FIXTURE_ANON(), { diff --git a/libs/feature/catalog/src/lib/my-org/my-org.service.spec.ts b/libs/feature/catalog/src/lib/my-org/my-org.service.spec.ts index 2046c26fd2..7a19836c3b 100644 --- a/libs/feature/catalog/src/lib/my-org/my-org.service.spec.ts +++ b/libs/feature/catalog/src/lib/my-org/my-org.service.spec.ts @@ -1,13 +1,13 @@ import { TestBed } from '@angular/core/testing' import { MyOrgService } from './my-org.service' -import { AuthService } from '@geonetwork-ui/api/repository/gn4' +import { AvatarServiceInterface } from '@geonetwork-ui/api/repository/gn4' import { OrganizationsServiceInterface } from '@geonetwork-ui/common/domain/organizations.service.interface' -import { BehaviorSubject, Observable, of, Subject } from 'rxjs' +import { BehaviorSubject, of } from 'rxjs' import { UserApiModel } from '@geonetwork-ui/data-access/gn4' -import { UserModel } from '@geonetwork-ui/common/domain/model/user/user.model' +import { MeUserModel } from '@geonetwork-ui/common/domain/model/user/user.model' import { HttpClientTestingModule } from '@angular/common/http/testing' import { TranslateService } from '@ngx-translate/core' -import { AvatarServiceInterface } from '@geonetwork-ui/api/repository/gn4' +import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface' const translateServiceMock = { currentLang: 'fr', @@ -27,9 +27,16 @@ class orgServiceMock { organisations$ = orgs$ } +const userSubject = new BehaviorSubject(null) +const allUsersSubject = new BehaviorSubject([]) + +class PlatformServiceMock { + getMe = jest.fn(() => userSubject) + getUsers = jest.fn(() => allUsersSubject) +} + describe('MyOrgService', () => { let myOrgService: MyOrgService - let authService: AuthService let orgService: OrganizationsServiceInterface beforeEach(() => { @@ -45,12 +52,14 @@ describe('MyOrgService', () => { useClass: AvatarServiceInterfaceMock, }, { provide: OrganizationsServiceInterface, useClass: orgServiceMock }, - AuthService, + { + provide: PlatformServiceInterface, + useClass: PlatformServiceMock, + }, ], imports: [HttpClientTestingModule], }) myOrgService = TestBed.inject(MyOrgService) - authService = TestBed.inject(AuthService) orgService = TestBed.inject(OrganizationsServiceInterface) }) @@ -59,8 +68,7 @@ describe('MyOrgService', () => { }) it('should update myOrgDataSubject when authService user$ emits a user', () => { - const userSubject = new BehaviorSubject(null) - const user: UserModel = { + const user: MeUserModel = { organisation: 'Géo2France', id: '2', profile: 'profile', @@ -70,7 +78,6 @@ describe('MyOrgService', () => { email: 'email@email', profileIcon: 'icon.com', } - authService.user$ = userSubject.asObservable() userSubject.next(user) @@ -96,13 +103,10 @@ describe('MyOrgService', () => { }) it('should update myOrgDataSubject when authService allUsers$ emits users', () => { - const allUsersSubject = new BehaviorSubject([]) const users: UserApiModel[] = [ { organisation: 'Géo2France' }, { organisation: 'Géo2France' }, ] - authService.allUsers$ = allUsersSubject.asObservable() - allUsersSubject.next(users) myOrgService.myOrgData$.subscribe((data) => { diff --git a/libs/feature/search/src/lib/favorites/favorite-star/favorite-star.component.spec.ts b/libs/feature/search/src/lib/favorites/favorite-star/favorite-star.component.spec.ts index 156c66f26f..c123fe48ff 100644 --- a/libs/feature/search/src/lib/favorites/favorite-star/favorite-star.component.spec.ts +++ b/libs/feature/search/src/lib/favorites/favorite-star/favorite-star.component.spec.ts @@ -7,14 +7,13 @@ import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core' import { TranslateModule, TranslateService } from '@ngx-translate/core' import tippy from 'tippy.js' import { DATASET_RECORDS } from '@geonetwork-ui/common/fixtures' -import { - AuthService, - FavoritesService, -} from '@geonetwork-ui/api/repository/gn4' +import { FavoritesService } from '@geonetwork-ui/api/repository/gn4' +import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface' tippy = jest.fn() -class AuthServiceMock { - isAnonymous$ = new BehaviorSubject(false) +const isAnonymous$ = new BehaviorSubject(false) +class PlatformServiceMock { + isAnonymous = jest.fn(() => isAnonymous$) } class FavoritesServiceMock { @@ -31,7 +30,7 @@ class TranslateServiceMock { describe('FavoriteStarComponent', () => { let component: FavoriteStarComponent let fixture: ComponentFixture - let authService: AuthService + let platformService: PlatformServiceInterface let favoritesService: FavoritesService let favoriteCountHTMLEl: HTMLElement let starToggle: StarToggleComponent @@ -42,8 +41,8 @@ describe('FavoriteStarComponent', () => { imports: [TranslateModule.forRoot()], providers: [ { - provide: AuthService, - useClass: AuthServiceMock, + provide: PlatformServiceInterface, + useClass: PlatformServiceMock, }, { provide: FavoritesService, @@ -63,7 +62,7 @@ describe('FavoriteStarComponent', () => { }) .compileComponents() - authService = TestBed.inject(AuthService) + platformService = TestBed.inject(PlatformServiceInterface) favoritesService = TestBed.inject(FavoritesService) fixture = TestBed.createComponent(FavoriteStarComponent) component = fixture.componentInstance @@ -120,7 +119,7 @@ describe('FavoriteStarComponent', () => { }) describe('when not authenticated', () => { beforeEach(() => { - ;(authService as any).isAnonymous$.next(true) + isAnonymous$.next(true) fixture.detectChanges() }) it('star toggle is disabled', () => { @@ -194,7 +193,7 @@ describe('FavoriteStarComponent', () => { }) it('increase record favorite count by one', () => { expect(favoriteCountHTMLEl.textContent).toEqual( - (component.record.extras.favoriteCount + 1).toString() + ((component.record.extras.favoriteCount as number) + 1).toString() ) }) }) diff --git a/libs/feature/search/src/lib/state/effects.spec.ts b/libs/feature/search/src/lib/state/effects.spec.ts index 3073368f34..ac394a12df 100644 --- a/libs/feature/search/src/lib/state/effects.spec.ts +++ b/libs/feature/search/src/lib/state/effects.spec.ts @@ -45,10 +45,8 @@ import { delay } from 'rxjs/operators' import { FILTER_GEOMETRY } from '../feature-search.module' import { RecordsRepositoryInterface } from '@geonetwork-ui/common/domain/repository/records-repository.interface' import { TestScheduler } from 'rxjs/internal/testing/TestScheduler' -import { - AuthService, - FavoritesService, -} from '@geonetwork-ui/api/repository/gn4' +import { FavoritesService } from '@geonetwork-ui/api/repository/gn4' +import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface' const defaultSearchState = initialState[DEFAULT_SEARCH_KEY] const stateWithSearches = { @@ -69,8 +67,8 @@ const stateWithSearches = { }, } -class AuthServiceMock { - authReady = () => of(true) +class Gn4PlatformServiceMock { + getMe = jest.fn(() => of(true)) } class FavoritesServiceMock { myFavoritesUuid$ = of(['fav001', 'fav002', 'fav003']) @@ -100,8 +98,8 @@ describe('Effects', () => { provideMockActions(() => actions$), SearchEffects, { - provide: AuthService, - useClass: AuthServiceMock, + provide: PlatformServiceInterface, + useClass: Gn4PlatformServiceMock, }, { provide: FavoritesService, diff --git a/libs/feature/search/src/lib/state/effects.ts b/libs/feature/search/src/lib/state/effects.ts index f06ecb416c..d175ee3782 100644 --- a/libs/feature/search/src/lib/state/effects.ts +++ b/libs/feature/search/src/lib/state/effects.ts @@ -43,10 +43,7 @@ import { switchMapWithSearchId } from '../utils/operators/search.operator' import { Geometry } from 'geojson' import { FILTER_GEOMETRY } from '../feature-search.module' import { RecordsRepositoryInterface } from '@geonetwork-ui/common/domain/repository/records-repository.interface' -import { - AuthService, - FavoritesService, -} from '@geonetwork-ui/api/repository/gn4' +import { FavoritesService } from '@geonetwork-ui/api/repository/gn4' import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface' @Injectable() @@ -59,7 +56,6 @@ export class SearchEffects { private actions$: Actions, private store$: Store, private recordsRepository: RecordsRepositoryInterface, - private authService: AuthService, private favoritesService: FavoritesService, private platformService: PlatformServiceInterface, @Optional()