Skip to content

Commit

Permalink
[ADF-5464] [form]Mandatory field validations are not applied once con…
Browse files Browse the repository at this point in the history
…tent removed (#7255)

* [ADF-5464] [form]Mandatory field validations are not applied once content is removed from these fields

* * fix test and people widget

* * fix flaky test
  • Loading branch information
dhrn committed Sep 28, 2021
1 parent e73d3c3 commit ccb17bb
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 209 deletions.
@@ -1,22 +1,24 @@
<div class="adf-group-widget {{field.className}}"
[class.is-dirty]="value"
[class.adf-invalid]="!field.isValid" [class.adf-readonly]="field.readOnly" id="functional-group-div">
[class.is-dirty]="!!field.value"
[class.adf-invalid]="!field.isValid"
[class.adf-readonly]="field.readOnly"
id="functional-group-div">

<mat-form-field>
<label class="adf-label" [attr.for]="field.id">{{field.name | translate }}<span *ngIf="isRequired()">*</span></label>
<input matInput
class="adf-input"
type="text"
data-automation-id="adf-group-search-input"
[id]="field.id"
[(ngModel)]="value"
(keyup)="onKeyUp($event)"
[disabled]="field.readOnly"
placeholder="{{field.placeholder}}"
[formControl]="searchTerm"
[placeholder]="field.placeholder"
[matAutocomplete]="auto">
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="onItemSelect($event.option.value)">
<mat-option *ngFor="let item of groups; let i = index" id="adf-group-widget-user-{{i}}"
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="updateOption($event.option.value)" [displayWith]="getDisplayName">
<mat-option *ngFor="let item of groups$ | async; let i = index"
id="adf-group-widget-user-{{i}}"
[id]="field.id +'-'+item.id"
(click)="onItemClick(item, $event)" [value]="item">
[value]="item">
<span id="adf-group-label-name">{{item.name}}</span>
</mat-option>
</mat-autocomplete>
Expand Down
Expand Up @@ -15,23 +15,25 @@
* limitations under the License.
*/

import { ElementRef } from '@angular/core';
import { Observable } from 'rxjs';
import { of, timer } from 'rxjs';
import { FormService } from '../../../services/form.service';
import { FormFieldModel } from '../core/form-field.model';
import { FormModel } from '../core/form.model';
import { GroupModel } from '../core/group.model';
import { FunctionalGroupWidgetComponent } from './functional-group.widget';
import { AlfrescoApiService } from '../../../../services';
import { TestBed } from '@angular/core/testing';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CoreTestingModule, setupTestBed } from '../../../../testing';
import { TranslateModule } from '@ngx-translate/core';

