Skip to content
Snippets Groups Projects
Commit d0dfef58 authored by OZGCloud's avatar OZGCloud
Browse files

Merge pull request 'OZG-3114 Löschen Suchfeldeingabe beim Verlassen des...

Merge pull request 'OZG-3114 Löschen Suchfeldeingabe beim Verlassen des Feldes' (#167) from OZG-3114 into master

Reviewed-on: https://git.ozg-sh.de/mgm/goofy/pulls/167
parents c36a166d 78aeb54b
No related branches found
No related tags found
No related merge requests found
Showing
with 148 additions and 26 deletions
......@@ -25,7 +25,7 @@ import { convertToDataTestId } from "../../support/tech.util";
export class VorgangSearchE2EComponent {
//private readonly locatorButton: string = 'search-button';
private readonly locatorButton: string = 'search-button';
private readonly locatorInput: string = 'search-input';
private readonly locatorForm: string = 'search-form';
private readonly locatorSearchPreviewList: string = 'search-preview-list';
......@@ -41,10 +41,9 @@ export class VorgangSearchE2EComponent {
return cy.getTestElement(this.locatorInput);
}
//FIXME klaeren wie mit dem ausgebauten Button umgegangen werden soll
// public search(): void {
// cy.getTestElement(this.locatorButton).click();
// }
public getSearchButton() {
return cy.getTestElement(this.locatorButton);
}
public getForm() {
return cy.getTestElement(this.locatorForm);
......
......@@ -273,7 +273,7 @@ describe('VorgangList Suche', () => {
initVorgaenge([vorgangStayByVorgangName, vorgangStayByAktenzeichen, vorgangStayByAntragstellerVorname, vorgangStayByAntragstellerNachname, vorgangStayByRequestId])
initSearchIndex([vorgangStayByVorgangName, vorgangStayByAktenzeichen, vorgangStayByAntragstellerVorname, vorgangStayByAntragstellerNachname, vorgangStayByRequestId])
loginAsSabine();;
loginAsSabine();
waitForSpinnerToDisappear();
exist(vorgangList.getRoot());
......@@ -355,6 +355,17 @@ describe('VorgangList Suche', () => {
})
})
describe('leave search field', () => {
it('without submit should set previously entered text', () => {
doSearchWith('Gewerbe');
mainPage.getVorgangSearch().getInput().clear().type('Gewe');
mainPage.getHeader().getNavigationToggle().click();
haveValue(mainPage.getVorgangSearch().getInput(), 'Gewerbe');
})
})
function doSearchWith(searchBy: string): void {
mainPage.getVorgangSearch().getInput().clear().type(searchBy + CypressKeyboardActions.ENTER);
}
......
......@@ -28,6 +28,7 @@ export class HeaderE2EComponent {
private readonly locatorTitle: string = 'title';
private readonly locatorRoot: string = 'header';
private readonly locatorNavigationToggle: string = 'navigation-toggle';
private readonly userSettings: UserSettingsE2EComponent = new UserSettingsE2EComponent();
private readonly currentUserProfile: CurrentUserProfileE2EComponent = new CurrentUserProfileE2EComponent();
......@@ -47,4 +48,8 @@ export class HeaderE2EComponent {
public getCurrentUserProfile(): CurrentUserProfileE2EComponent {
return this.currentUserProfile;
}
public getNavigationToggle() {
return cy.getTestElement(this.locatorNavigationToggle);
}
}
\ No newline at end of file
......@@ -41,7 +41,6 @@ describe('KommentarFormComponent', () => {
let fixture: ComponentFixture<KommentarFormComponent>;
const formService = mock(KommentarFormService);
const service = mock(KommentarService);
const kommentarService = mock(KommentarService);
beforeEach(async () => {
......@@ -61,10 +60,6 @@ describe('KommentarFormComponent', () => {
provide: KommentarFormService,
useValue: formService
},
{
provide: KommentarService,
useValue: service
},
{
provide: KommentarService,
useValue: kommentarService
......
......@@ -26,6 +26,7 @@
<header data-test-id="header">
<div class="left">
<goofy-client-icon-button-with-spinner
data-test-id="navigation-toggle"
icon="menu" toolTip="Hauptmenü umschalten"
(clickEmitter)="toggleMenuEvent.emit(!this.navigationCollapse)">
</goofy-client-icon-button-with-spinner>
......
......@@ -23,8 +23,14 @@
unter der Lizenz sind dem Lizenztext zu entnehmen.
-->
<form (ngSubmit)="formService.submit()" [formGroup]="formService.form" [class.search-field--open]="searchAutoComplete.isOpen" class="search-field" data-test-id="search-form">
<button type="submit" data-test-id="search-button" mat-icon-button aria-label="Vorgang suchen">
<form (ngSubmit)="submit()" [formGroup]="formService.form"
[class.search-field--open]="searchAutoComplete.isOpen" class="search-field"
data-test-id="search-form">
<button
#searchSubmitButton
type="submit"
data-test-id="search-button"
mat-icon-button aria-label="Vorgang suchen">
<mat-icon matPrefix class="search-icon">search</mat-icon>
</button>
<mat-form-field floatLabel="never">
......@@ -36,7 +42,9 @@
maxlength="50"
[matAutocomplete]="searchAutoComplete"
[formControlName]="formService.SEARCH_FIELD"
name="searchString" />
name="searchString"
(focusout)="focusOut($event)"
(focusin)="focusIn()"/>
<mat-autocomplete #searchAutoComplete="matAutocomplete" class="vorgang-search" (optionSelected)="formService.submitByPreviewList($event.option.value)">
<goofy-client-spinner [stateResource]="vorgangSearchPreviewList" [class.autocomplete-spinner]="vorgangSearchPreviewList.loading"></goofy-client-spinner>
......
......@@ -22,7 +22,7 @@
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ReactiveFormsModule, UntypedFormBuilder } from '@angular/forms';
import { ReactiveFormsModule, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIcon } from '@angular/material/icon';
......@@ -36,11 +36,12 @@ import { SearchInfo, VorgangHeaderLinkRel, VorgangListService } from '@goofy-cli
import { getDataTestClassOf, getDataTestIdOf } from 'libs/tech-shared/test/data-test';
import { createVorgangListResource } from 'libs/vorgang-shared/test/vorgang';
import { MockComponent } from 'ng-mocks';
import { BehaviorSubject, Subject } from 'rxjs';
import { VorgangSearchAutocompleteOptionsContentComponent } from './vorgang-search-autocomplete-options-content/vorgang-search-autocomplete-options-content.component';
import { VorgangSearchClearButtonComponent } from './vorgang-search-clear-button/vorgang-search-clear-button.component';
import { VorgangSearchComponent } from './vorgang-search.component';
import { VorgangSearchFormService } from './vorgang-search.formservice';
import { BehaviorSubject, Subject } from 'rxjs';
import { MatButton } from '@angular/material/button';
describe('VorgangSearchComponent', () => {
let component: VorgangSearchComponent;
......@@ -49,7 +50,10 @@ describe('VorgangSearchComponent', () => {
const searchFormService = mock(VorgangSearchFormService);
const vorgangListService = { ...mock(VorgangListService), getSearchInfo: () => searchInfoSubj };
const searchInfoSubj: Subject<SearchInfo> = new BehaviorSubject({ searchString: EMPTY_STRING, changedAfterSearchDone: false });
const searchInfoSubj: Subject<SearchInfo> = new BehaviorSubject({
searchString: EMPTY_STRING,
changedAfterSearchDone: false
});
const searchPreviewOption: string = getDataTestClassOf('search-preview-option');
const searchClearButton: string = getDataTestIdOf('vorgang-search-clear-button');
......@@ -137,5 +141,76 @@ describe('VorgangSearchComponent', () => {
expect(component.searchInput.nativeElement.focus).toHaveBeenCalled();
})
})
});
describe('submit', () => {
it('should store entered search value', () => {
jest.spyOn(VorgangSearchFormService.prototype, 'getValue').mockReturnValue('Gewerbe');
component.submit();
expect(component.previouslyEnteredSearchValue).toEqual('Gewerbe');
});
it('should submit form', () => {
const submitSpy = jest.spyOn(VorgangSearchFormService.prototype, 'submit');
component.submit();
expect(submitSpy).toHaveBeenCalled();
});
});
describe('focusIn', () => {
it('should store current form value', () => {
jest.spyOn(VorgangSearchFormService.prototype, 'getValue').mockReturnValue('Gewerbe');
component.focusIn();
expect(component.previouslyEnteredSearchValue).toEqual('Gewerbe');
});
});
describe('focusOut', () => {
function createSearchSubmitMockButton(nativeElement: any): MatButton {
return {
_elementRef: {
nativeElement: nativeElement
}
} as MatButton;
}
function createMockFormGroup(searchFieldFormControl: UntypedFormControl): UntypedFormGroup {
return new UntypedFormGroup({
search: searchFieldFormControl
});
}
it('should set new form value when focus out to search button (Lupe)', () => {
const lupeElement = {};
component.previouslyEnteredSearchValue = 'Gewerbe';
component.searchSubmitButton = createSearchSubmitMockButton(lupeElement);
const searchFieldFormControl = new UntypedFormControl('Gewe');
component.formService.form = createMockFormGroup(searchFieldFormControl);
component.focusOut({ relatedTarget: lupeElement } as FocusEvent);
expect(searchFieldFormControl.value).toEqual('Gewe');
});
it('should set previous value', () => {
component.previouslyEnteredSearchValue = 'Gewe';
component.searchSubmitButton = createSearchSubmitMockButton(null);
const searchFieldFormControl = new UntypedFormControl('Gewerbe');
component.formService.form = createMockFormGroup(searchFieldFormControl);
component.focusOut({ relatedTarget: {} } as FocusEvent);
expect(searchFieldFormControl.value).toEqual('Gewe');
});
});
});
\ No newline at end of file
......@@ -25,6 +25,7 @@ import { Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@
import { StateResource } from '@goofy-client/tech-shared';
import { VorgangHeaderLinkRel, VorgangListLinkRel, VorgangListResource } from '@goofy-client/vorgang-shared';
import { VorgangSearchFormService } from './vorgang-search.formservice';
import { MatButton } from '@angular/material/button';
@Component({
selector: 'goofy-client-vorgang-search',
......@@ -39,13 +40,36 @@ export class VorgangSearchComponent {
@Output() public clearVorgangSearchPreviewList: EventEmitter<void> = new EventEmitter<void>();
@ViewChild('searchInput') searchInput: ElementRef;
@ViewChild('searchSubmitButton') searchSubmitButton: MatButton;
previouslyEnteredSearchValue: string;
readonly vorgangHeaderLinkRel = VorgangHeaderLinkRel;
readonly vorgangListLinkRel = VorgangListLinkRel;
constructor(public formService: VorgangSearchFormService) { }
constructor(public formService: VorgangSearchFormService) {
}
focus(): void {
this.searchInput.nativeElement.focus();
}
submit(): void {
this.previouslyEnteredSearchValue = this.formService.getValue();
this.formService.submit();
}
focusIn(): void {
this.previouslyEnteredSearchValue = this.formService.getValue();
}
focusOut(event: FocusEvent): void {
if (!this.isRelatedTargetSearchButton(event)) {
this.formService.setSearchValue(this.previouslyEnteredSearchValue);
}
}
private isRelatedTargetSearchButton(event: FocusEvent): boolean {
return event.relatedTarget === this.searchSubmitButton._elementRef.nativeElement;
}
}
\ No newline at end of file
......@@ -149,6 +149,10 @@ export class VorgangSearchFormService implements OnDestroy {
return isEmpty(value) ? null : value;
}
public setSearchValue(value: string): void {
this.form.controls[this.SEARCH_FIELD].setValue(value);
}
ngOnDestroy(): void {
if (isNotNil(this.subscription)) this.subscription.unsubscribe();
if (isNotNil(this.previewSubscription)) this.previewSubscription.unsubscribe();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment