From 6f730e42dd49751388734b71d3786e548ef5475b Mon Sep 17 00:00:00 2001 From: sebo <sebastian.bergandy@external.mgm-cp.com> Date: Tue, 11 Mar 2025 15:05:34 +0100 Subject: [PATCH] OZG-7473 add list component Sub task: OZG-7883 --- ...gregation-mapping-list-item.component.html | 10 ++ ...gation-mapping-list-item.component.spec.ts | 21 +++ ...aggregation-mapping-list-item.component.ts | 14 ++ .../aggregation-mapping-list.component.html | 7 + ...aggregation-mapping-list.component.spec.ts | 120 ++++++++++++++++++ .../aggregation-mapping-list.component.ts | 31 +++++ .../statistik-container.component.html | 2 +- .../statistik-container.component.spec.ts | 32 ++++- .../statistik-container.component.ts | 3 +- alfa-client/libs/test-utils/src/lib/helper.ts | 4 +- .../libs/test-utils/src/lib/jest.helper.ts | 11 +- 11 files changed, 247 insertions(+), 8 deletions(-) create mode 100644 alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list-item/aggregation-mapping-list-item.component.html create mode 100644 alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list-item/aggregation-mapping-list-item.component.spec.ts create mode 100644 alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list-item/aggregation-mapping-list-item.component.ts create mode 100644 alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list.component.html create mode 100644 alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list.component.spec.ts create mode 100644 alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list.component.ts diff --git a/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list-item/aggregation-mapping-list-item.component.html b/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list-item/aggregation-mapping-list-item.component.html new file mode 100644 index 0000000000..8bf3593a46 --- /dev/null +++ b/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list-item/aggregation-mapping-list-item.component.html @@ -0,0 +1,10 @@ +<ods-list-item [path]="" [attr.data-test-id]="(aggregationMapping.name | convertForDataTest)"> + <div class="flex-1 basis-1/2"> + <div class="mb-2 flex flex-wrap items-center gap-3"> + <h3 class="text-md font-semibold" data-test-class="fullname">{{ aggregationMapping.name }}</h3> + </div> + <!-- Remove null safe check operator after backend provides correct data. --> + <div>{{aggregationMapping.formIdentifier?.formEngineName}}</div> + <div>{{aggregationMapping.formIdentifier?.formId}}</div> + </div> +</ods-list-item> diff --git a/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list-item/aggregation-mapping-list-item.component.spec.ts b/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list-item/aggregation-mapping-list-item.component.spec.ts new file mode 100644 index 0000000000..7e48ac908d --- /dev/null +++ b/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list-item/aggregation-mapping-list-item.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { AggregationMappingListItemComponent } from './aggregation-mapping-list-item.component'; + +describe('AggregationMappingListItemComponent', () => { + let component: AggregationMappingListItemComponent; + let fixture: ComponentFixture<AggregationMappingListItemComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [AggregationMappingListItemComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(AggregationMappingListItemComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list-item/aggregation-mapping-list-item.component.ts b/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list-item/aggregation-mapping-list-item.component.ts new file mode 100644 index 0000000000..ca31dbc05b --- /dev/null +++ b/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list-item/aggregation-mapping-list-item.component.ts @@ -0,0 +1,14 @@ +import { AggregationMappingResource } from '@admin-client/reporting-shared'; +import { ConvertForDataTestPipe } from '@alfa-client/tech-shared'; +import { Component, Input } from '@angular/core'; +import { ListItemComponent } from '@ods/system'; + +@Component({ + selector: 'admin-aggregation-mapping-list-item', + standalone: true, + templateUrl: './aggregation-mapping-list-item.component.html', + imports: [ConvertForDataTestPipe, ListItemComponent], +}) +export class AggregationMappingListItemComponent { + @Input({ required: true }) aggregationMapping: AggregationMappingResource; +} diff --git a/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list.component.html b/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list.component.html new file mode 100644 index 0000000000..2746dbebda --- /dev/null +++ b/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list.component.html @@ -0,0 +1,7 @@ +<ods-spinner [stateResource]="listStateResource"> + <ods-list data-test-id="aggregation-mapping-list"> + @for (aggregationMapping of aggregationMappings; track $index) { + <admin-aggregation-mapping-list-item [aggregationMapping]="aggregationMapping" /> + } + </ods-list> +</ods-spinner> \ No newline at end of file diff --git a/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list.component.spec.ts b/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list.component.spec.ts new file mode 100644 index 0000000000..dd1647f73a --- /dev/null +++ b/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list.component.spec.ts @@ -0,0 +1,120 @@ +import { AggregationMappingListResource } from '@admin-client/reporting-shared'; +import { + createEmptyStateResource, + createLoadingStateResource, + createStateResource, + getEmbeddedResources, + StateResource, +} from '@alfa-client/tech-shared'; +import { expectComponentExistsInTemplate, getElementFromFixtureByType } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { expect } from '@jest/globals'; +import { SpinnerComponent } from '@ods/component'; +import { ListComponent } from '@ods/system'; +import { MockComponent } from 'ng-mocks'; +import { AggregationMappingListLinkRel } from '../../../../reporting-shared/src/lib/aggregation-mapping.linkrel'; +import { createAggregationMappingListResource } from '../../../../reporting-shared/test/aggregation-mapping'; +import { AggregationMappingListItemComponent } from './aggregation-mapping-list-item/aggregation-mapping-list-item.component'; +import { AggregationMappingListComponent } from './aggregation-mapping-list.component'; + +describe('AggregationMappingListComponent', () => { + let component: AggregationMappingListComponent; + let fixture: ComponentFixture<AggregationMappingListComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + AggregationMappingListComponent, + MockComponent(SpinnerComponent), + MockComponent(ListComponent), + MockComponent(AggregationMappingListItemComponent), + ], + }).compileComponents(); + + fixture = TestBed.createComponent(AggregationMappingListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('component', () => { + const aggregationMappingListStateResource: StateResource<AggregationMappingListResource> = createStateResource( + createAggregationMappingListResource(), + ); + + it('should have initial state', () => { + expect(component.listStateResource).toEqual(createEmptyStateResource()); + expect(component.aggregationMappings).toEqual([]); + }); + + describe('_update', () => { + it('should set list state resource', () => { + component.aggregationMappingListStateResource = aggregationMappingListStateResource; + + expect(component.listStateResource).toEqual(aggregationMappingListStateResource); + }); + + it('should set aggregation mappings if loaded and not nil', () => { + component.aggregationMappingListStateResource = aggregationMappingListStateResource; + + expect(component.aggregationMappings).toEqual( + getEmbeddedResources(aggregationMappingListStateResource, AggregationMappingListLinkRel.LIST), + ); + }); + + it('should NOT set aggregation mappings if nil', () => { + component.aggregationMappingListStateResource = null; + + expect(component.aggregationMappings).toEqual([]); + }); + + it('should NOT set aggregation mappings if loading', () => { + component.aggregationMappingListStateResource = createLoadingStateResource(); + + expect(component.aggregationMappings).toEqual([]); + }); + }); + + describe('set aggregation mapping list state resource', () => { + it('should update component state', () => { + component._update = jest.fn(); + + component.aggregationMappingListStateResource = aggregationMappingListStateResource; + + expect(component._update).toHaveBeenCalledWith(aggregationMappingListStateResource); + }); + }); + }); + + describe('template', () => { + const aggregationMappingListStateResource: StateResource<AggregationMappingListResource> = createStateResource( + createAggregationMappingListResource(), + ); + + beforeEach(() => { + component.aggregationMappingListStateResource = aggregationMappingListStateResource; + fixture.detectChanges(); + }); + + it('should have spinner with state resource', () => { + expectComponentExistsInTemplate(fixture, SpinnerComponent); + const comp = getElementFromFixtureByType(fixture, SpinnerComponent); + expect(comp.stateResource).toEqual(aggregationMappingListStateResource); + }); + + it('should have list', () => { + expectComponentExistsInTemplate(fixture, ListComponent); + }); + + it('should have list item with mapping', () => { + expectComponentExistsInTemplate(fixture, AggregationMappingListItemComponent); + const comp = getElementFromFixtureByType(fixture, AggregationMappingListItemComponent); + expect(comp.aggregationMapping).toEqual( + getEmbeddedResources(aggregationMappingListStateResource, AggregationMappingListLinkRel.LIST)[0], + ); + }); + }); +}); diff --git a/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list.component.ts b/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list.component.ts new file mode 100644 index 0000000000..c427bc7903 --- /dev/null +++ b/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list.component.ts @@ -0,0 +1,31 @@ +import { AggregationMappingListResource, AggregationMappingResource } from '@admin-client/reporting-shared'; +import { createEmptyStateResource, getEmbeddedResources, isLoaded, isNotNil, StateResource } from '@alfa-client/tech-shared'; +import { Component, Input } from '@angular/core'; +import { SpinnerComponent } from '@ods/component'; +import { ListComponent } from '@ods/system'; +import { AggregationMappingListLinkRel } from '../../../../reporting-shared/src/lib/aggregation-mapping.linkrel'; +import { AggregationMappingListItemComponent } from './aggregation-mapping-list-item/aggregation-mapping-list-item.component'; + +@Component({ + selector: 'admin-aggregation-mapping-list', + standalone: true, + templateUrl: './aggregation-mapping-list.component.html', + imports: [SpinnerComponent, ListComponent, AggregationMappingListItemComponent], +}) +export class AggregationMappingListComponent { + @Input({ required: true }) set aggregationMappingListStateResource( + stateResource: StateResource<AggregationMappingListResource>, + ) { + this._update(stateResource); + } + + public listStateResource: StateResource<AggregationMappingListResource> = createEmptyStateResource(); + public aggregationMappings: AggregationMappingResource[] = []; + + _update(stateResource: StateResource<AggregationMappingListResource>): void { + this.listStateResource = stateResource; + if (isNotNil(stateResource) && isLoaded(stateResource)) { + this.aggregationMappings = getEmbeddedResources(stateResource, AggregationMappingListLinkRel.LIST); + } + } +} diff --git a/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.html b/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.html index 1fd0441a39..f7cb1c606f 100644 --- a/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.html +++ b/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.html @@ -32,4 +32,4 @@ ></ods-routing-button> </div> -<ng-container *ngIf="listStateResource$ | async"></ng-container> +<admin-aggregation-mapping-list [aggregationMappingListStateResource]="listStateResource$ | async"></admin-aggregation-mapping-list> diff --git a/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.spec.ts b/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.spec.ts index 3abca44e4a..014109b6a8 100644 --- a/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.spec.ts +++ b/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.spec.ts @@ -23,12 +23,15 @@ */ import { AggregationMappingListResource, AggregationMappingService } from '@admin-client/reporting-shared'; import { createStateResource, StateResource } from '@alfa-client/tech-shared'; -import { mock, Mock } from '@alfa-client/test-utils'; +import { expectComponentExistsInTemplate, getElementFromFixtureByType, mock, Mock } from '@alfa-client/test-utils'; import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { expect } from '@jest/globals'; import { RoutingButtonComponent } from '@ods/component'; import { singleCold } from 'libs/tech-shared/test/marbles'; import { MockComponent } from 'ng-mocks'; +import { of } from 'rxjs'; import { createAggregationMappingListResource } from '../../../../reporting-shared/test/aggregation-mapping'; +import { AggregationMappingListComponent } from '../aggregation-mapping-list/aggregation-mapping-list.component'; import { StatistikContainerComponent } from './statistik-container.component'; describe('StatistikContainerComponent', () => { @@ -41,8 +44,11 @@ describe('StatistikContainerComponent', () => { aggregationMappingService = mock(AggregationMappingService); await TestBed.configureTestingModule({ - imports: [StatistikContainerComponent], - declarations: [MockComponent(RoutingButtonComponent)], + imports: [ + StatistikContainerComponent, + MockComponent(RoutingButtonComponent), + MockComponent(AggregationMappingListComponent), + ], }) .overrideComponent(StatistikContainerComponent, { set: { @@ -86,4 +92,24 @@ describe('StatistikContainerComponent', () => { expect(component.listStateResource$).toBeObservable(singleCold(stateResource)); }); }); + + describe('template', () => { + describe('aggregation mapping list', () => { + it('should exists', () => { + expectComponentExistsInTemplate(fixture, AggregationMappingListComponent); + }); + + it('should have inputs', () => { + const stateResource: StateResource<AggregationMappingListResource> = createStateResource( + createAggregationMappingListResource(), + ); + component.listStateResource$ = of(stateResource); + fixture.detectChanges(); + + const comp = getElementFromFixtureByType(fixture, AggregationMappingListComponent); + + expect(comp.aggregationMappingListStateResource).toEqual(stateResource); + }); + }); + }); }); diff --git a/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.ts b/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.ts index 90c3515896..70db01b592 100644 --- a/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.ts +++ b/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.ts @@ -28,12 +28,13 @@ import { CommonModule } from '@angular/common'; import { Component, inject, OnInit } from '@angular/core'; import { RoutingButtonComponent } from '@ods/component'; import { Observable } from 'rxjs'; +import { AggregationMappingListComponent } from '../aggregation-mapping-list/aggregation-mapping-list.component'; @Component({ selector: 'admin-statistik-container', templateUrl: './statistik-container.component.html', standalone: true, - imports: [CommonModule, RoutingButtonComponent], + imports: [CommonModule, RoutingButtonComponent, AggregationMappingListComponent], providers: [AggregationMappingService], }) export class StatistikContainerComponent implements OnInit { diff --git a/alfa-client/libs/test-utils/src/lib/helper.ts b/alfa-client/libs/test-utils/src/lib/helper.ts index 66f33c3579..df9518764f 100644 --- a/alfa-client/libs/test-utils/src/lib/helper.ts +++ b/alfa-client/libs/test-utils/src/lib/helper.ts @@ -26,8 +26,8 @@ import { ComponentFixture } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { EventData } from './model'; -export function getElementFromFixtureByType<T>(fixture: ComponentFixture<any>, component: Type<T>): T { - return getDebugElementFromFixtureByType(fixture, component).componentInstance as T; +export function getElementFromFixtureByType<T>(fixture: ComponentFixture<any>, component: Type<T>): T | null { + return getDebugElementFromFixtureByType(fixture, component)?.componentInstance as T; } function getDebugElementFromFixtureByType<T>(fixture: ComponentFixture<any>, component: Type<T>): DebugElement { diff --git a/alfa-client/libs/test-utils/src/lib/jest.helper.ts b/alfa-client/libs/test-utils/src/lib/jest.helper.ts index 60df8592af..1b0f86ec5b 100644 --- a/alfa-client/libs/test-utils/src/lib/jest.helper.ts +++ b/alfa-client/libs/test-utils/src/lib/jest.helper.ts @@ -21,10 +21,11 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { Type } from '@angular/core'; import { ComponentFixture } from '@angular/core/testing'; import { expect } from '@jest/globals'; import { TooltipDirective } from '@ods/system'; -import { getDebugElementFromFixtureByCss, getElementFromFixture } from './helper'; +import { getDebugElementFromFixtureByCss, getElementFromFixture, getElementFromFixtureByType } from './helper'; export function notExistsAsHtmlElement(fixture: ComponentFixture<any>, domElement: string): void { expect(getElementFromFixture(fixture, domElement)).not.toBeInstanceOf(HTMLElement); @@ -34,6 +35,14 @@ export function existsAsHtmlElement(fixture: ComponentFixture<any>, domElement: expect(getElementFromFixture(fixture, domElement)).toBeInstanceOf(HTMLElement); } +export function expectComponentExistsInTemplate<T>(fixture: ComponentFixture<any>, component: Type<T>): void { + expect(getElementFromFixtureByType(fixture, component)).toBeInstanceOf(component); +} + +export function expectComponentMissingInTemplate<T>(fixture: ComponentFixture<any>, component: Type<T>): void { + expect(getElementFromFixtureByType(fixture, component)).toBeUndefined(); +} + export function tooltipExistsWithText(fixture: ComponentFixture<any>, domElement: string, tooltipText: string) { const tooltipInstance = getDebugElementFromFixtureByCss(fixture, domElement).injector.get(TooltipDirective); expect(tooltipInstance.componentRef.instance.text).toBe(tooltipText); -- GitLab