describe('FunctionalGroupWidgetComponent', () => {
let fixture: ComponentFixture<FunctionalGroupWidgetComponent>;
let component: FunctionalGroupWidgetComponent;
let formService: FormService;
let elementRef: ElementRef;
let widget: FunctionalGroupWidgetComponent;
let alfrescoApiService: AlfrescoApiService;
let getWorkflowGroupsSpy: jasmine.Spy;
const groups: GroupModel[] = [
{ id: '1', name: 'group 1' },
{ id: '2', name: 'group 2' }
];

setupTestBed({
imports: [
Expand All @@ -41,170 +43,109 @@ describe('FunctionalGroupWidgetComponent', () => {
});

beforeEach(() => {
alfrescoApiService = TestBed.inject(AlfrescoApiService);
formService = TestBed.inject(FormService);
getWorkflowGroupsSpy = spyOn(formService, 'getWorkflowGroups').and.returnValue(of([]));

formService = new FormService(null, alfrescoApiService, null);
elementRef = new ElementRef(null);
widget = new FunctionalGroupWidgetComponent(formService, elementRef);
widget.field = new FormFieldModel(new FormModel());
fixture = TestBed.createComponent(FunctionalGroupWidgetComponent);
component = fixture.componentInstance;
component.field = new FormFieldModel(new FormModel());
fixture.detectChanges();
});

it('should setup text from underlying field on init', () => {
const group: GroupModel = { name: 'group-1'};
widget.field.value = group;

spyOn(formService, 'getWorkflowGroups').and.returnValue(
new Observable((observer) => {
observer.next(null);
observer.complete();
})
);

widget.ngOnInit();
expect(formService.getWorkflowGroups).toHaveBeenCalled();
expect(widget.value).toBe(group.name);
afterEach(() => {
getWorkflowGroupsSpy.calls.reset();
fixture.destroy();
});

it('should not setup text on init', () => {
widget.field.value = null;
widget.ngOnInit();
expect(widget.value).toBeUndefined();
});
async function typeIntoInput(text: string) {
component.searchTerm.setValue(text);
fixture.detectChanges();

it('should require form field to setup values on init', () => {
widget.field = null;
widget.ngOnInit();
await timer(300).toPromise();
await fixture.whenStable();
fixture.detectChanges();

expect(widget.value).toBeUndefined();
expect(widget.groupId).toBeUndefined();
});
const input = fixture.nativeElement.querySelector('input');
input.focus();
input.dispatchEvent(new Event('focusin'));
input.dispatchEvent(new Event('input'));

it('should setup group restriction', () => {
widget.ngOnInit();
expect(widget.groupId).toBeUndefined();
await fixture.whenStable();
fixture.detectChanges();
}

it('should setup text from underlying field on init', async () => {
const group: GroupModel = { name: 'group-1'};
component.field.value = group;
component.ngOnInit();

widget.field.params = { restrictWithGroup: { id: '<id>' } };
widget.ngOnInit();
expect(widget.groupId).toBe('<id>');
expect(component.searchTerm.value).toEqual(group.name);
});

it('should prevent default behaviour on option item click', () => {
const event = jasmine.createSpyObj('event', ['preventDefault']);
widget.onItemClick(null, event);
expect(event.preventDefault).toHaveBeenCalled();
it('should not setup text on init', () => {
component.field.value = null;
component.ngOnInit();
expect(component.searchTerm.value).toBeNull();
});

it('should update values on item click', () => {
const item: GroupModel = { name: 'group-1' };
it('should setup group restriction', () => {
component.ngOnInit();
expect(component.groupId).toBeUndefined();

widget.onItemClick(item, null);
expect(widget.field.value).toBe(item);
expect(widget.value).toBe(item.name);
component.field.params = { restrictWithGroup: { id: '<id>' } };
component.ngOnInit();
expect(component.groupId).toBe('<id>');
});

it('should update form on value flush', () => {
spyOn(widget.field, 'updateForm').and.callThrough();
widget.flushValue();
expect(widget.field.updateForm).toHaveBeenCalled();
spyOn(component.field, 'updateForm').and.callThrough();
component.updateOption();
expect(component.field.updateForm).toHaveBeenCalled();
});

it('should flush selected value', () => {
const groups: GroupModel[] = [
{ id: '1', name: 'group 1' },
{ id: '2', name: 'group 2' }
];
getWorkflowGroupsSpy.and.returnValue(of(groups));

widget.groups = groups;
widget.value = 'group 2';
widget.flushValue();
component.updateOption(groups[1]);

expect(widget.value).toBe(groups[1].name);
expect(widget.field.value).toBe(groups[1]);
expect(component.field.value).toBe(groups[1]);
});

it('should be case insensitive when flushing value', () => {
const groups: GroupModel[] = [
{ id: '1', name: 'group 1' },
{ id: '2', name: 'gRoUp 2' }
];
it('should fetch groups and show popup on key up', async () => {
component.groupId = 'parentGroup';
getWorkflowGroupsSpy.and.returnValue(of(groups));

widget.groups = groups;
widget.value = 'GROUP 2';
widget.flushValue();
await typeIntoInput('group');

expect(widget.value).toBe(groups[1].name);
expect(widget.field.value).toBe(groups[1]);
const options: HTMLElement[] = Array.from(document.querySelectorAll('[id="adf-group-label-name"]'));
expect(options.map(option => option.innerText)).toEqual(['group 1', 'group 2']);
expect(getWorkflowGroupsSpy).toHaveBeenCalledWith('group', 'parentGroup');
});

it('should fetch groups and show popup on key up', () => {
const groups: GroupModel[] = [{}, {}];
spyOn(formService, 'getWorkflowGroups').and.returnValue(
new Observable((observer) => {
observer.next(groups);
observer.complete();
})
);

const keyboardEvent = new KeyboardEvent('keypress');
widget.value = 'group';
widget.onKeyUp(keyboardEvent);

expect(formService.getWorkflowGroups).toHaveBeenCalledWith('group', undefined);
expect(widget.groups).toBe(groups);
});
it('should hide popup when fetching empty group list', async () => {
component.groupId = 'parentGroup';
getWorkflowGroupsSpy.and.returnValues(of(groups), of([]));

it('should fetch groups with a group filter', () => {
const groups: GroupModel[] = [{}, {}];
spyOn(formService, 'getWorkflowGroups').and.returnValue(
new Observable((observer) => {
observer.next(groups);
observer.complete();
})
);

const keyboardEvent = new KeyboardEvent('keypress');
widget.groupId = 'parentGroup';
widget.value = 'group';
widget.onKeyUp(keyboardEvent);

expect(formService.getWorkflowGroups).toHaveBeenCalledWith('group', 'parentGroup');
expect(widget.groups).toBe(groups);
});
await typeIntoInput('group');

it('should hide popup when fetching empty group list', () => {
spyOn(formService, 'getWorkflowGroups').and.returnValue(
new Observable((observer) => {
observer.next(null);
observer.complete();
})
);
let options: HTMLElement[] = Array.from(document.querySelectorAll('[id="adf-group-label-name"]'));
expect(options.map(option => option.innerText)).toEqual(['group 1', 'group 2']);

const keyboardEvent = new KeyboardEvent('keypress');
widget.value = 'group';
widget.onKeyUp(keyboardEvent);
await typeIntoInput('unknown-group');

expect(formService.getWorkflowGroups).toHaveBeenCalledWith('group', undefined);
expect(widget.groups.length).toBe(0);
options = Array.from(document.querySelectorAll('[id="adf-group-label-name"]'));
expect(options).toEqual([]);
expect(getWorkflowGroupsSpy).toHaveBeenCalledTimes(2);
});

it('should not fetch groups when value is missing', () => {
spyOn(formService, 'getWorkflowGroups').and.stub();

const keyboardEvent = new KeyboardEvent('keypress');
widget.value = null;
widget.onKeyUp(keyboardEvent);

expect(formService.getWorkflowGroups).not.toHaveBeenCalled();
it('should not fetch groups when value is missing', async () => {
await typeIntoInput('');
expect(getWorkflowGroupsSpy).not.toHaveBeenCalled();
});

it('should not fetch groups when value violates constraints', () => {
spyOn(formService, 'getWorkflowGroups').and.stub();

const keyboardEvent = new KeyboardEvent('keypress');
widget.minTermLength = 4;
widget.value = '123';
widget.onKeyUp(keyboardEvent);

expect(formService.getWorkflowGroups).not.toHaveBeenCalled();
it('should not fetch groups when value violates constraints', async () => {
component.minTermLength = 4;
await typeIntoInput('123');
expect(getWorkflowGroupsSpy).not.toHaveBeenCalled();
});
});

0 comments on commit ccb17bb

Please sign in to comment.