diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.html b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.html index f1ac25eb71af847bdcb522fe3f231474f1341c78..dc08624feba50617540824639b130daa51881517 100644 --- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.html +++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.html @@ -30,6 +30,7 @@ class="search-field" data-test-id="search-form" > + <span aria-live="polite" class="sr-only" role="status">{{ searchResultPreviewLabel }}</span> <button #searchSubmitButton type="submit" @@ -61,14 +62,14 @@ (optionSelected)="formService.submitByPreviewList($event.option.value, searchString)" > <ozgcloud-spinner - [stateResource]="vorgangSearchPreviewList" - [class.autocomplete-spinner]="vorgangSearchPreviewList.loading" + [stateResource]="vorgangListPreview" + [class.autocomplete-spinner]="vorgangListPreview.loading" ></ozgcloud-spinner> - <ng-container *ngIf="vorgangSearchPreviewList.resource" data-test-id="search-preview-list"> + <ng-container *ngIf="vorgangListPreview.resource" data-test-id="search-preview-list"> <mat-option *ngFor=" - let vorgang of vorgangSearchPreviewList.resource + let vorgang of vorgangListPreview.resource | toEmbeddedResources: vorgangListLinkRel.VORGANG_HEADER_LIST " [value]="vorgang" diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.spec.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.spec.ts index 9fe1622edc1c551c7bff4d9ed5cb9ed910bceb40..ca73c782d282523f6ae32f0ef50fa9ec872d217f 100644 --- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.spec.ts +++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.spec.ts @@ -54,7 +54,11 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { NavigationEnd, Router, RouterEvent } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { getDataTestClassOf, getDataTestIdOf } from 'libs/tech-shared/test/data-test'; -import { createVorgangListResource } from 'libs/vorgang-shared/test/vorgang'; +import { + createVorgangListResource, + createVorgangListResourceWithResource, + createVorgangResource, +} from 'libs/vorgang-shared/test/vorgang'; import { MockComponent } from 'ng-mocks'; import { BehaviorSubject, ReplaySubject, Subject, of } from 'rxjs'; import { VorgangSearchAutocompleteOptionsContentComponent } from './vorgang-search-autocomplete-options-content/vorgang-search-autocomplete-options-content.component'; @@ -186,6 +190,66 @@ describe('VorgangSearchComponent', () => { }); }); + describe('set vorgangSearchPreviewList', () => { + it('should set vorgangPreview', () => { + const vorgangList = createStateResource(createVorgangListResource()); + + component.vorgangSearchPreviewList = vorgangList; + + expect(component.vorgangListPreview).toEqual(vorgangList); + }); + + it('should call buildSearchResultPreviewLabel', () => { + component.buildSearchResultPreviewLabel = jest.fn(); + const vorgangList = createStateResource(createVorgangListResource()); + + component.vorgangSearchPreviewList = vorgangList; + + expect(component.buildSearchResultPreviewLabel).toBeCalledWith(vorgangList); + }); + + it('should set previewLabel', () => { + component.buildSearchResultPreviewLabel = jest.fn(() => 'test'); + const vorgangList = createStateResource(createVorgangListResource()); + + component.vorgangSearchPreviewList = vorgangList; + + expect(component.searchResultPreviewLabel).toBe('test'); + }); + }); + + describe('buildSearchResultPreviewLabel', () => { + it('should return label for many search results', () => { + const vorgangList = createStateResource(createVorgangListResource()); + + const result = component.buildSearchResultPreviewLabel(vorgangList); + + expect(result).toBe( + '10 Vorschläge werden angezeigt, nutze Pfeiltaste nach unten, um diese zu erreichen', + ); + }); + + it('should return label for one search result', () => { + const vorgangList = createStateResource( + createVorgangListResourceWithResource([createVorgangResource()]), + ); + + const result = component.buildSearchResultPreviewLabel(vorgangList); + + expect(result).toBe( + 'Ein Vorschlag wird angezeigt, nutze Pfeiltaste nach unten, um den zu erreichen', + ); + }); + + it('should return empty string', () => { + const vorgangList = createStateResource(null); + + const result = component.buildSearchResultPreviewLabel(vorgangList); + + expect(result).toBe(EMPTY_STRING); + }); + }); + describe('search clear button', () => { beforeEach(() => { searchStringSubj.next('test'); diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.ts index 5375e849b6359a8ba54dd883b83ed8da5daae844..7857c502c95a7b38bed14c9a85ef50d8a748a68a 100644 --- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.ts +++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.ts @@ -21,7 +21,12 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { StateResource, isNotNil } from '@alfa-client/tech-shared'; +import { + EMPTY_STRING, + StateResource, + getEmbeddedResources, + isNotNil, +} from '@alfa-client/tech-shared'; import { VorgangHeaderLinkRel, VorgangListLinkRel, @@ -51,7 +56,12 @@ import { VorgangSearchFormService } from './vorgang-search.formservice'; providers: [VorgangSearchFormService], }) export class VorgangSearchComponent implements OnInit, OnDestroy { - @Input() vorgangSearchPreviewList: StateResource<VorgangListResource>; + @Input() set vorgangSearchPreviewList( + vorgangListStateResource: StateResource<VorgangListResource>, + ) { + this.vorgangListPreview = vorgangListStateResource; + this.searchResultPreviewLabel = this.buildSearchResultPreviewLabel(vorgangListStateResource); + } @Input() searchString: string; @Output() public clearVorgangSearchPreviewList: EventEmitter<void> = new EventEmitter<void>(); @@ -60,6 +70,8 @@ export class VorgangSearchComponent implements OnInit, OnDestroy { @ViewChild('searchSubmitButton') searchSubmitButton: MatButton; @ViewChild('searchAutoComplete') searchAutoComplete: MatAutocomplete; + vorgangListPreview: StateResource<VorgangListResource>; + searchResultPreviewLabel: string = ''; previouslyEnteredSearchValue: string; private subscription: Subscription; @@ -101,6 +113,20 @@ export class VorgangSearchComponent implements OnInit, OnDestroy { } } + buildSearchResultPreviewLabel( + vorgangListStateResource: StateResource<VorgangListResource>, + ): string { + const previewListLength = getEmbeddedResources( + vorgangListStateResource, + this.vorgangListLinkRel.VORGANG_HEADER_LIST, + )?.length; + if (previewListLength === 1) + return 'Ein Vorschlag wird angezeigt, nutze Pfeiltaste nach unten, um den zu erreichen'; + if (previewListLength > 1) + return `${previewListLength} Vorschläge werden angezeigt, nutze Pfeiltaste nach unten, um diese zu erreichen`; + return EMPTY_STRING; + } + private isRelatedTargetSearchButton(event: FocusEvent): boolean { return event.relatedTarget === this.searchSubmitButton._elementRef.nativeElement; }