diff --git a/lib/process-services-cloud/src/lib/task/start-task/components/people-cloud/people-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/task/start-task/components/people-cloud/people-cloud.component.spec.ts index 4b2bad9f2b..0d23998d9e 100644 --- a/lib/process-services-cloud/src/lib/task/start-task/components/people-cloud/people-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/task/start-task/components/people-cloud/people-cloud.component.spec.ts @@ -15,346 +15,538 @@ * limitations under the License. */ -import { ComponentFixture, TestBed, async } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; import { PeopleCloudComponent } from './people-cloud.component'; -import { StartTaskCloudTestingModule } from '../../testing/start-task-cloud.testing.module'; -import { LogService, setupTestBed, IdentityUserService, IdentityUserModel } from '@alfresco/adf-core'; -import { mockUsers } from '../../mock/user-cloud.mock'; -import { of } from 'rxjs'; +import { ComponentFixture, TestBed, async, tick, fakeAsync } from '@angular/core/testing'; +import { IdentityUserService, AlfrescoApiService, AlfrescoApiServiceMock, CoreModule, IdentityUserModel } from '@alfresco/adf-core'; import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module'; +import { of } from 'rxjs'; +import { mockUsers } from '../../mock/user-cloud.mock'; +import { StartTaskCloudModule } from '../../start-task-cloud.module'; import { SimpleChange } from '@angular/core'; +import { By } from '@angular/platform-browser'; describe('PeopleCloudComponent', () => { let component: PeopleCloudComponent; let fixture: ComponentFixture; let element: HTMLElement; let identityService: IdentityUserService; - let findUsersSpy: jasmine.Spy; - let checkUserHasAccessSpy: jasmine.Spy; - let loadClientsByApplicationNameSpy: jasmine.Spy; + let alfrescoApiService: AlfrescoApiService; - setupTestBed({ - imports: [ProcessServiceCloudTestingModule, StartTaskCloudTestingModule], - providers: [IdentityUserService, LogService] - }); + const mock = { + oauth2Auth: { + callCustomApi: () => Promise.resolve(mockUsers) + } + }; + + const mockPreselectedUsers = [ + { id: mockUsers[1].id, username: mockUsers[1].username }, + { id: mockUsers[2].id, username: mockUsers[2].username } + ]; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + CoreModule.forRoot(), + ProcessServiceCloudTestingModule, + StartTaskCloudModule + ], + providers: [ + IdentityUserService + ] + }) + .overrideComponent(PeopleCloudComponent, { + set: { + providers: [ + { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock } + ] + } + }).compileComponents(); + })); beforeEach(() => { fixture = TestBed.createComponent(PeopleCloudComponent); component = fixture.componentInstance; - element = fixture.nativeElement; identityService = TestBed.get(IdentityUserService); - findUsersSpy = spyOn(identityService, 'findUsersByName').and.returnValue(of(mockUsers)); - checkUserHasAccessSpy = spyOn(identityService, 'checkUserHasClientApp').and.returnValue(of(true)); - loadClientsByApplicationNameSpy = spyOn(identityService, 'getClientIdByApplicationName').and.returnValue(of('mock-client-id')); + alfrescoApiService = TestBed.get(AlfrescoApiService); }); it('should create PeopleCloudComponent', () => { - expect(component instanceof PeopleCloudComponent).toBeTruthy(); + expect(component instanceof PeopleCloudComponent).toBe(true, 'should create PeopleCloudComponent'); }); - it('should show the users if the typed result match', async(() => { - component.searchUsers$ = of( mockUsers); - fixture.detectChanges(); - const inputHTMLElement: HTMLInputElement = element.querySelector('input'); - inputHTMLElement.focus(); - inputHTMLElement.dispatchEvent(new Event('input')); - inputHTMLElement.dispatchEvent(new Event('keyup')); - inputHTMLElement.dispatchEvent(new Event('keydown')); - inputHTMLElement.value = 'M'; - fixture.detectChanges(); - fixture.whenStable().then(() => { + describe('Search user', () => { + + let findUsersByNameSpy: jasmine.Spy; + + beforeEach(async(() => { + spyOn(alfrescoApiService, 'getInstance').and.returnValue(mock); + findUsersByNameSpy = spyOn(identityService, 'findUsersByName').and.returnValue(of(mockUsers)); fixture.detectChanges(); - expect(fixture.debugElement.query(By.css('mat-option'))).toBeDefined(); - }); - })); + element = fixture.nativeElement; + })); - it('should hide result list if input is empty', async(() => { - fixture.detectChanges(); - const inputHTMLElement: HTMLInputElement = element.querySelector('input'); - inputHTMLElement.focus(); - inputHTMLElement.value = ''; - inputHTMLElement.dispatchEvent(new Event('keyup')); - inputHTMLElement.dispatchEvent(new Event('input')); - fixture.detectChanges(); - fixture.whenStable().then(() => { - expect(fixture.debugElement.query(By.css('mat-option'))).toBeNull(); - expect(fixture.debugElement.query(By.css('#adf-people-cloud-user-0'))).toBeNull(); + afterEach(() => { + fixture.destroy(); + TestBed.resetTestingModule(); }); - })); - it('should emit selectedUser if option is valid', async(() => { - fixture.detectChanges(); - const selectEmitSpy = spyOn(component.selectUser, 'emit'); - component.onSelect(new IdentityUserModel({ username: 'username' })); - fixture.whenStable().then(() => { - expect(selectEmitSpy).toHaveBeenCalled(); - }); - })); - - it('should show an error message if the user is invalid', async(() => { - checkUserHasAccessSpy.and.returnValue(of(false)); - findUsersSpy.and.returnValue(of([])); - fixture.detectChanges(); - const inputHTMLElement: HTMLInputElement = element.querySelector('input'); - inputHTMLElement.focus(); - inputHTMLElement.value = 'ZZZ'; - inputHTMLElement.dispatchEvent(new Event('input')); - fixture.detectChanges(); - fixture.whenStable().then(() => { - inputHTMLElement.blur(); + it('should list the users if the typed result match', async(() => { + const inputHTMLElement: HTMLInputElement = element.querySelector('input'); + inputHTMLElement.focus(); + inputHTMLElement.value = 'M'; + inputHTMLElement.dispatchEvent(new Event('input')); fixture.detectChanges(); - const errorMessage = element.querySelector('.adf-start-task-cloud-error-message'); - expect(errorMessage).not.toBeNull(); - expect(errorMessage.textContent).toContain('ADF_CLOUD_START_TASK.ERROR.MESSAGE'); - }); - })); + fixture.whenStable().then(() => { + fixture.detectChanges(); + component.searchUsers$.subscribe((res) => { + expect(res).toBeDefined(); + expect(res.length).toBe(3); + }); + expect(findUsersByNameSpy).toHaveBeenCalled(); + }); + })); - it('should show chip list when mode=multiple', async(() => { - component.mode = 'multiple'; - fixture.detectChanges(); - fixture.whenStable().then(() => { - const chip = element.querySelector('mat-chip-list'); - expect(chip).toBeDefined(); - }); - })); - - it('should not show chip list when mode=single', async(() => { - component.mode = 'single'; - fixture.detectChanges(); - fixture.whenStable().then(() => { - const chip = element.querySelector('mat-chip-list'); - expect(chip).toBeNull(); - }); - })); - - it('should pre-select all preSelectUsers when mode=multiple', async(() => { - spyOn(identityService, 'getUsersByRolesWithCurrentUser').and.returnValue(Promise.resolve(mockUsers)); - component.mode = 'multiple'; - component.preSelectUsers = [{ id: mockUsers[1].id }, { id: mockUsers[2].id }]; - fixture.detectChanges(); - fixture.whenStable().then(() => { + it('should hide result list if input is empty', async(() => { fixture.detectChanges(); - const chips = fixture.debugElement.queryAll(By.css('mat-chip')); - expect(chips.length).toBe(2); - }); - })); - - it('should not pre-select any user when preSelectUsers is empty and mode=multiple', async(() => { - spyOn(identityService, 'getUsersByRolesWithCurrentUser').and.returnValue(Promise.resolve(mockUsers)); - component.mode = 'multiple'; - fixture.detectChanges(); - fixture.whenStable().then(() => { + const inputHTMLElement: HTMLInputElement = element.querySelector('input'); + inputHTMLElement.focus(); + inputHTMLElement.value = ''; + inputHTMLElement.dispatchEvent(new Event('keyup')); + inputHTMLElement.dispatchEvent(new Event('input')); fixture.detectChanges(); - const chip = fixture.debugElement.query(By.css('mat-chip')); - expect(chip).toBeNull(); - }); - })); + fixture.whenStable().then(() => { + expect(element.querySelector('mat-option')).toBeNull(); + }); + })); - it('should pre-select preSelectUsers[0] when mode=single', async(() => { - spyOn(identityService, 'getUsersByRolesWithCurrentUser').and.returnValue(Promise.resolve(mockUsers)); - component.mode = 'single'; - component.preSelectUsers = [{ id: mockUsers[1].id }, { id: mockUsers[2].id }]; - fixture.detectChanges(); - fixture.whenStable().then(() => { + it('should emit selectedUser if option is valid', async(() => { + fixture.detectChanges(); + const selectEmitSpy = spyOn(component.selectUser, 'emit'); + component.onSelect(new IdentityUserModel({ username: 'username' })); + fixture.detectChanges(); + fixture.whenStable().then(() => { + expect(selectEmitSpy).toHaveBeenCalled(); + }); + })); + + it('should show an error message if the search result empty', async(() => { + findUsersByNameSpy.and.returnValue(of([])); + fixture.detectChanges(); + const inputHTMLElement: HTMLInputElement = element.querySelector('input'); + inputHTMLElement.focus(); + inputHTMLElement.value = 'ZZZ'; + inputHTMLElement.dispatchEvent(new Event('input')); + fixture.detectChanges(); + fixture.whenStable().then(() => { + inputHTMLElement.blur(); + fixture.detectChanges(); + const errorMessage = element.querySelector('.adf-start-task-cloud-error-message'); + expect(errorMessage).not.toBeNull(); + expect(errorMessage.textContent).toContain('ADF_CLOUD_START_TASK.ERROR.MESSAGE'); + }); + })); + }); + + describe('when application name defined', () => { + + let checkUserHasAccessSpy: jasmine.Spy; + let checkUserHasAnyClientAppRoleSpy: jasmine.Spy; + let findUsersByNameSpy: jasmine.Spy; + + beforeEach(async(() => { + spyOn(alfrescoApiService, 'getInstance').and.returnValue(mock); + findUsersByNameSpy = spyOn(identityService, 'findUsersByName').and.returnValue(of(mockUsers)); + checkUserHasAccessSpy = spyOn(identityService, 'checkUserHasClientApp').and.returnValue(of(true)); + checkUserHasAnyClientAppRoleSpy = spyOn(identityService, 'checkUserHasAnyClientAppRole').and.returnValue(of(true)); + component.preSelectUsers = []; + component.appName = 'mock-app-name'; + fixture.detectChanges(); + element = fixture.nativeElement; + })); + + afterEach(() => { + fixture.destroy(); + TestBed.resetTestingModule(); + }); + + it('should list users who have access to the app when appName is specified', async(() => { + const inputHTMLElement: HTMLInputElement = element.querySelector('input'); + inputHTMLElement.focus(); + inputHTMLElement.value = 'M'; + inputHTMLElement.dispatchEvent(new Event('input')); + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + component.searchUsers$.subscribe((res) => { + expect(res).toBeDefined(); + expect(res.length).toBe(3); + }); + }); + })); + + it('should not list users who do not have access to the app when appName is specified', async(() => { + checkUserHasAccessSpy.and.returnValue(of(false)); + fixture.detectChanges(); + const inputHTMLElement: HTMLInputElement = element.querySelector('input'); + inputHTMLElement.focus(); + inputHTMLElement.value = 'M'; + inputHTMLElement.dispatchEvent(new Event('input')); + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + component.searchUsers$.subscribe((res) => { + expect(res).toBeDefined(); + expect(res.length).toBe(0); + }); + }); + })); + + it('should list users if given roles mapped with client roles', async(() => { + component.roles = ['MOCK_ROLE_1', 'MOCK_ROLE_1']; + const inputHTMLElement: HTMLInputElement = element.querySelector('input'); + inputHTMLElement.focus(); + inputHTMLElement.value = 'M'; + inputHTMLElement.dispatchEvent(new Event('input')); + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + component.searchUsers$.subscribe((res) => { + expect(res).toBeDefined(); + expect(res.length).toBe(3); + }); + expect(checkUserHasAnyClientAppRoleSpy).toHaveBeenCalled(); + }); + })); + + it('should not list users if roles are not mapping with client roles', async(() => { + checkUserHasAnyClientAppRoleSpy.and.returnValue(of(false)); + component.roles = ['MOCK_ROLE_1', 'MOCK_ROLE_1']; + const inputHTMLElement: HTMLInputElement = element.querySelector('input'); + inputHTMLElement.focus(); + inputHTMLElement.value = 'M'; + inputHTMLElement.dispatchEvent(new Event('input')); + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + component.searchUsers$.subscribe((res) => { + expect(res).toBeDefined(); + expect(res.length).toBe(0); + }); + expect(checkUserHasAnyClientAppRoleSpy).toHaveBeenCalled(); + }); + })); + + it('should not call client role mapping sevice if roles not specified', async(() => { + const inputHTMLElement: HTMLInputElement = element.querySelector('input'); + inputHTMLElement.focus(); + inputHTMLElement.value = 'M'; + inputHTMLElement.dispatchEvent(new Event('input')); + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + expect(checkUserHasAnyClientAppRoleSpy).not.toHaveBeenCalled(); + }); + })); + + it('should validate access to the app when appName is specified', async(() => { + const inputHTMLElement: HTMLInputElement = element.querySelector('input'); + inputHTMLElement.focus(); + inputHTMLElement.value = 'M'; + inputHTMLElement.dispatchEvent(new Event('input')); + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + expect(checkUserHasAccessSpy).toHaveBeenCalledTimes(3); + }); + })); + + it('should not validate access to the app when appName is not specified', async(() => { + component.appName = ''; + fixture.detectChanges(); + const inputHTMLElement: HTMLInputElement = element.querySelector('input'); + inputHTMLElement.focus(); + inputHTMLElement.value = 'M'; + inputHTMLElement.dispatchEvent(new Event('input')); + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + expect(checkUserHasAccessSpy).not.toHaveBeenCalled(); + }); + })); + + it('should show an error message if the user does not have access', async(() => { + checkUserHasAccessSpy.and.returnValue(of(false)); + findUsersByNameSpy.and.returnValue(of([])); + fixture.detectChanges(); + const inputHTMLElement: HTMLInputElement = element.querySelector('input'); + inputHTMLElement.focus(); + inputHTMLElement.value = 'ZZZ'; + inputHTMLElement.dispatchEvent(new Event('input')); + fixture.detectChanges(); + fixture.whenStable().then(() => { + inputHTMLElement.blur(); + fixture.detectChanges(); + const errorMessage = element.querySelector('.adf-start-task-cloud-error-message'); + expect(errorMessage).not.toBeNull(); + expect(errorMessage.textContent).toContain('ADF_CLOUD_START_TASK.ERROR.MESSAGE'); + }); + })); + }); + + describe('When roles defined', () => { + + let checkUserHasRoleSpy: jasmine.Spy; + + beforeEach(async(() => { + component.roles = ['mock-role-1', 'mock-role-2']; + spyOn(alfrescoApiService, 'getInstance').and.returnValue(mock); + spyOn(identityService, 'findUsersByName').and.returnValue(of(mockUsers)); + checkUserHasRoleSpy = spyOn(identityService, 'checkUserHasRole').and.returnValue(of(true)); + fixture.detectChanges(); + element = fixture.nativeElement; + })); + + afterEach(() => { + fixture.destroy(); + TestBed.resetTestingModule(); + }); + + it('should filter users if users has any specified role', async(() => { + fixture.detectChanges(); + const inputHTMLElement: HTMLInputElement = element.querySelector('input'); + inputHTMLElement.focus(); + inputHTMLElement.value = 'M'; + inputHTMLElement.dispatchEvent(new Event('input')); + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + component.searchUsers$.subscribe((res) => { + expect(res).toBeDefined(); + expect(res.length).toEqual(3); + }); + expect(checkUserHasRoleSpy).toHaveBeenCalledTimes(3); + }); + })); + + it('should not filter users if user does not have any specified role', async(() => { + fixture.detectChanges(); + checkUserHasRoleSpy.and.returnValue(of(false)); + const inputHTMLElement: HTMLInputElement = element.querySelector('input'); + inputHTMLElement.focus(); + inputHTMLElement.value = 'M'; + inputHTMLElement.dispatchEvent(new Event('input')); + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + component.searchUsers$.subscribe((res) => { + expect(res).toBeDefined(); + expect(res.length).toEqual(0); + }); + expect(checkUserHasRoleSpy).toHaveBeenCalled(); + }); + })); + + it('should not call checkUserHasRole service when roles are not specified', async(() => { + component.roles = []; + fixture.detectChanges(); + const inputHTMLElement: HTMLInputElement = element.querySelector('input'); + inputHTMLElement.focus(); + inputHTMLElement.value = 'M'; + inputHTMLElement.dispatchEvent(new Event('input')); + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + expect(checkUserHasRoleSpy).not.toHaveBeenCalled(); + }); + })); + }); + + describe('Single Mode and Pre-selected users with no validate flag', () => { + + const change = new SimpleChange(null, mockPreselectedUsers, false); + + beforeEach(async(() => { + component.mode = 'single'; + component.preSelectUsers = mockPreselectedUsers; + fixture.detectChanges(); + element = fixture.nativeElement; + })); + + afterEach(() => { + fixture.destroy(); + TestBed.resetTestingModule(); + }); + + it('should not show chip list when mode=single', async(() => { + fixture.detectChanges(); + fixture.whenStable().then(() => { + const chip = element.querySelector('mat-chip-list'); + expect(chip).toBeNull(); + }); + })); + + it('should pre-select preSelectUsers[0] when mode=single', async(() => { + component.ngOnChanges({ 'preSelectUsers': change }); + fixture.detectChanges(); + fixture.whenStable().then(() => { + const selectedUser = component.searchUserCtrl.value; + expect(selectedUser.id).toBe(mockUsers[1].id); + }); + })); + it('should not pre-select any user when preSelectUsers is empty and mode=single', async(() => { + component.preSelectUsers = []; + fixture.detectChanges(); + fixture.whenStable().then(() => { + const selectedUser = component.searchUserCtrl.value; + expect(selectedUser).toBeNull(); + }); + })); + }); + + describe('Single Mode and Pre-selected users with validate flag', () => { + + const change = new SimpleChange(null, mockPreselectedUsers, false); + + beforeEach(async(() => { + component.mode = 'single'; + component.validate = true; + component.preSelectUsers = mockPreselectedUsers; + fixture.detectChanges(); + element = fixture.nativeElement; + })); + + afterEach(() => { + fixture.destroy(); + TestBed.resetTestingModule(); + }); + + it('should not show chip list when mode=single', async(() => { + fixture.detectChanges(); + fixture.whenStable().then(() => { + const chip = element.querySelector('mat-chip-list'); + expect(chip).toBeNull(); + }); + })); + + it('should pre-select preSelectUsers[0] when mode=single', fakeAsync(() => { + fixture.detectChanges(); + spyOn(component, 'searchUser').and.returnValue(Promise.resolve(mockPreselectedUsers)); + component.ngOnChanges({ 'preSelectUsers': change }); + fixture.detectChanges(); + tick(); const selectedUser = component.searchUserCtrl.value; expect(selectedUser.id).toBe(mockUsers[1].id); - }); - })); - - it('should not pre-select any user when preSelectUsers is empty and mode=single', async(() => { - spyOn(identityService, 'getUsersByRolesWithCurrentUser').and.returnValue(Promise.resolve(mockUsers)); - component.mode = 'single'; - fixture.detectChanges(); - fixture.whenStable().then(() => { - const selectedUser = component.searchUserCtrl.value; - expect(selectedUser).toBeNull(); - }); - })); - - it('should emit removeUser when a selected user is removed if mode=multiple', async(() => { - spyOn(identityService, 'getUsersByRolesWithCurrentUser').and.returnValue(Promise.resolve(mockUsers)); - const removeUserSpy = spyOn(component.removeUser, 'emit'); - - component.mode = 'multiple'; - component.preSelectUsers = [{ id: mockUsers[1].id }, { id: mockUsers[2].id }]; - fixture.detectChanges(); - - fixture.whenStable().then(() => { - fixture.detectChanges(); - const removeIcon = fixture.debugElement.query(By.css('mat-chip mat-icon')); - removeIcon.nativeElement.click(); - - expect(removeUserSpy).toHaveBeenCalledWith({ id: mockUsers[1].id }); - }); - - })); - - it('should list users who have access to the app when appName is specified', async(() => { - component.appName = 'sample-app'; - fixture.detectChanges(); - const inputHTMLElement: HTMLInputElement = element.querySelector('input'); - inputHTMLElement.focus(); - inputHTMLElement.value = 'M'; - inputHTMLElement.dispatchEvent(new Event('input')); - fixture.detectChanges(); - fixture.whenStable().then(() => { - fixture.detectChanges(); - const usersList = fixture.debugElement.queryAll(By.css('mat-option')); - expect(usersList.length).toBe(mockUsers.length); - }); - })); - - it('should not list users who do not have access to the app when appName is specified', async(() => { - checkUserHasAccessSpy.and.returnValue(of(false)); - component.appName = 'sample-app'; - - fixture.detectChanges(); - const inputHTMLElement: HTMLInputElement = element.querySelector('input'); - inputHTMLElement.focus(); - inputHTMLElement.value = 'M'; - inputHTMLElement.dispatchEvent(new Event('input')); - fixture.detectChanges(); - fixture.whenStable().then(() => { - fixture.detectChanges(); - const usersList = fixture.debugElement.queryAll(By.css('mat-option')); - expect(usersList.length).toBe(0); - }); - })); - - it('should validate access to the app when appName is specified', async(() => { - component.appName = 'sample-app'; - - fixture.detectChanges(); - const inputHTMLElement: HTMLInputElement = element.querySelector('input'); - inputHTMLElement.focus(); - inputHTMLElement.value = 'M'; - inputHTMLElement.dispatchEvent(new Event('input')); - fixture.detectChanges(); - fixture.whenStable().then(() => { - fixture.detectChanges(); - expect(checkUserHasAccessSpy).toHaveBeenCalledTimes(mockUsers.length); - }); - })); - - it('should not validate access to the app when appName is not specified', async(() => { - fixture.detectChanges(); - const inputHTMLElement: HTMLInputElement = element.querySelector('input'); - inputHTMLElement.focus(); - inputHTMLElement.value = 'M'; - inputHTMLElement.dispatchEvent(new Event('input')); - fixture.detectChanges(); - fixture.whenStable().then(() => { - fixture.detectChanges(); - expect(checkUserHasAccessSpy).not.toHaveBeenCalled(); - }); - })); - - it('should return true if user has any specified role', async(() => { - const checkUserHasRoleSpy = spyOn(identityService, 'checkUserHasRole').and.returnValue(of(true)); - component.roles = ['mock-role-1']; - fixture.detectChanges(); - const inputHTMLElement: HTMLInputElement = element.querySelector('input'); - inputHTMLElement.focus(); - inputHTMLElement.value = 'M'; - inputHTMLElement.dispatchEvent(new Event('input')); - fixture.detectChanges(); - fixture.whenStable().then(() => { - fixture.detectChanges(); - expect(checkUserHasRoleSpy).toHaveBeenCalled(); - }); - })); - - it('should return false if user does not have any specified role', async(() => { - const checkUserHasRoleSpy = spyOn(identityService, 'checkUserHasRole').and.returnValue(of(false)); - component.appName = ''; - component.roles = ['mock-role-10']; - fixture.detectChanges(); - const inputHTMLElement: HTMLInputElement = element.querySelector('input'); - inputHTMLElement.focus(); - inputHTMLElement.value = 'M'; - inputHTMLElement.dispatchEvent(new Event('input')); - fixture.detectChanges(); - fixture.whenStable().then(() => { - fixture.detectChanges(); - expect(checkUserHasRoleSpy).toHaveBeenCalled(); - }); - })); - - it('should not fire checkUserHasRole when roles are not specified', async(() => { - const checkUserHasRoleSpy = spyOn(identityService, 'checkUserHasRole').and.returnValue(of(false)); - component.appName = ''; - component.roles = []; - fixture.detectChanges(); - const inputHTMLElement: HTMLInputElement = element.querySelector('input'); - inputHTMLElement.focus(); - inputHTMLElement.value = 'M'; - inputHTMLElement.dispatchEvent(new Event('input')); - fixture.detectChanges(); - fixture.whenStable().then(() => { - fixture.detectChanges(); - expect(checkUserHasRoleSpy).not.toHaveBeenCalled(); - }); - })); - - it('should load the clients if appName change', async(() => { - component.appName = 'ADF'; - fixture.detectChanges(); - fixture.whenStable().then(() => { - fixture.detectChanges(); - expect(loadClientsByApplicationNameSpy).toHaveBeenCalled(); - }); - })); - - it('should filter users if appName change', async(() => { - component.appName = ''; - fixture.detectChanges(); - component.appName = 'ADF'; - fixture.detectChanges(); - fixture.whenStable().then(() => { - fixture.detectChanges(); - expect(checkUserHasAccessSpy).toHaveBeenCalled(); - }); - })); - - it('should not validate preselect values if preselectValidation flag is set to false', () => { - component.mode = 'multiple'; - component.preSelectUsers = [{ id: mockUsers[1].id }, { id: mockUsers[2].id }]; - const change = new SimpleChange(null, 'validate', false); - component.ngOnChanges({'validate': change}); - fixture.whenStable().then(() => { - fixture.detectChanges(); - expect(component.validatePreselectUsers).not.toHaveBeenCalled(); - }); + })); }); - it('should filter users when validation flag is true', async(() => { - component.mode = 'multiple'; - component.validate = true; - component.preSelectUsers = [{ id: mockUsers[1].id }, { id: mockUsers[2].id }]; - fixture.detectChanges(); - fixture.whenStable().then(() => { - component.filterPreselectUsers().then((result) => { - expect(component.userExists(result)).toEqual(false); - }); - }); - })); + describe('Multiple Mode and Pre-selected users with no validate flag', () => { - it('should emit warning if are invalid users', async((done) => { - const warningSpy = spyOn(component.warning, 'emit').and.returnValue(of(false)); - component.mode = 'single'; + const change = new SimpleChange(null, mockPreselectedUsers, false); + + beforeEach(async(() => { + component.mode = 'multiple'; + component.preSelectUsers = mockPreselectedUsers; + fixture.detectChanges(); + element = fixture.nativeElement; + })); + + afterEach(() => { + fixture.destroy(); + TestBed.resetTestingModule(); + }); + + it('should show chip list when mode=multiple', async(() => { + fixture.detectChanges(); + fixture.whenStable().then(() => { + const chip = element.querySelector('mat-chip-list'); + expect(chip).toBeDefined(); + }); + })); + + it('should pre-select all preSelectUsers when mode=multiple', async(() => { + component.mode = 'multiple'; + component.ngOnChanges({ 'preSelectUsers': change }); + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + component.selectedUsers$.subscribe((selectedUsers) => { + expect(selectedUsers).toBeDefined(); + expect(selectedUsers.length).toEqual(2); + expect(selectedUsers[0].id).toEqual('fake-id-2'); + }); + }); + })); + }); + + describe('Multiple Mode and Pre-selected users with validate flag', () => { + + const change = new SimpleChange(null, mockPreselectedUsers, false); + + beforeEach(async(() => { + component.mode = 'multiple'; + component.validate = true; + component.preSelectUsers = mockPreselectedUsers; + fixture.detectChanges(); + element = fixture.nativeElement; + })); + + afterEach(() => { + fixture.destroy(); + TestBed.resetTestingModule(); + }); + + it('should show chip list when mode=multiple', async(() => { + fixture.detectChanges(); + fixture.whenStable().then(() => { + const chip = element.querySelector('mat-chip-list'); + expect(chip).toBeDefined(); + }); + })); + + it('should pre-select all preSelectUsers when mode=multiple', async(() => { + fixture.detectChanges(); + spyOn(component, 'searchUser').and.returnValue(Promise.resolve(mockPreselectedUsers)); + component.mode = 'multiple'; + component.ngOnChanges({ 'preSelectUsers': change }); + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + const chips = fixture.debugElement.queryAll(By.css('mat-chip')); + expect(chips.length).toBe(2); + }); + })); + + it('should emit removeUser when a selected user is removed if mode=multiple', async(() => { + fixture.detectChanges(); + const removeUserSpy = spyOn(component.removeUser, 'emit'); + component.mode = 'multiple'; + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + const removeIcon = fixture.debugElement.query(By.css('mat-chip mat-icon')); + removeIcon.nativeElement.click(); + expect(removeUserSpy).toHaveBeenCalled(); + }); + })); + }); + + it('should emit warning if are invalid users', (done) => { + spyOn(identityService, 'findUserByUsername').and.returnValue(Promise.resolve([])); + const warnMessage = { message: 'INVALID_PRESELECTED_USERS', users: [{ username: 'invalidUsername' }] }; component.validate = true; component.preSelectUsers = [{ username: 'invalidUsername' }]; fixture.detectChanges(); - fixture.whenStable().then(() => { - component.loadSinglePreselectUser().then((result) => { - fixture.detectChanges(); - expect(warningSpy).toHaveBeenCalled(); - }); + component.loadSinglePreselectUser(); + component.warning.subscribe((response) => { + expect(response).toEqual(warnMessage); + expect(response.message).toEqual(warnMessage.message); + expect(response.users).toEqual(warnMessage.users); + expect(response.users[0].username).toEqual('invalidUsername'); + done(); }); - })); + }); - it('should filter user by id if validate true', async((done) => { + it('should filter user by id if validate true', async(() => { const findByIdSpy = spyOn(identityService, 'findUserById').and.returnValue(Promise.resolve(mockUsers)); component.mode = 'multiple'; component.validate = true; @@ -364,12 +556,11 @@ describe('PeopleCloudComponent', () => { component.filterPreselectUsers().then((result) => { expect(findByIdSpy).toHaveBeenCalled(); expect(component.userExists(result)).toEqual(true); - done(); }); }); })); - it('should filter user by username if validate true', async((done) => { + it('should filter user by username if validate true', async(() => { const findUserByUsernameSpy = spyOn(identityService, 'findUserByUsername').and.returnValue(Promise.resolve(mockUsers)); component.mode = 'multiple'; component.validate = true; @@ -379,12 +570,11 @@ describe('PeopleCloudComponent', () => { component.filterPreselectUsers().then((result) => { expect(findUserByUsernameSpy).toHaveBeenCalled(); expect(component.userExists(result)).toEqual(true); - done(); }); }); })); - it('should filter user by email if validate true', async((done) => { + it('should filter user by email if validate true', async(() => { const findUserByEmailSpy = spyOn(identityService, 'findUserByEmail').and.returnValue(Promise.resolve(mockUsers)); component.mode = 'multiple'; component.validate = true; @@ -394,27 +584,7 @@ describe('PeopleCloudComponent', () => { component.filterPreselectUsers().then((result) => { expect(findUserByEmailSpy).toHaveBeenCalled(); expect(component.userExists(result)).toEqual(true); - done(); }); }); })); - - it('should not filter the preselect user in single selection mode', async ((done) => { - spyOn(identityService, 'findUserByUsername').and.returnValue(Promise.resolve(mockUsers)); - component.mode = 'single'; - component.validate = true; - component.preSelectUsers = [{ username: mockUsers[1].username }]; - fixture.detectChanges(); - const inputHTMLElement: HTMLInputElement = element.querySelector('input'); - inputHTMLElement.focus(); - inputHTMLElement.dispatchEvent(new Event('input')); - inputHTMLElement.dispatchEvent(new Event('keyup')); - inputHTMLElement.dispatchEvent(new Event('keydown')); - inputHTMLElement.value = mockUsers[1].username; - fixture.detectChanges(); - fixture.whenStable().then(() => { - fixture.detectChanges(); - expect(fixture.debugElement.queryAll(By.css('mat-option')).length).toBe(3); - }); - })); }); diff --git a/lib/process-services-cloud/src/lib/task/start-task/components/people-cloud/people-cloud.component.ts b/lib/process-services-cloud/src/lib/task/start-task/components/people-cloud/people-cloud.component.ts index c91f63b91d..af01e43337 100644 --- a/lib/process-services-cloud/src/lib/task/start-task/components/people-cloud/people-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/task/start-task/components/people-cloud/people-cloud.component.ts @@ -118,10 +118,12 @@ export class PeopleCloudComponent implements OnInit, OnChanges { ngOnChanges(changes: SimpleChanges) { this.initSubjects(); - if (this.isPreselectedUserChanged(changes) && this.isValidationEnabled()) { - this.loadPreSelectUsers(); - } else { - this.loadNoValidationPreselctUsers(); + if (this.isPreselectedUserChanged(changes)) { + if (this.isValidationEnabled()) { + this.loadPreSelectUsers(); + } else { + this.loadNoValidationPreselctUsers(); + } } if (changes.appName && this.isAppNameChanged(changes.appName)) { @@ -160,7 +162,7 @@ export class PeopleCloudComponent implements OnInit, OnChanges { async validatePreselectUsers(): Promise { this.invalidUsers = []; - let filteredPreSelectUsers: IdentityUserModel[]; + let filteredPreSelectUsers: { isValid: boolean, user: IdentityUserModel } []; try { filteredPreSelectUsers = await this.filterPreselectUsers(); @@ -169,11 +171,11 @@ export class PeopleCloudComponent implements OnInit, OnChanges { this.logService.error(error); } - return filteredPreSelectUsers.reduce((validUsers, user: IdentityUserModel) => { - if (this.userExists(user)) { - validUsers.push(user); + return filteredPreSelectUsers.reduce((validUsers, validatedUser: any) => { + if (validatedUser.isValid) { + validUsers.push(validatedUser.user); } else { - this.invalidUsers.push(user); + this.invalidUsers.push(validatedUser.user); } return validUsers; }, []); @@ -182,15 +184,14 @@ export class PeopleCloudComponent implements OnInit, OnChanges { async filterPreselectUsers() { const promiseBatch = this.preSelectUsers.map(async (user: IdentityUserModel) => { let result: any; - try { result = await this.searchUser(user); } catch (error) { result = []; this.logService.error(error); } - const isUserValid: Boolean = this.userExists(result); - return isUserValid ? new IdentityUserModel(result[0]) : user; + const isUserValid: boolean = this.userExists(result); + return isUserValid ? { isValid: isUserValid, user: new IdentityUserModel(user) } : { isValid: isUserValid, user: user }; }); return await Promise.all(promiseBatch); } @@ -205,11 +206,8 @@ export class PeopleCloudComponent implements OnInit, OnChanges { } } - public userExists(result: any) { - return result.length > 0 || - result.id !== undefined || - result.username !== undefined || - result.amil !== undefined; + public userExists(result: any): boolean { + return result && result.length > 0; } private initSearch() { @@ -241,6 +239,7 @@ export class PeopleCloudComponent implements OnInit, OnChanges { }), mergeMap((user: any) => { if (this.appName) { + return this.checkUserHasAccess(user.id).pipe( mergeMap((hasRole) => { return hasRole ? of(user) : of(); @@ -309,15 +308,23 @@ export class PeopleCloudComponent implements OnInit, OnChanges { public async loadSinglePreselectUser() { const users = await this.validatePreselectUsers(); - this.checkPreselectValidationErrors(); - this.searchUserCtrl.setValue(users[0]); + if (users && users.length > 0) { + this.checkPreselectValidationErrors(); + this.searchUserCtrl.setValue(users[0]); + } else { + this.checkPreselectValidationErrors(); + } } public async loadMultiplePreselectUsers() { const users = await this.validatePreselectUsers(); - this.checkPreselectValidationErrors(); - this.preSelectUsers = [...users]; - this.selectedUsersSubject.next(users); + if (users && users.length > 0) { + this.checkPreselectValidationErrors(); + this.preSelectUsers = [...users]; + this.selectedUsersSubject.next(users); + } else { + this.checkPreselectValidationErrors(); + } } public checkPreselectValidationErrors() { diff --git a/lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.spec.ts index b2db6f5b46..c50bc2dae9 100644 --- a/lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.spec.ts @@ -95,7 +95,7 @@ describe('TaskHeaderCloudComponent', () => { fixture.whenStable().then(() => { const valueEl = fixture.debugElement.query(By.css('[data-automation-id="header-dueDate"] .adf-property-value')); - expect(valueEl.nativeElement.innerText.trim()).toBe('Dec 18 2018'); + expect(valueEl.nativeElement.innerText.trim()).toBe('18-12-2018'); }); }));