AAE-39612 Registering click event on form widget twice (#11323)

* AAE-39612 Remove click from base and add it directly to the implementations

* AAE-39612 Add unit tests for the Text Widgets

* AAE-39612 Add unit tests for the Date Widgets

* AAE-39612 Add unit tests for the UI Widgets

* AAE-39612 Add unit tests for the People Widgets

* AAE-39612 Add unit tests for the Display Text Widgets

* AAE-39612 Add unit tests for the Base Viewer Widget

* AAE-39612 Add unit tests for the Object View Widgets

* AAE-39612 Add unit tests for the File Upload Widgets

* AAE-39612 Add unit tests for the Data Table Widget
This commit is contained in:
Wiktor Danielewski
2025-11-04 12:08:04 +01:00
committed by GitHub
parent f7d26d904f
commit c4f276e228
40 changed files with 597 additions and 92 deletions
@@ -170,8 +170,22 @@ describe('AttachFileCloudWidgetComponent', () => {
});
});
afterEach(() => {
fixture.destroy();
describe('event tracking', () => {
let eventSpy: jasmine.Spy;
beforeEach(() => {
eventSpy = spyOn(widget, 'event').and.callThrough();
widget.field = new FormFieldModel(new FormModel(), {});
fixture.detectChanges();
});
it('should call event method only once when widget is clicked', () => {
const clickEvent = new MouseEvent('click', { bubbles: true });
fixture.debugElement.nativeElement.dispatchEvent(clickEvent);
expect(eventSpy).toHaveBeenCalledTimes(1);
expect(eventSpy).toHaveBeenCalledWith(clickEvent);
});
});
it('should show up as simple upload when is configured for only local files', async () => {
@@ -56,17 +56,6 @@ const VALID_ALIAS = [ALIAS_ROOT_FOLDER, ALIAS_USER_FOLDER, '-shared-'];
imports: [CommonModule, ErrorWidgetComponent, TranslatePipe, MatIconModule, FilePropertiesTableCloudComponent, MatButtonModule],
templateUrl: './attach-file-cloud-widget.component.html',
styleUrls: ['./attach-file-cloud-widget.component.scss'],
host: {
'(click)': 'event($event)',
'(blur)': 'event($event)',
'(change)': 'event($event)',
'(focus)': 'event($event)',
'(focusin)': 'event($event)',
'(focusout)': 'event($event)',
'(input)': 'event($event)',
'(invalid)': 'event($event)',
'(select)': 'event($event)'
},
encapsulation: ViewEncapsulation.None
})
export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent implements OnInit, OnDestroy {
@@ -96,6 +96,24 @@ describe('DataTableWidgetComponent', () => {
});
});
describe('event tracking', () => {
let eventSpy: jasmine.Spy;
beforeEach(() => {
eventSpy = spyOn(widget, 'event').and.callThrough();
widget.field = new FormFieldModel(new FormModel(), {});
fixture.detectChanges();
});
it('should call event method only once when widget is clicked', () => {
const clickEvent = new MouseEvent('click', { bubbles: true });
fixture.debugElement.nativeElement.dispatchEvent(clickEvent);
expect(eventSpy).toHaveBeenCalledTimes(1);
expect(eventSpy).toHaveBeenCalledWith(clickEvent);
});
});
it('should display label', () => {
fixture.detectChanges();
@@ -48,6 +48,24 @@ describe('DateCloudWidgetComponent', () => {
testingUtils = new UnitTestingUtils(fixture.debugElement, loader);
});
describe('event tracking', () => {
let eventSpy: jasmine.Spy;
beforeEach(() => {
eventSpy = spyOn(widget, 'event').and.callThrough();
widget.field = new FormFieldModel(new FormModel(), {});
fixture.detectChanges();
});
it('should call event method only once when widget is clicked', () => {
const clickEvent = new MouseEvent('click', { bubbles: true });
fixture.debugElement.nativeElement.dispatchEvent(clickEvent);
expect(eventSpy).toHaveBeenCalledTimes(1);
expect(eventSpy).toHaveBeenCalledWith(clickEvent);
});
});
it('should not call onFieldChanged on init', () => {
spyOn(widget, 'onFieldChanged').and.callThrough();
expect(widget.onFieldChanged).not.toHaveBeenCalled();
@@ -46,6 +46,24 @@ describe('DisplayExternalPropertyWidgetComponent', () => {
testingUtils = new UnitTestingUtils(fixture.debugElement, loader);
});
describe('event tracking', () => {
let eventSpy: jasmine.Spy;
beforeEach(() => {
eventSpy = spyOn(widget, 'event').and.callThrough();
widget.field = new FormFieldModel(new FormModel(), {});
fixture.detectChanges();
});
it('should call event method only once when widget is clicked', () => {
const clickEvent = new MouseEvent('click', { bubbles: true });
fixture.debugElement.nativeElement.dispatchEvent(clickEvent);
expect(eventSpy).toHaveBeenCalledTimes(1);
expect(eventSpy).toHaveBeenCalledWith(clickEvent);
});
});
it('should display initial value', async () => {
widget.field = new FormFieldModel(new FormModel({ taskId: '<id>' }), {
type: FormFieldTypes.DISPLAY_EXTERNAL_PROPERTY,
@@ -20,6 +20,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DisplayRichTextWidgetComponent, RICH_TEXT_PARSER_TOKEN } from './display-rich-text.widget';
import { RichTextParserService } from '../../../services/rich-text-parser.service';
import { FormFieldModel, FormModel } from '@alfresco/adf-core';
describe('DisplayRichTextWidgetComponent', () => {
let widget: DisplayRichTextWidgetComponent;
@@ -96,6 +97,24 @@ describe('DisplayRichTextWidgetComponent', () => {
widget.field = fakeFormField;
});
describe('event tracking', () => {
let eventSpy: jasmine.Spy;
beforeEach(() => {
eventSpy = spyOn(widget, 'event').and.callThrough();
widget.field = new FormFieldModel(new FormModel(), {});
fixture.detectChanges();
});
it('should call event method only once when widget is clicked', () => {
const clickEvent = new MouseEvent('click', { bubbles: true });
fixture.debugElement.nativeElement.dispatchEvent(clickEvent);
expect(eventSpy).toHaveBeenCalledTimes(1);
expect(eventSpy).toHaveBeenCalledWith(clickEvent);
});
});
it('should call RichTextParserService.parse() method', () => {
fixture.detectChanges();
@@ -74,6 +74,24 @@ describe('DropdownCloudWidgetComponent', () => {
afterEach(() => fixture.destroy());
describe('event tracking', () => {
let eventSpy: jasmine.Spy;
beforeEach(() => {
eventSpy = spyOn(widget, 'event').and.callThrough();
widget.field = new FormFieldModel(new FormModel(), {});
fixture.detectChanges();
});
it('should call event method only once when widget is clicked', () => {
const clickEvent = new MouseEvent('click', { bubbles: true });
fixture.debugElement.nativeElement.dispatchEvent(clickEvent);
expect(eventSpy).toHaveBeenCalledTimes(1);
expect(eventSpy).toHaveBeenCalledWith(clickEvent);
});
});
describe('Simple Dropdown', () => {
beforeEach(() => {
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: false, id: 'form-id' }), {
@@ -29,7 +29,7 @@ import {
SelectFilterInputComponent,
WidgetComponent
} from '@alfresco/adf-core';
import { AsyncPipe, NgClass, NgFor, NgIf } from '@angular/common';
import { AsyncPipe, NgClass, NgIf } from '@angular/common';
import { Component, DestroyRef, inject, OnInit, ViewEncapsulation } from '@angular/core';
import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
import { MatFormFieldModule } from '@angular/material/form-field';
@@ -56,10 +56,12 @@ export const DROPDOWN_CLOUD_WIDGET_SET_VALUE_DEBOUNCE = 100;
selector: 'dropdown-cloud-widget',
templateUrl: './dropdown-cloud.widget.html',
styleUrls: ['./dropdown-cloud.widget.scss'],
host: {
'(click)': 'event($event)'
},
encapsulation: ViewEncapsulation.None,
imports: [
NgIf,
NgFor,
NgClass,
AsyncPipe,
ReactiveFormsModule,
@@ -51,6 +51,24 @@ describe('FileViewerWidgetComponent', () => {
widget = fixture.componentInstance;
});
describe('event tracking', () => {
let eventSpy: jasmine.Spy;
beforeEach(() => {
eventSpy = spyOn(widget, 'event').and.callThrough();
widget.field = new FormFieldModel(new FormModel(), {});
fixture.detectChanges();
});
it('should call event method only once when widget is clicked', () => {
const clickEvent = new MouseEvent('click', { bubbles: true });
fixture.debugElement.nativeElement.dispatchEvent(clickEvent);
expect(eventSpy).toHaveBeenCalledTimes(1);
expect(eventSpy).toHaveBeenCalledWith(clickEvent);
});
});
it('should set the file id corretly when the field value is an array', async () => {
widget.field = new FormFieldModel(fakeForm, { id: 'fakeField', value: [fakePngAnswer] });
@@ -27,17 +27,6 @@ import { TranslatePipe } from '@ngx-translate/core';
imports: [ErrorWidgetComponent, AlfrescoViewerComponent, TranslatePipe],
templateUrl: './file-viewer.widget.html',
styleUrls: ['./file-viewer.widget.scss'],
host: {
'(click)': 'event($event)',
'(blur)': 'event($event)',
'(change)': 'event($event)',
'(focus)': 'event($event)',
'(focusin)': 'event($event)',
'(focusout)': 'event($event)',
'(input)': 'event($event)',
'(invalid)': 'event($event)',
'(select)': 'event($event)'
},
encapsulation: ViewEncapsulation.None
})
export class FileViewerWidgetComponent extends BaseViewerWidgetComponent {
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { FormFieldModel, FormFieldTypes, FormModel, IdentityGroupModel, NoopAuthModule, CoreModule } from '@alfresco/adf-core';
import { FormFieldModel, FormFieldTypes, FormModel, IdentityGroupModel, NoopAuthModule } from '@alfresco/adf-core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { GroupCloudWidgetComponent } from './group-cloud.widget';
import { HarnessLoader } from '@angular/cdk/testing';
@@ -30,7 +30,7 @@ describe('GroupCloudWidgetComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [CoreModule.forRoot(), NoopAuthModule, GroupCloudWidgetComponent]
imports: [NoopAuthModule, GroupCloudWidgetComponent]
});
fixture = TestBed.createComponent(GroupCloudWidgetComponent);
widget = fixture.componentInstance;
@@ -38,8 +38,22 @@ describe('GroupCloudWidgetComponent', () => {
loader = TestbedHarnessEnvironment.loader(fixture);
});
afterEach(() => {
fixture.destroy();
describe('event tracking', () => {
let eventSpy: jasmine.Spy;
beforeEach(() => {
eventSpy = spyOn(widget, 'event').and.callThrough();
widget.field = new FormFieldModel(new FormModel(), {});
fixture.detectChanges();
});
it('should call event method only once when widget is clicked', () => {
const clickEvent = new MouseEvent('click', { bubbles: true });
fixture.debugElement.nativeElement.dispatchEvent(clickEvent);
expect(eventSpy).toHaveBeenCalledTimes(1);
expect(eventSpy).toHaveBeenCalledWith(clickEvent);
});
});
it('should have enabled validation if field is NOT readOnly', () => {
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { FormFieldModel, FormFieldTypes, FormModel, IdentityUserModel, NoopAuthModule, CoreModule } from '@alfresco/adf-core';
import { FormFieldModel, FormFieldTypes, FormModel, IdentityUserModel, NoopAuthModule } from '@alfresco/adf-core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PeopleCloudWidgetComponent } from './people-cloud.widget';
import { IdentityUserService } from '../../../../people/services/identity-user.service';
@@ -33,7 +33,7 @@ describe('PeopleCloudWidgetComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [CoreModule.forRoot(), NoopAuthModule, PeopleCloudWidgetComponent]
imports: [NoopAuthModule, PeopleCloudWidgetComponent]
});
identityUserService = TestBed.inject(IdentityUserService);
fixture = TestBed.createComponent(PeopleCloudWidgetComponent);
@@ -43,8 +43,22 @@ describe('PeopleCloudWidgetComponent', () => {
loader = TestbedHarnessEnvironment.loader(fixture);
});
afterEach(() => {
fixture.destroy();
describe('event tracking', () => {
let eventSpy: jasmine.Spy;
beforeEach(() => {
eventSpy = spyOn(widget, 'event').and.callThrough();
widget.field = new FormFieldModel(new FormModel(), {});
fixture.detectChanges();
});
it('should call event method only once when widget is clicked', () => {
const clickEvent = new MouseEvent('click', { bubbles: true });
fixture.debugElement.nativeElement.dispatchEvent(clickEvent);
expect(eventSpy).toHaveBeenCalledTimes(1);
expect(eventSpy).toHaveBeenCalledWith(clickEvent);
});
});
it('should preselect the current user', () => {
@@ -57,7 +57,23 @@ describe('PropertiesViewerWidgetComponent', () => {
spyOn(nodesApiService, 'getNode').and.returnValue(of(fakeNodeWithProperties));
});
afterEach(() => fixture.destroy());
describe('event tracking', () => {
let eventSpy: jasmine.Spy;
beforeEach(() => {
eventSpy = spyOn(widget, 'event').and.callThrough();
widget.field = new FormFieldModel(new FormModel(), {});
fixture.detectChanges();
});
it('should call event method only once when widget is clicked', () => {
const clickEvent = new MouseEvent('click', { bubbles: true });
fixture.debugElement.nativeElement.dispatchEvent(clickEvent);
expect(eventSpy).toHaveBeenCalledTimes(1);
expect(eventSpy).toHaveBeenCalledWith(clickEvent);
});
});
it('should not display properties viewer when value is not set', async () => {
widget.field.value = undefined;
@@ -29,17 +29,6 @@ import { CommonModule } from '@angular/common';
imports: [CommonModule, ErrorWidgetComponent, PropertiesViewerWrapperComponent, TranslatePipe],
templateUrl: './properties-viewer.widget.html',
styleUrls: ['./properties-viewer.widget.scss'],
host: {
'(click)': 'event($event)',
'(blur)': 'event($event)',
'(change)': 'event($event)',
'(focus)': 'event($event)',
'(focusin)': 'event($event)',
'(focusout)': 'event($event)',
'(input)': 'event($event)',
'(invalid)': 'event($event)',
'(select)': 'event($event)'
},
encapsulation: ViewEncapsulation.None
})
export class PropertiesViewerWidgetComponent extends BaseViewerWidgetComponent {
@@ -56,6 +56,24 @@ describe('RadioButtonsCloudWidgetComponent', () => {
widget.field = new FormFieldModel(new FormModel(), { restUrl: '<url>' });
});
describe('event tracking', () => {
let eventSpy: jasmine.Spy;
beforeEach(() => {
eventSpy = spyOn(widget, 'event').and.callThrough();
widget.field = new FormFieldModel(new FormModel(), {});
fixture.detectChanges();
});
it('should call event method only once when widget is clicked', () => {
const clickEvent = new MouseEvent('click', { bubbles: true });
fixture.debugElement.nativeElement.dispatchEvent(clickEvent);
expect(eventSpy).toHaveBeenCalledTimes(1);
expect(eventSpy).toHaveBeenCalledWith(clickEvent);
});
});
it('should update form on values fetched', () => {
spyOn(formCloudService, 'getRestWidgetData').and.returnValue(of(restOption));
const taskId = '<form-id>';
@@ -0,0 +1,58 @@
/*!
* @license
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { UploadCloudWidgetComponent } from './upload-cloud.widget';
import { FormFieldModel, FormModel, ThumbnailService, NotificationService } from '@alfresco/adf-core';
import { ProcessCloudContentService } from '../../../services/process-cloud-content.service';
describe('UploadCloudWidgetComponent', () => {
let fixture: ComponentFixture<UploadCloudWidgetComponent>;
let widget: UploadCloudWidgetComponent;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [UploadCloudWidgetComponent],
providers: [
{ provide: ThumbnailService, useValue: {} },
{ provide: ProcessCloudContentService, useValue: {} },
{ provide: NotificationService, useValue: {} }
]
});
fixture = TestBed.createComponent(UploadCloudWidgetComponent);
widget = fixture.componentInstance;
});
describe('event tracking', () => {
let eventSpy: jasmine.Spy;
beforeEach(() => {
eventSpy = spyOn(widget, 'event').and.callThrough();
widget.field = new FormFieldModel(new FormModel(), {});
fixture.detectChanges();
});
it('should call event method only once when widget is clicked', () => {
const clickEvent = new MouseEvent('click', { bubbles: true });
fixture.debugElement.nativeElement.dispatchEvent(clickEvent);
expect(eventSpy).toHaveBeenCalledTimes(1);
expect(eventSpy).toHaveBeenCalledWith(clickEvent);
});
});
});