ACS-8761 Noop Auth Module for unit testing ergonomics (#10195)

This commit is contained in:
Denys Vuika
2024-09-18 08:05:26 -04:00
committed by GitHub
parent 075c6891fe
commit 4d4a1dd6b1
69 changed files with 630 additions and 836 deletions

View File

@@ -42,7 +42,7 @@ export class DialogSelectAppTestComponent {
});
this.dialogRef.afterClosed().subscribe((selectedProcess) => {
this.processId = selectedProcess.id;
this.processId = selectedProcess?.id;
});
}
}

View File

@@ -17,13 +17,13 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { AlfrescoApiService, ContentModule, ContentNodeSelectorPanelComponent, DocumentListService, SitesService, NodesApiService } from '@alfresco/adf-content-services';
import { ContentNodeSelectorPanelComponent, DocumentListService, SitesService, NodesApiService } from '@alfresco/adf-content-services';
import { EventEmitter, NO_ERRORS_SCHEMA } from '@angular/core';
import { ProcessTestingModule } from '../../../testing/process.testing.module';
import { AttachFileWidgetDialogComponent } from './attach-file-widget-dialog.component';
import { BasicAlfrescoAuthService, OidcAuthenticationService } from '@alfresco/adf-core';
import { AuthenticationService } from '@alfresco/adf-core';
import { AttachFileWidgetDialogComponentData } from './attach-file-widget-dialog-component.interface';
import { of, throwError } from 'rxjs';
import { of, Subject, throwError } from 'rxjs';
import { By } from '@angular/platform-browser';
import { Node, SiteEntry, NodeEntry, SitePaging, SitePagingList } from '@alfresco/js-api';
@@ -39,21 +39,19 @@ describe('AttachFileWidgetDialogComponent', () => {
isSelectionValid: (entry: Node) => entry.isFile
};
let element: HTMLInputElement;
let basicAlfrescoAuthService: BasicAlfrescoAuthService;
let siteService: SitesService;
let nodeService: NodesApiService;
let documentListService: DocumentListService;
let apiService: AlfrescoApiService;
let matDialogRef: MatDialogRef<AttachFileWidgetDialogComponent>;
let isLoggedInSpy: jasmine.Spy;
let authService: AuthenticationService;
let closeSpy: jasmine.Spy;
let isLogged = false;
const fakeSite = new SiteEntry({ entry: { id: 'fake-site', guid: 'fake-site', title: 'fake-site', visibility: 'visible' } });
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ContentModule.forRoot(), ProcessTestingModule, AttachFileWidgetDialogComponent],
imports: [ProcessTestingModule, AttachFileWidgetDialogComponent],
providers: [
{ provide: OidcAuthenticationService, useValue: {} },
{ provide: MAT_DIALOG_DATA, useValue: data },
{ provide: MatDialogRef, useValue: { close: () => of() } }
],
@@ -62,12 +60,16 @@ describe('AttachFileWidgetDialogComponent', () => {
fixture = TestBed.createComponent(AttachFileWidgetDialogComponent);
widget = fixture.componentInstance;
element = fixture.nativeElement;
basicAlfrescoAuthService = fixture.debugElement.injector.get(BasicAlfrescoAuthService);
siteService = fixture.debugElement.injector.get(SitesService);
nodeService = fixture.debugElement.injector.get(NodesApiService);
documentListService = fixture.debugElement.injector.get(DocumentListService);
matDialogRef = fixture.debugElement.injector.get(MatDialogRef);
apiService = fixture.debugElement.injector.get(AlfrescoApiService);
const matDialogRef = fixture.debugElement.injector.get(MatDialogRef);
closeSpy = spyOn(matDialogRef, 'close');
authService = fixture.debugElement.injector.get(AuthenticationService);
spyOn(authService, 'login').and.returnValue(of({ type: 'type', ticket: 'ticket' }));
authService.onLogin = new Subject<any>();
spyOn(documentListService, 'getFolderNode').and.returnValue(of({ entry: { path: { elements: [] } } } as NodeEntry));
spyOn(documentListService, 'getFolder').and.returnValue(throwError('No results for test'));
@@ -77,22 +79,17 @@ describe('AttachFileWidgetDialogComponent', () => {
spyOn(siteService, 'getSite').and.returnValue(of(fakeSite));
spyOn(siteService, 'getSites').and.returnValue(of(new SitePaging({ list: new SitePagingList({ entries: [] }) })));
spyOn(widget, 'isLoggedIn').and.callFake(() => isLogged);
isLoggedInSpy = spyOn(widget, 'isLoggedIn').and.returnValue(false);
});
afterEach(() => {
fixture.destroy();
});
it('should be able to create the widget', () => {
fixture.detectChanges();
expect(widget).not.toBeNull();
});
describe('When is not logged in', () => {
beforeEach(() => {
isLoggedInSpy.and.returnValue(false);
fixture.detectChanges();
isLogged = false;
});
it('should show the login form', () => {
@@ -103,8 +100,7 @@ describe('AttachFileWidgetDialogComponent', () => {
});
it('should be able to login', (done) => {
spyOn(basicAlfrescoAuthService, 'login').and.returnValue(of({ type: 'type', ticket: 'ticket' }));
isLogged = true;
isLoggedInSpy.and.returnValue(true);
let loginButton: HTMLButtonElement = element.querySelector('[data-automation-id="attach-file-dialog-actions-login"]');
const usernameInput: HTMLInputElement = element.querySelector('#username');
const passwordInput: HTMLInputElement = element.querySelector('#password');
@@ -129,7 +125,7 @@ describe('AttachFileWidgetDialogComponent', () => {
let contentNodePanel;
beforeEach(() => {
isLogged = true;
isLoggedInSpy.and.returnValue(true);
fixture.detectChanges();
contentNodePanel = fixture.debugElement.query(By.directive(ContentNodeSelectorPanelComponent));
});
@@ -181,43 +177,36 @@ describe('AttachFileWidgetDialogComponent', () => {
describe('login only', () => {
beforeEach(() => {
spyOn(basicAlfrescoAuthService, 'login').and.returnValue(of({ type: 'type', ticket: 'ticket' }));
spyOn(matDialogRef, 'close').and.callThrough();
fixture.detectChanges();
widget.data.loginOnly = true;
widget.data.registerExternalHost = () => {};
isLogged = false;
widget.data = {
...widget.data,
loginOnly: true,
registerExternalHost: () => {}
};
});
it('should close the dialog once user loggedIn', () => {
it('should close the dialog once user loggedIn', async () => {
isLoggedInSpy.and.returnValue(false);
fixture.detectChanges();
isLogged = true;
const loginButton = element.querySelector<HTMLButtonElement>('[data-automation-id="attach-file-dialog-actions-login"]');
const usernameInput = element.querySelector<HTMLInputElement>('#username');
const passwordInput = element.querySelector<HTMLInputElement>('#password');
usernameInput.value = 'fake-user';
passwordInput.value = 'fake-user';
usernameInput.dispatchEvent(new Event('input'));
passwordInput.dispatchEvent(new Event('input'));
loginButton.click();
basicAlfrescoAuthService.onLogin.next('logged-in');
authService.onLogin.next('logged-in');
fixture.detectChanges();
expect(matDialogRef.close).toHaveBeenCalled();
await fixture.whenStable();
expect(closeSpy).toHaveBeenCalled();
});
it('should close the dialog immediately if user already loggedIn', () => {
isLogged = true;
isLoggedInSpy.and.returnValue(true);
fixture.detectChanges();
spyOn(apiService, 'getInstance').and.returnValue({ isLoggedIn: () => true } as any);
widget.updateExternalHost();
expect(matDialogRef.close).toHaveBeenCalled();
fixture.componentInstance.ngOnInit();
expect(closeSpy).toHaveBeenCalled();
});
});
describe('Attach button', () => {
beforeEach(() => {
isLogged = true;
isLoggedInSpy.and.returnValue(true);
});
it('should be disabled by default', () => {

View File

@@ -15,16 +15,24 @@
* limitations under the License.
*/
import { Component, Inject, ViewEncapsulation, ViewChild } from '@angular/core';
import { Component, Inject, ViewEncapsulation, ViewChild, OnDestroy, OnInit } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { LoginDialogPanelComponent, TranslationService, AuthenticationService } from '@alfresco/adf-core';
import { AttachFileWidgetDialogComponentData } from './attach-file-widget-dialog-component.interface';
import { DocumentListService, SitesService, SearchService, ContentNodeSelectorPanelComponent, AlfrescoApiService } from '@alfresco/adf-content-services';
import {
DocumentListService,
SitesService,
SearchService,
ContentNodeSelectorPanelComponent,
AlfrescoApiService
} from '@alfresco/adf-content-services';
import { ExternalAlfrescoApiService } from '../../services/external-alfresco-api.service';
import { Node } from '@alfresco/js-api';
import { CommonModule } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
import { TranslateModule } from '@ngx-translate/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'adf-attach-file-widget-dialog',
@@ -41,7 +49,7 @@ import { TranslateModule } from '@ngx-translate/core';
{ provide: AlfrescoApiService, useClass: ExternalAlfrescoApiService }
]
})
export class AttachFileWidgetDialogComponent {
export class AttachFileWidgetDialogComponent implements OnInit, OnDestroy {
@ViewChild('adfLoginPanel')
loginPanel: LoginDialogPanelComponent;
@@ -50,6 +58,8 @@ export class AttachFileWidgetDialogComponent {
buttonActionName: string;
chosenNode: Node[];
private onDestroy$ = new Subject<boolean>();
constructor(
private translation: TranslationService,
@Inject(MAT_DIALOG_DATA) public data: AttachFileWidgetDialogComponentData,
@@ -61,16 +71,21 @@ export class AttachFileWidgetDialogComponent {
this.action = data.actionName ? data.actionName.toUpperCase() : 'CHOOSE';
this.buttonActionName = `ATTACH-FILE.ACTIONS.${this.action}`;
this.updateTitle('DROPDOWN.MY_FILES_OPTION');
this.updateExternalHost();
}
updateExternalHost() {
this.authenticationService.onLogin.subscribe(() => this.registerAndClose());
ngOnInit() {
this.authenticationService.onLogin.pipe(takeUntil(this.onDestroy$)).subscribe(() => this.registerAndClose());
if (this.isLoggedIn()) {
this.registerAndClose();
}
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
isLoggedIn(): boolean {
return !!this.externalApiService.getInstance()?.isLoggedIn();
}
@@ -111,10 +126,13 @@ export class AttachFileWidgetDialogComponent {
}
private registerAndClose() {
this.data.registerExternalHost(this.data.accountIdentifier, this.externalApiService);
if (this.data.loginOnly) {
this.data.selected.complete();
this.matDialogRef.close();
if (this.data) {
this.data.registerExternalHost?.(this.data.accountIdentifier, this.externalApiService);
if (this.data.loginOnly) {
this.data.selected?.complete();
this.matDialogRef.close();
}
}
}
}

View File

@@ -28,7 +28,7 @@ import {
AppConfigService,
AppConfigValues
} from '@alfresco/adf-core';
import { ContentNodeDialogService, ContentModule } from '@alfresco/adf-content-services';
import { ContentNodeDialogService } from '@alfresco/adf-content-services';
import { of } from 'rxjs';
import { Node } from '@alfresco/js-api';
import { ProcessTestingModule } from '../../../testing/process.testing.module';
@@ -154,7 +154,7 @@ describe('AttachFileWidgetComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ProcessTestingModule, ContentModule.forRoot()]
imports: [ProcessTestingModule, AttachFileWidgetComponent]
});
fixture = TestBed.createComponent(AttachFileWidgetComponent);
widget = fixture.componentInstance;

View File

@@ -15,12 +15,12 @@
* limitations under the License.
*/
import { ComponentFixture, fakeAsync, TestBed } from '@angular/core/testing';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PeopleComponent } from './people.component';
import { ProcessTestingModule } from '../../../testing/process.testing.module';
import { LightUserRepresentation } from '@alfresco/js-api';
declare let jasmine: any;
import { PeopleProcessService } from '@alfresco/adf-process-services';
import { of, throwError } from 'rxjs';
const fakeUser: LightUserRepresentation = {
id: 0,
@@ -40,19 +40,24 @@ describe('PeopleComponent', () => {
let peopleComponent: PeopleComponent;
let fixture: ComponentFixture<PeopleComponent>;
let element: HTMLElement;
const userArray = [fakeUser, fakeSecondUser];
let peopleProcessService: PeopleProcessService;
let userArray: LightUserRepresentation[];
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ProcessTestingModule, PeopleComponent]
});
fixture = TestBed.createComponent(PeopleComponent);
peopleProcessService = fixture.debugElement.injector.get(PeopleProcessService);
peopleComponent = fixture.componentInstance;
element = fixture.nativeElement;
peopleComponent.people = [];
peopleComponent.readOnly = true;
fixture.detectChanges();
userArray = [fakeUser, fakeSecondUser];
});
afterEach(() => fixture.destroy());
@@ -78,18 +83,10 @@ describe('PeopleComponent', () => {
describe('when there are involved people', () => {
beforeEach(() => {
peopleComponent.taskId = 'fake-task-id';
peopleComponent.people.push(...userArray);
peopleComponent.people = [...userArray];
fixture.detectChanges();
});
beforeEach(() => {
jasmine.Ajax.install();
});
afterEach(() => {
jasmine.Ajax.uninstall();
});
it('should show people involved', async () => {
fixture.detectChanges();
await fixture.whenStable();
@@ -99,33 +96,73 @@ describe('PeopleComponent', () => {
expect(gatewayElement.children.length).toBe(2);
});
it('should remove people involved', fakeAsync(() => {
peopleComponent.removeInvolvedUser(fakeUser);
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200
});
fixture.whenStable().then(() => {
fixture.detectChanges();
const gatewayElement: any = element.querySelector('#assignment-people-list .adf-datatable-body');
expect(gatewayElement).not.toBeNull();
expect(gatewayElement.children.length).toBe(1);
});
}));
it('should remove involved user successfully', () => {
spyOn(peopleProcessService, 'removeInvolvedUser').and.returnValue(of(null));
peopleComponent.people = [...userArray];
peopleComponent.removeInvolvedUser(fakeUser);
fixture.detectChanges();
expect(peopleComponent.people.length).toBe(1);
expect(peopleComponent.people.find((user) => user.id === fakeUser.id)).toBeUndefined();
});
it('should emit error when removing involved user fails', () => {
spyOn(peopleProcessService, 'removeInvolvedUser').and.returnValue(throwError(() => new Error('error')));
spyOn(peopleComponent.error, 'emit');
peopleComponent.people = [...userArray];
peopleComponent.removeInvolvedUser(fakeUser);
fixture.detectChanges();
expect(peopleComponent.people.length).toBe(2);
expect(peopleComponent.error.emit).toHaveBeenCalledWith('Impossible to remove involved user from task');
});
it('should involve user successfully', () => {
spyOn(peopleProcessService, 'involveUserWithTask').and.returnValue(of(null));
peopleComponent.people = [...userArray];
it('should involve people', fakeAsync(() => {
peopleComponent.involveUser(fakeUser);
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200
});
fixture.whenStable().then(() => {
fixture.detectChanges();
const gatewayElement: any = element.querySelector('#assignment-people-list .adf-datatable-body');
expect(gatewayElement).not.toBeNull();
expect(gatewayElement.children.length).toBe(3);
});
}));
fixture.detectChanges();
expect(peopleComponent.people.length).toBe(3);
expect(peopleComponent.people.find((user) => user.id === fakeUser.id)).toBeDefined();
});
it('should emit error when involving user fails', () => {
spyOn(peopleProcessService, 'involveUserWithTask').and.returnValue(throwError(() => new Error('error')));
spyOn(peopleComponent.error, 'emit');
peopleComponent.people = [...userArray];
peopleComponent.involveUser(fakeUser);
fixture.detectChanges();
expect(peopleComponent.people.length).toBe(2);
expect(peopleComponent.error.emit).toHaveBeenCalledWith('Impossible to involve user with task');
});
it('should return an observable with user search results', (done) => {
spyOn(peopleProcessService, 'getWorkflowUsers').and.returnValue(
of([
{
id: 1,
firstName: 'fake-test-1',
lastName: 'fake-last-1',
email: 'fake-test-1@test.com'
},
{
id: 2,
firstName: 'fake-test-2',
lastName: 'fake-last-2',
email: 'fake-test-2@test.com'
}
])
);
peopleComponent.peopleSearch$.subscribe((users) => {
expect(users.length).toBe(2);
expect(users[0].firstName).toBe('fake-test-1');
@@ -135,71 +172,44 @@ describe('PeopleComponent', () => {
done();
});
peopleComponent.searchUser('fake-search-word');
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'json',
responseText: {
data: [
{
id: 1,
firstName: 'fake-test-1',
lastName: 'fake-last-1',
email: 'fake-test-1@test.com'
},
{
id: 2,
firstName: 'fake-test-2',
lastName: 'fake-last-2',
email: 'fake-test-2@test.com'
}
]
}
});
});
it('should return an empty list for not valid search', (done) => {
spyOn(peopleProcessService, 'getWorkflowUsers').and.returnValue(of([]));
peopleComponent.peopleSearch$.subscribe((users) => {
expect(users.length).toBe(0);
done();
});
peopleComponent.searchUser('fake-search-word');
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'json',
responseText: {}
});
});
});
describe('when there are errors on service call', () => {
beforeEach(() => {
jasmine.Ajax.install();
peopleComponent.people.push(...userArray);
fixture.detectChanges();
});
afterEach(() => {
jasmine.Ajax.uninstall();
});
it('should not remove user if remove involved user fail', async () => {
spyOn(peopleProcessService, 'removeInvolvedUser').and.returnValue(throwError(() => new Error('error')));
peopleComponent.removeInvolvedUser(fakeUser);
jasmine.Ajax.requests.mostRecent().respondWith({
status: 403
});
fixture.detectChanges();
await fixture.whenStable();
const gatewayElement: any = element.querySelector('#assignment-people-list .adf-datatable-body');
const gatewayElement = element.querySelector('#assignment-people-list .adf-datatable-body');
expect(gatewayElement).not.toBeNull();
expect(gatewayElement.children.length).toBe(2);
});
it('should not involve user if involve user fail', async () => {
spyOn(peopleProcessService, 'involveUserWithTask').and.returnValue(throwError(() => new Error('error')));
peopleComponent.involveUser(fakeUser);
jasmine.Ajax.requests.mostRecent().respondWith({
status: 403
});
fixture.detectChanges();
await fixture.whenStable();
const gatewayElement: any = element.querySelector('#assignment-people-list .adf-datatable-body');
const gatewayElement = element.querySelector('#assignment-people-list .adf-datatable-body');
expect(gatewayElement).not.toBeNull();
expect(gatewayElement.children.length).toBe(2);
});

View File

@@ -75,30 +75,30 @@ export class PeopleComponent {
}
searchUser(searchedWord: string) {
this.peopleProcessService.getWorkflowUsers(this.taskId, searchedWord).subscribe(
(users) => {
this.peopleProcessService.getWorkflowUsers(this.taskId, searchedWord).subscribe({
next: (users) => {
this.peopleSearchObserver.next(users);
},
(error) => this.error.emit(error)
);
error: (error) => this.error.emit(error)
});
}
involveUser(user: LightUserRepresentation) {
if (user?.id !== undefined) {
this.peopleProcessService.involveUserWithTask(this.taskId, user.id.toString()).subscribe(
() => (this.people = [...this.people, user]),
() => this.error.emit('Impossible to involve user with task')
);
this.peopleProcessService.involveUserWithTask(this.taskId, user.id.toString()).subscribe({
next: () => (this.people = [...this.people, user]),
error: () => this.error.emit('Impossible to involve user with task')
});
}
}
removeInvolvedUser(user: LightUserRepresentation) {
this.peopleProcessService.removeInvolvedUser(this.taskId, user.id.toString()).subscribe(
() => {
this.peopleProcessService.removeInvolvedUser(this.taskId, user.id.toString()).subscribe({
next: () => {
this.people = this.people.filter((involvedUser) => involvedUser.id !== user.id);
},
() => this.error.emit('Impossible to remove involved user from task')
);
error: () => this.error.emit('Impossible to remove involved user from task')
});
}
getDisplayUser(firstName: string, lastName: string, delimiter: string = '-'): string {

View File

@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { CUSTOM_ELEMENTS_SCHEMA, SimpleChange } from '@angular/core';
import { SimpleChange } from '@angular/core';
import { from, of, throwError } from 'rxjs';
import { AppsProcessService } from '../../../services/apps-process.service';
import { ProcessFilterService } from '../../services/process-filter.service';
@@ -24,7 +24,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { ProcessTestingModule } from '../../../testing/process.testing.module';
import { NavigationStart, Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { ProcessInstanceFilterRepresentation, UserProcessInstanceFilterRepresentation } from '@alfresco/js-api';
const fakeProcessFilters: UserProcessInstanceFilterRepresentation[] = [
@@ -54,17 +53,26 @@ describe('ProcessFiltersComponent', () => {
let processFilterService: ProcessFilterService;
let appsProcessService: AppsProcessService;
let router: Router;
let getProcessFiltersSpy: jasmine.Spy;
let getDeployedApplicationsByNameSpy: jasmine.Spy;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ProcessTestingModule, RouterTestingModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
imports: [ProcessTestingModule]
});
processFilterService = TestBed.inject(ProcessFilterService);
getProcessFiltersSpy = spyOn(processFilterService, 'getProcessFilters').and.returnValue(of(fakeProcessFilters));
appsProcessService = TestBed.inject(AppsProcessService);
getDeployedApplicationsByNameSpy = spyOn(appsProcessService, 'getDeployedApplicationsByName').and.returnValue(
from(Promise.resolve({ id: 1 }))
);
router = TestBed.inject(Router);
fixture = TestBed.createComponent(ProcessFiltersComponent);
filterList = fixture.componentInstance;
processFilterService = TestBed.inject(ProcessFilterService);
appsProcessService = TestBed.inject(AppsProcessService);
router = TestBed.inject(Router);
});
afterEach(() => {
@@ -72,7 +80,6 @@ describe('ProcessFiltersComponent', () => {
});
it('should return the filter task list', async () => {
spyOn(processFilterService, 'getProcessFilters').and.returnValue(of(fakeProcessFilters));
const appId = '1';
const change = new SimpleChange(null, appId, true);
@@ -97,23 +104,7 @@ describe('ProcessFiltersComponent', () => {
expect(filterList.filters[2].name).toEqual('Running');
});
it('should select the Running process filter', async () => {
spyOn(processFilterService, 'getProcessFilters').and.returnValue(of(fakeProcessFilters));
const appId = '1';
const change = new SimpleChange(null, appId, true);
filterList.ngOnChanges({ appId: change });
fixture.detectChanges();
await fixture.whenStable();
filterList.selectRunningFilter();
expect(filterList.currentFilter.name).toEqual('Running');
});
it('should emit the selected filter based on the filterParam input', async () => {
spyOn(processFilterService, 'getProcessFilters').and.returnValue(of(fakeProcessFilters));
filterList.filterParam = { id: 10 } as any;
const appId = '1';
const change = new SimpleChange(null, appId, true);
@@ -142,8 +133,6 @@ describe('ProcessFiltersComponent', () => {
});
it('should reset selection when filterParam is a filter that does not exist', async () => {
spyOn(processFilterService, 'getProcessFilters').and.returnValue(of(fakeProcessFilters));
const nonExistingFilterParam = { name: 'non-existing-filter' };
const appId = '1';
const change = new SimpleChange(null, appId, true);
@@ -159,18 +148,15 @@ describe('ProcessFiltersComponent', () => {
});
it('should return the filter task list, filtered By Name', () => {
const deployApp = spyOn(appsProcessService, 'getDeployedApplicationsByName').and.returnValue(from(Promise.resolve({ id: 1 })));
spyOn(processFilterService, 'getProcessFilters').and.returnValue(of(fakeProcessFilters));
const change = new SimpleChange(null, 'test', true);
filterList.ngOnChanges({ appName: change });
fixture.detectChanges();
expect(deployApp.calls.count()).toEqual(1);
expect(getDeployedApplicationsByNameSpy.calls.count()).toEqual(1);
});
it('should emit an error with a bad response of getProcessFilters', () => {
spyOn(processFilterService, 'getProcessFilters').and.returnValue(throwError('error'));
getProcessFiltersSpy.and.returnValue(throwError(() => new Error('error')));
const appId = '1';
const change = new SimpleChange(null, appId, true);
@@ -184,7 +170,7 @@ describe('ProcessFiltersComponent', () => {
});
it('should emit an error with a bad response of getDeployedApplicationsByName', () => {
spyOn(appsProcessService, 'getDeployedApplicationsByName').and.returnValue(throwError('wrong request'));
getDeployedApplicationsByNameSpy.and.returnValue(throwError(() => new Error('wrong request')));
const appId = 'fake-app';
const change = new SimpleChange(null, appId, true);
@@ -255,8 +241,6 @@ describe('ProcessFiltersComponent', () => {
});
it('should select the filter passed as input by id', async () => {
spyOn(processFilterService, 'getProcessFilters').and.returnValue(of(fakeProcessFilters));
filterList.filterParam = { id: 20 } as any;
const appId = 1;
@@ -272,8 +256,6 @@ describe('ProcessFiltersComponent', () => {
});
it('should select the filter passed as input by name', async () => {
spyOn(processFilterService, 'getProcessFilters').and.returnValue(of(fakeProcessFilters));
filterList.filterParam = { name: 'FakeAll' } as any;
const appId = 1;
@@ -289,7 +271,6 @@ describe('ProcessFiltersComponent', () => {
});
it('should attach specific icon for each filter if hasIcon is true', async () => {
spyOn(processFilterService, 'getProcessFilters').and.returnValue(of(fakeProcessFilters));
filterList.showIcon = true;
const change = new SimpleChange(undefined, 1, true);
filterList.ngOnChanges({ appId: change });
@@ -304,7 +285,6 @@ describe('ProcessFiltersComponent', () => {
});
it('should not attach icons for each filter if hasIcon is false', async () => {
spyOn(processFilterService, 'getProcessFilters').and.returnValue(of(fakeProcessFilters));
filterList.showIcon = false;
const change = new SimpleChange(undefined, 1, true);
filterList.ngOnChanges({ appId: change });

View File

@@ -15,18 +15,17 @@
* limitations under the License.
*/
import { NO_ERRORS_SCHEMA, SimpleChange } from '@angular/core';
import { SimpleChange } from '@angular/core';
import { ComponentFixture, fakeAsync, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { of, throwError } from 'rxjs';
import { FormModel, FormOutcomeEvent, FormOutcomeModel, CommentModel, User } from '@alfresco/adf-core';
import { FormModel, FormOutcomeEvent, FormOutcomeModel, CommentModel, User, ADF_COMMENTS_SERVICE, CommentsService } from '@alfresco/adf-core';
import { noDataMock, taskDetailsMock, taskFormMock, tasksMock, taskDetailsWithOutAssigneeMock } from '../../../testing/mock';
import { TaskListService } from '../../services/tasklist.service';
import { TaskDetailsComponent } from './task-details.component';
import { ProcessTestingModule } from '../../../testing/process.testing.module';
import { TaskService } from '../../../form/services/task.service';
import { TaskFormService } from '../../../form/services/task-form.service';
import { TaskCommentsService } from '../../../services/task-comments.service';
import { PeopleProcessService } from '../../../services/people-process.service';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { HarnessLoader } from '@angular/cdk/testing';
@@ -48,32 +47,27 @@ const fakeTaskAssignResponse: any = {
};
describe('TaskDetailsComponent', () => {
let taskListService: TaskListService;
let taskService: TaskService;
let taskFormService: TaskFormService;
let component: TaskDetailsComponent;
let fixture: ComponentFixture<TaskDetailsComponent>;
let loader: HarnessLoader;
let getTaskDetailsSpy: jasmine.Spy;
let getCommentsSpy: jasmine.Spy;
let getTasksSpy: jasmine.Spy;
let assignTaskSpy: jasmine.Spy;
let taskCommentsService: TaskCommentsService;
let taskCommentsService: CommentsService;
let peopleProcessService: PeopleProcessService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ProcessTestingModule, TaskDetailsComponent],
schemas: [NO_ERRORS_SCHEMA]
imports: [ProcessTestingModule, TaskDetailsComponent]
});
peopleProcessService = TestBed.inject(PeopleProcessService);
spyOn(peopleProcessService, 'getCurrentUserInfo').and.returnValue(of({ email: 'fake-email' } as any));
taskListService = TestBed.inject(TaskListService);
const taskListService = TestBed.inject(TaskListService);
spyOn(taskListService, 'getTaskChecklist').and.returnValue(of(noDataMock));
taskService = TestBed.inject(TaskService);
const taskService = TestBed.inject(TaskService);
taskFormService = TestBed.inject(TaskFormService);
getTaskDetailsSpy = spyOn(taskListService, 'getTaskDetails').and.returnValue(of(taskDetailsMock));
@@ -83,9 +77,11 @@ describe('TaskDetailsComponent', () => {
getTasksSpy = spyOn(taskListService, 'getTasks').and.returnValue(of(tasksMock));
assignTaskSpy = spyOn(taskListService, 'assignTask').and.returnValue(of(fakeTaskAssignResponse));
taskCommentsService = TestBed.inject(TaskCommentsService);
getCommentsSpy = spyOn(taskCommentsService, 'get').and.returnValue(
fixture = TestBed.createComponent(TaskDetailsComponent);
taskCommentsService = fixture.debugElement.injector.get<CommentsService>(ADF_COMMENTS_SERVICE);
spyOn(taskCommentsService, 'get').and.returnValue(
of([
new CommentModel({ message: 'Test1', created: new Date(), createdBy: new User({ firstName: 'Admin', lastName: 'User' }) }),
new CommentModel({ message: 'Test2', created: new Date(), createdBy: new User({ firstName: 'Admin', lastName: 'User' }) }),
@@ -93,15 +89,12 @@ describe('TaskDetailsComponent', () => {
])
);
fixture = TestBed.createComponent(TaskDetailsComponent);
peopleProcessService = TestBed.inject(PeopleProcessService);
component = fixture.componentInstance;
component.showComments = false;
loader = TestbedHarnessEnvironment.documentRootLoader(fixture);
});
afterEach(() => {
getTaskDetailsSpy.calls.reset();
getCommentsSpy.calls.reset();
fixture.destroy();
});
@@ -418,8 +411,12 @@ describe('TaskDetailsComponent', () => {
expect(lastValue.length).toBe(0);
});
it('should assign task to user', () => {
it('should assign task to user', async () => {
component.assignTaskToUser(fakeUser);
fixture.detectChanges();
await fixture.whenStable();
expect(assignTaskSpy).toHaveBeenCalled();
});
});

View File

@@ -16,6 +16,7 @@
*/
import {
ADF_COMMENTS_SERVICE,
CardViewUpdateService,
ClickNotification,
ContentLinkModel,
@@ -51,7 +52,7 @@ import { TranslateModule } from '@ngx-translate/core';
import { AttachFormComponent } from '../attach-form/attach-form.component';
import { PeopleComponent, PeopleSearchComponent } from '../../../people';
import { TaskHeaderComponent } from '../task-header/task-header.component';
import { TaskCommentsComponent } from '../../../task-comments';
import { TaskCommentsComponent, TaskCommentsService } from '../../../task-comments';
import { ChecklistComponent } from '../checklist/checklist.component';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
@@ -75,6 +76,12 @@ import { MatCardModule } from '@angular/material/card';
InfoDrawerComponent,
MatCardModule
],
providers: [
{
provide: ADF_COMMENTS_SERVICE,
useClass: TaskCommentsService
}
],
templateUrl: './task-details.component.html',
styleUrls: ['./task-details.component.scss'],
encapsulation: ViewEncapsulation.None

View File

@@ -15,36 +15,19 @@
* limitations under the License.
*/
import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-content-services';
import { NgModule } from '@angular/core';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { ProcessModule } from '../process.module';
import {
AppConfigService,
AppConfigServiceMock,
CoreModule,
FormRenderingService,
AuthModule,
NoopTranslateModule
} from '@alfresco/adf-core';
import { CoreModule, FormRenderingService, NoopTranslateModule, NoopAuthModule } from '@alfresco/adf-core';
import { ProcessFormRenderingService } from '../form/process-form-rendering.service';
import { RouterTestingModule } from '@angular/router/testing';
import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-content-services';
@NgModule({
imports: [
AuthModule.forRoot({ useHash: true }),
NoopAnimationsModule,
CoreModule.forRoot(),
ProcessModule.forRoot(),
RouterTestingModule,
NoopTranslateModule
],
imports: [CoreModule.forRoot(), ProcessModule.forRoot(), NoopAuthModule, NoopAnimationsModule, NoopTranslateModule],
providers: [
{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock },
{ provide: AppConfigService, useClass: AppConfigServiceMock },
FormRenderingService,
{ provide: FormRenderingService, useClass: ProcessFormRenderingService }
],
exports: [NoopAnimationsModule, CoreModule, ProcessModule]
exports: [CoreModule, ProcessModule]
})
export class ProcessTestingModule {}

View File

@@ -22,5 +22,5 @@ import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@ang
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), {
teardown: { destroyAfterEach: false }
teardown: { destroyAfterEach: true }
});