diff --git a/goofy-client/apps/goofy/src/app/app.component.html b/goofy-client/apps/goofy/src/app/app.component.html index 7d6440b7d96c43869ad6af3cff1adc8196d614b8..746c64f6ef9ab7ef6d9f969963613511e93fe420 100644 --- a/goofy-client/apps/goofy/src/app/app.component.html +++ b/goofy-client/apps/goofy/src/app/app.component.html @@ -1,13 +1,13 @@ <ng-container *ngIf="apiRoot$ | async as apiRoot"> <goofy-client-spinner [stateResource]="apiRoot"> - <goofy-client-header-container></goofy-client-header-container> <div class="container"> - <goofy-client-navigation class="mat-app-background left-nav"></goofy-client-navigation> + <goofy-client-navigation-container class="mat-app-background left-nav"></goofy-client-navigation-container> <main [ngClass]="{ small: navigationCollapse$ | async }"><router-outlet></router-outlet></main> + <section class="mat-app-background right-nav"> - <goofy-client-build-info *ngIf="apiRoot.resource" [apiRoot]="apiRoot.resource"></goofy-client-build-info> + <goofy-client-build-info *ngIf="apiRoot.resource" [apiRoot]="apiRoot.resource" data-test-id="build-info"></goofy-client-build-info> </section> </div> </goofy-client-spinner> diff --git a/goofy-client/apps/goofy/src/app/app.component.spec.ts b/goofy-client/apps/goofy/src/app/app.component.spec.ts index a9e762566f1b23e26649560c4760f29c61fd6515..4b9cfc8543623fb6f3716106dc7c0eb84e1782af 100644 --- a/goofy-client/apps/goofy/src/app/app.component.spec.ts +++ b/goofy-client/apps/goofy/src/app/app.component.spec.ts @@ -6,12 +6,16 @@ import { RouterTestingModule } from '@angular/router/testing'; import { ApiRootResource, ApiRootService } from '@goofy-client/api-root-shared'; import { AppService } from '@goofy-client/app-shared'; import { ENVIRONMENT_CONFIG } from '@goofy-client/environment-shared'; -import { NavigationModule } from '@goofy-client/navigation'; -import { createEmptyStateResource, createStateResource, NavigationService, StateResource } from '@goofy-client/tech-shared'; +import { createEmptyStateResource, createStateResource, StateResource } from '@goofy-client/tech-shared'; import { mock } from '@goofy-client/test-utils'; -import { UiModule } from '@goofy-client/ui'; +import { SpinnerComponent } from '@goofy-client/ui'; import { OAuthService } from 'angular-oauth2-oidc'; import { createApiRootResource } from 'libs/api-root-shared/test/api-root'; +import { BuildInfoComponent } from 'libs/navigation/src/lib/build-info/build-info.component'; +import { HeaderContainerComponent } from 'libs/navigation/src/lib/header-container/header-container.component'; +import { NavigationContainerComponent } from 'libs/navigation/src/lib/navigation-container/navigation-container.component'; +import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; +import { MockComponent } from 'ng-mocks'; import { BehaviorSubject, of } from 'rxjs'; import { AppComponent } from './app.component'; @@ -22,25 +26,28 @@ describe('AppComponent', () => { let fixture: ComponentFixture<AppComponent>; const apiRootSubj: BehaviorSubject<StateResource<ApiRootResource>> = new BehaviorSubject(null); - const darkModeSubj: BehaviorSubject<boolean> = new BehaviorSubject(false); const apiRootService = { ...mock(ApiRootService), getApiRoot: () => apiRootSubj }; - const appService = { ...mock(AppService), getDarkMode: () => darkModeSubj }; - const navigationService = { ...mock(NavigationService), init: () => { }, urlChanged: () => of({}) }; + const appService = { ...mock(AppService), getDarkMode: () => of(false) }; const authService = { ...mock(OAuthService), loadDiscoveryDocumentAndLogin: () => new Promise((resolve, reject) => resolve(null)) }; const envConfig = { authServer: 'http://' }; const httpClient = mock(HttpClient); - const buildInfo: string = 'goofy-client-build-info'; + const buildInfo: string = getDataTestIdOf('build-info'); + const title: string = 'goofy'; beforeEach(async () => { await TestBed.configureTestingModule({ imports: [ - UiModule, - NavigationModule, RouterTestingModule ], - declarations: [AppComponent], + declarations: [ + AppComponent, + MockComponent(NavigationContainerComponent), + MockComponent(HeaderContainerComponent), + MockComponent(SpinnerComponent), + MockComponent(BuildInfoComponent) + ], providers: [ { provide: ApiRootService, @@ -51,9 +58,6 @@ describe('AppComponent', () => { useValue: appService }, { - provide: NavigationService, - useValue: navigationService - }, { provide: OAuthService, useValue: authService }, @@ -79,8 +83,8 @@ describe('AppComponent', () => { expect(component).toBeTruthy(); }); - it(`should have as title 'goofy'`, () => { - expect(component.title).toEqual('goofy'); + it(`should have ${title} as title`, () => { + expect(component.title).toEqual(title); }); describe('buildInfo', () => { diff --git a/goofy-client/libs/navigation/src/lib/navigation-container/navigation-container.component.html b/goofy-client/libs/navigation/src/lib/navigation-container/navigation-container.component.html new file mode 100644 index 0000000000000000000000000000000000000000..ad041fe3ca7454740c0859b6640be4e65cf453b3 --- /dev/null +++ b/goofy-client/libs/navigation/src/lib/navigation-container/navigation-container.component.html @@ -0,0 +1,4 @@ +<goofy-client-navigation + [apiRootStateResource]="apiRootStateResource$ | async" [navigationCollapse]="navigationCollapse$ | async" [selectedNavigationItem]="selectedNavigationItem$ | async" + (selectItem)="selectItem($event)"> +</goofy-client-navigation> \ No newline at end of file diff --git a/goofy-client/libs/navigation/src/lib/navigation-container/navigation-container.component.scss b/goofy-client/libs/navigation/src/lib/navigation-container/navigation-container.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/goofy-client/libs/navigation/src/lib/navigation-container/navigation-container.component.spec.ts b/goofy-client/libs/navigation/src/lib/navigation-container/navigation-container.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..4c48db6ca0da298a81d56f2c11d5cad4132fff28 --- /dev/null +++ b/goofy-client/libs/navigation/src/lib/navigation-container/navigation-container.component.spec.ts @@ -0,0 +1,81 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ApiRootService } from '@goofy-client/api-root-shared'; +import { AppService } from '@goofy-client/app-shared'; +import { NavigationItem, NavigationService } from '@goofy-client/tech-shared'; +import { mock } from '@goofy-client/test-utils'; +import { MockComponent } from 'ng-mocks'; +import { NavigationComponent } from '../navigation/navigation.component'; +import { NavigationContainerComponent } from './navigation-container.component'; + +describe('NavigationContainerComponent', () => { + let component: NavigationContainerComponent; + let fixture: ComponentFixture<NavigationContainerComponent>; + + const appService = mock(AppService); + const apiRootService = mock(ApiRootService); + const navigationService = mock(NavigationService); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [NavigationContainerComponent, + MockComponent(NavigationComponent),], + providers: [ + { + provide: AppService, + useValue: appService + }, + { + provide: ApiRootService, + useValue: apiRootService + }, + { + provide: NavigationService, + useValue: navigationService + } + ], + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(NavigationContainerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('ngOnInit', () => { + + it('should call navigation service', () => { + component.ngOnInit(); + + expect(navigationService.getSelectedItem).toHaveBeenCalled(); + }); + + it('should call app service', () => { + component.ngOnInit(); + + expect(appService.getNavigationCollapse).toHaveBeenCalled(); + }); + + it('should call api root service', () => { + component.ngOnInit(); + + expect(apiRootService.getApiRoot).toHaveBeenCalled(); + }); + }) + + describe('select item', () => { + + const itemToSelect: NavigationItem = NavigationItem.ALL_VORGAENGE; + + it('should call navigation service', () => { + component.selectItem(itemToSelect); + + expect(navigationService.setSelectedItem).toHaveBeenCalledWith(itemToSelect); + }) + }) +}); diff --git a/goofy-client/libs/navigation/src/lib/navigation-container/navigation-container.component.ts b/goofy-client/libs/navigation/src/lib/navigation-container/navigation-container.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..97ac4132d68842b3697fa2433c1f8b0a0963fe65 --- /dev/null +++ b/goofy-client/libs/navigation/src/lib/navigation-container/navigation-container.component.ts @@ -0,0 +1,29 @@ +import { Component, OnInit } from '@angular/core'; +import { ApiRootResource, ApiRootService } from '@goofy-client/api-root-shared'; +import { AppService } from '@goofy-client/app-shared'; +import { NavigationItem, NavigationService, StateResource } from '@goofy-client/tech-shared'; +import { Observable } from 'rxjs'; + +@Component({ + selector: 'goofy-client-navigation-container', + templateUrl: './navigation-container.component.html', + styleUrls: ['./navigation-container.component.scss'] +}) +export class NavigationContainerComponent implements OnInit { + + navigationCollapse$: Observable<boolean>; + apiRootStateResource$: Observable<StateResource<ApiRootResource>>; + selectedNavigationItem$: Observable<NavigationItem>; + + constructor(private appService: AppService, private apiRootService: ApiRootService, private navigationService: NavigationService) { } + + ngOnInit(): void { + this.navigationCollapse$ = this.appService.getNavigationCollapse(); + this.apiRootStateResource$ = this.apiRootService.getApiRoot(); + this.selectedNavigationItem$ = this.navigationService.getSelectedItem(); + } + + selectItem(item: NavigationItem): void { + this.navigationService.setSelectedItem(item); + } +} \ No newline at end of file diff --git a/goofy-client/libs/navigation/src/lib/navigation.module.ts b/goofy-client/libs/navigation/src/lib/navigation.module.ts index 7e25ca7e5083dda422b73f0dfb6e0780fc046c82..c714a5ee8b5087bf1ca59be99a754f8268961a42 100644 --- a/goofy-client/libs/navigation/src/lib/navigation.module.ts +++ b/goofy-client/libs/navigation/src/lib/navigation.module.ts @@ -8,6 +8,7 @@ import { BuildInfoComponent } from './build-info/build-info.component'; import { HeaderContainerComponent } from './header-container/header-container.component'; import { HeaderComponent } from './header-container/header/header.component'; import { SettingsComponent } from './header-container/header/settings/settings.component'; +import { NavigationContainerComponent } from './navigation-container/navigation-container.component'; import { AllVorgaengeNavigationItemComponent } from './navigation/all-vorgaenge-navigation-item/all-vorgaenge-navigation-item.component'; import { MyVorgaengeNavigationItemComponent } from './navigation/my-vorgaenge-navigation-item/my-vorgaenge-navigation-item.component'; import { NavigationComponent } from './navigation/navigation.component'; @@ -20,7 +21,8 @@ import { NavigationComponent } from './navigation/navigation.component'; SettingsComponent, HeaderContainerComponent, AllVorgaengeNavigationItemComponent, - MyVorgaengeNavigationItemComponent + MyVorgaengeNavigationItemComponent, + NavigationContainerComponent ], imports: [ CommonModule, @@ -32,7 +34,7 @@ import { NavigationComponent } from './navigation/navigation.component'; exports: [ BuildInfoComponent, HeaderComponent, - NavigationComponent, + NavigationContainerComponent, SettingsComponent, HeaderContainerComponent ] diff --git a/goofy-client/libs/navigation/src/lib/navigation/navigation.component.html b/goofy-client/libs/navigation/src/lib/navigation/navigation.component.html index 793f5e7f9f873bcf7afd21acab6532fdda1989d0..9d15fa2fdd29163afcb5d54ebd9b4689b8f89ee1 100644 --- a/goofy-client/libs/navigation/src/lib/navigation/navigation.component.html +++ b/goofy-client/libs/navigation/src/lib/navigation/navigation.component.html @@ -1,20 +1,18 @@ -<ng-container *ngIf="apiRootStateResource$ | async as apiRootStateResource"> - <nav [ngClass]="{ small: navigationCollapse$ | async }" data-test-id="navigation"> + <nav [ngClass]="{ small: navigationCollapse }" data-test-id="navigation"> <ul> <li> <goofy-client-all-vorgaenge-navigation-item *ngIf="apiRootStateResource.resource | hasLink: apiRootLinkRel.VORGAENGE" data-test-id="all-vorgaenge-navigation-item" - [navigationCollapse]="navigationCollapse$ | async" - [selectedNavigationItem]="selectedNavigationItem$ | async" - (selectItem)="selectItem($event)"> + [navigationCollapse]="navigationCollapse" + [selectedNavigationItem]="selectedNavigationItem" + (selectItem)="selectItem.emit($event)"> </goofy-client-all-vorgaenge-navigation-item> </li> <li> <goofy-client-my-vorgaenge-navigation-item *ngIf="apiRootStateResource.resource | hasLink: apiRootLinkRel.MY_VORGAENGE" data-test-id="my-vorgaenge-navigation-item" - [navigationCollapse]="navigationCollapse$ | async" - [selectedNavigationItem]="selectedNavigationItem$ | async" - (selectItem)="selectItem($event)"> + [navigationCollapse]="navigationCollapse" + [selectedNavigationItem]="selectedNavigationItem" + (selectItem)="selectItem.emit($event)"> </goofy-client-my-vorgaenge-navigation-item> </li> </ul> - </nav> -</ng-container> \ No newline at end of file + </nav> \ No newline at end of file diff --git a/goofy-client/libs/navigation/src/lib/navigation/navigation.component.spec.ts b/goofy-client/libs/navigation/src/lib/navigation/navigation.component.spec.ts index 6f841f16fdc72e304401ae448f6037e2e61f26c5..c1e1f42709a15788011040a2a07945d97764d5f8 100644 --- a/goofy-client/libs/navigation/src/lib/navigation/navigation.component.spec.ts +++ b/goofy-client/libs/navigation/src/lib/navigation/navigation.component.spec.ts @@ -1,12 +1,10 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { ApiRootLinkRel, ApiRootService } from '@goofy-client/api-root-shared'; -import { AppService } from '@goofy-client/app-shared'; -import { createStateResource, HasLinkPipe, NavigationItem, NavigationService } from '@goofy-client/tech-shared'; -import { getElementFromFixture, mock } from '@goofy-client/test-utils'; +import { ApiRootLinkRel } from '@goofy-client/api-root-shared'; +import { createStateResource, HasLinkPipe } from '@goofy-client/tech-shared'; +import { getElementFromFixture } from '@goofy-client/test-utils'; import { createApiRootResource } from 'libs/api-root-shared/test/api-root'; import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; import { MockComponent } from 'ng-mocks'; -import { of } from 'rxjs'; import { AllVorgaengeNavigationItemComponent } from './all-vorgaenge-navigation-item/all-vorgaenge-navigation-item.component'; import { MyVorgaengeNavigationItemComponent } from './my-vorgaenge-navigation-item/my-vorgaenge-navigation-item.component'; import { NavigationComponent } from './navigation.component'; @@ -15,29 +13,11 @@ describe('NavigationComponent', () => { let component: NavigationComponent; let fixture: ComponentFixture<NavigationComponent>; - const appService = mock(AppService); - const apiRootService = mock(ApiRootService); - const navigationService = mock(NavigationService); - const allVorgaenge: string = getDataTestIdOf('all-vorgaenge-navigation-item'); const myVorgaenge: string = getDataTestIdOf('my-vorgaenge-navigation-item'); beforeEach(async () => { await TestBed.configureTestingModule({ - providers: [ - { - provide: AppService, - useValue: appService - }, - { - provide: ApiRootService, - useValue: apiRootService - }, - { - provide: NavigationService, - useValue: navigationService - } - ], declarations: [ NavigationComponent, HasLinkPipe, @@ -57,31 +37,10 @@ describe('NavigationComponent', () => { expect(component).toBeTruthy(); }); - describe('on constructor', () => { - - it('should call navigation service', () => { - fixture.detectChanges(); - - expect(navigationService.getSelectedItem).toHaveBeenCalled(); - }); - - it('should call app service', () => { - fixture.detectChanges(); - - expect(appService.getNavigationCollapse).toHaveBeenCalled(); - }); - - it('should call api root service', () => { - fixture.detectChanges(); - - expect(apiRootService.getApiRoot).toHaveBeenCalled(); - }); - }) - describe('all vorgaenge item', () => { it('should show on existing link', () => { - component.apiRootStateResource$ = of(createStateResource(createApiRootResource([ApiRootLinkRel.VORGAENGE]))); + component.apiRootStateResource = createStateResource(createApiRootResource([ApiRootLinkRel.VORGAENGE])); fixture.detectChanges(); const element = getElementFromFixture(fixture, allVorgaenge); @@ -90,7 +49,7 @@ describe('NavigationComponent', () => { }) it('should hide on missing link', () => { - component.apiRootStateResource$ = of(createStateResource(createApiRootResource())); + component.apiRootStateResource = createStateResource(createApiRootResource()); fixture.detectChanges(); const element = getElementFromFixture(fixture, allVorgaenge); @@ -102,7 +61,7 @@ describe('NavigationComponent', () => { describe('my vorgaenge item', () => { it('should show on existing link', () => { - component.apiRootStateResource$ = of(createStateResource(createApiRootResource([ApiRootLinkRel.MY_VORGAENGE]))); + component.apiRootStateResource = createStateResource(createApiRootResource([ApiRootLinkRel.MY_VORGAENGE])); fixture.detectChanges(); const element = getElementFromFixture(fixture, myVorgaenge); @@ -111,7 +70,7 @@ describe('NavigationComponent', () => { }) it('should hide on missing link', () => { - component.apiRootStateResource$ = of(createStateResource(createApiRootResource())); + component.apiRootStateResource = createStateResource(createApiRootResource()); fixture.detectChanges(); const element = getElementFromFixture(fixture, myVorgaenge); @@ -119,15 +78,4 @@ describe('NavigationComponent', () => { expect(element).not.toBeInstanceOf(HTMLElement); }) }) - - describe('select item', () => { - - const itemToSelect: NavigationItem = NavigationItem.ALL_VORGAENGE; - - it('should call navigation service', () => { - component.selectItem(itemToSelect); - - expect(navigationService.setSelectedItem).toHaveBeenCalledWith(itemToSelect); - }) - }) }); diff --git a/goofy-client/libs/navigation/src/lib/navigation/navigation.component.ts b/goofy-client/libs/navigation/src/lib/navigation/navigation.component.ts index f756c884a1bf5adc63e70428c1a3cb2858f3f84c..8b9ab5fce1404cc54d5d92526f8f4031381fa1a1 100644 --- a/goofy-client/libs/navigation/src/lib/navigation/navigation.component.ts +++ b/goofy-client/libs/navigation/src/lib/navigation/navigation.component.ts @@ -1,10 +1,8 @@ -import { Component } from '@angular/core'; -import { ApiRootLinkRel, ApiRootResource, ApiRootService } from '@goofy-client/api-root-shared'; -import { AppService } from '@goofy-client/app-shared'; -import { NavigationItem, NavigationService, StateResource } from '@goofy-client/tech-shared'; -import { Observable } from 'rxjs'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { ApiRootLinkRel, ApiRootResource } from '@goofy-client/api-root-shared'; +import { NavigationItem, StateResource } from '@goofy-client/tech-shared'; -//TODO Componente an die Containerstruktur anpassen +//TODO: Componente nach navigation-container verschieben @Component({ selector: 'goofy-client-navigation', templateUrl: './navigation.component.html', @@ -12,19 +10,11 @@ import { Observable } from 'rxjs'; }) export class NavigationComponent { - navigationCollapse$: Observable<boolean>; - apiRootStateResource$: Observable<StateResource<ApiRootResource>>; - selectedNavigationItem$: Observable<NavigationItem>; + @Input() navigationCollapse: boolean; + @Input() apiRootStateResource: StateResource<ApiRootResource>; + @Input() selectedNavigationItem: NavigationItem; - readonly apiRootLinkRel = ApiRootLinkRel; - - constructor(private appService: AppService, private apiRootService: ApiRootService, private navigationService: NavigationService) { - this.navigationCollapse$ = this.appService.getNavigationCollapse(); - this.apiRootStateResource$ = this.apiRootService.getApiRoot(); - this.selectedNavigationItem$ = this.navigationService.getSelectedItem(); - } + @Output() selectItem: EventEmitter<NavigationItem> = new EventEmitter<NavigationItem>(); - selectItem(item: NavigationItem): void { - this.navigationService.setSelectedItem(item); - } + readonly apiRootLinkRel = ApiRootLinkRel; } \ No newline at end of file