[ADF-5034] [GroupCloudComponent] Provide a way to make pre-selected groups read-only. (#5306)

* Added readonly property to the IdentityGroupModel.
* Updated unit tests.
* Changed class to interface.
* Updated doc
This commit is contained in:
siva kumar
2019-12-04 18:56:56 +05:30
committed by Maurizio Vitale
parent c01f2744b6
commit cc4c9bc567
7 changed files with 493 additions and 291 deletions

View File

@@ -92,3 +92,35 @@ export class MyComponent {
[preSelectGroups]="groups"> [preSelectGroups]="groups">
</adf-cloud-group> </adf-cloud-group>
``` ```
### Read-only
You can use `readonly` property to make preselected groups read-only in `multiple` mode.
Usage example:
```ts
import { ObjectDataTableAdapter } from '@alfresco/adf-core';
@Component({...})
export class MyComponent {
groups: any;
constructor() {
this.groups =
[
{id: 1, name: 'Group 1', readonly: true},
{id: 2, name: 'Group 2', readonly: false}
];
}
}
```
```html
<adf-cloud-group
[mode]="'multiple'"
[preSelectGroups]="groups">
</adf-cloud-group>
```
from above `preSelectGroups`, `Group 2` is removable from the `preSelectGroups` whereas `Group 1` is readonly you can not remove them.

View File

@@ -18,30 +18,30 @@
import { IdentityGroupModel, IdentityGroupCountModel } from '../models/identity-group.model'; import { IdentityGroupModel, IdentityGroupCountModel } from '../models/identity-group.model';
import { IdentityRoleModel } from '../models/identity-role.model'; import { IdentityRoleModel } from '../models/identity-role.model';
export let mockIdentityGroup1 = new IdentityGroupModel({ export let mockIdentityGroup1 = <IdentityGroupModel> {
id: 'mock-group-id-1', name: 'Mock Group 1', path: '/mock', subGroups: [] id: 'mock-group-id-1', name: 'Mock Group 1', path: '/mock', subGroups: []
}); };
export let mockIdentityGroup2 = new IdentityGroupModel({ export let mockIdentityGroup2 = <IdentityGroupModel> {
id: 'mock-group-id-2', name: 'Mock Group 2', path: '', subGroups: [] id: 'mock-group-id-2', name: 'Mock Group 2', path: '', subGroups: []
}); };
export let mockIdentityGroup3 = new IdentityGroupModel({ export let mockIdentityGroup3 = <IdentityGroupModel> {
id: 'mock-group-id-3', name: 'Mock Group 3', path: '', subGroups: [] id: 'mock-group-id-3', name: 'Mock Group 3', path: '', subGroups: []
}); };
export let mockIdentityGroup4 = new IdentityGroupModel({ export let mockIdentityGroup4 = <IdentityGroupModel> {
id: 'mock-group-id-4', name: 'Mock Group 4', path: '', subGroups: [] id: 'mock-group-id-4', name: 'Mock Group 4', path: '', subGroups: []
}); };
export let mockIdentityGroup5 = new IdentityGroupModel({ export let mockIdentityGroup5 = <IdentityGroupModel> {
id: 'mock-group-id-5', name: 'Mock Group 5', path: '', subGroups: [] id: 'mock-group-id-5', name: 'Mock Group 5', path: '', subGroups: []
}); };
export let mockIdentityGroupsCount = <IdentityGroupCountModel> { count: 10 }; export let mockIdentityGroupsCount = <IdentityGroupCountModel> { count: 10 };
export let mockIdentityGroups = [ export let mockIdentityGroups = [
mockIdentityGroup1, mockIdentityGroup2, mockIdentityGroup3, mockIdentityGroup5, mockIdentityGroup5 mockIdentityGroup1, mockIdentityGroup2, mockIdentityGroup3, mockIdentityGroup4, mockIdentityGroup5
]; ];
export let mockApplicationDetails = {id: 'mock-app-id', name: 'mock-app-name'}; export let mockApplicationDetails = {id: 'mock-app-id', name: 'mock-app-name'};

View File

@@ -57,17 +57,17 @@ export const mockEffectiveRoles = [
export const mockJoinGroupRequest: IdentityJoinGroupRequestModel = {userId: 'mock-hser-id', groupId: 'mock-group-id', realm: 'mock-realm-name'}; export const mockJoinGroupRequest: IdentityJoinGroupRequestModel = {userId: 'mock-hser-id', groupId: 'mock-group-id', realm: 'mock-realm-name'};
export const mockGroup1 = new IdentityGroupModel({ export const mockGroup1 = <IdentityGroupModel> {
id: 'mock-group-id-1', name: 'Mock Group 1', path: '/mock', subGroups: [] id: 'mock-group-id-1', name: 'Mock Group 1', path: '/mock', subGroups: []
}); };
export const mockGroup2 = new IdentityGroupModel({ export const mockGroup2 = <IdentityGroupModel> {
id: 'mock-group-id-2', name: 'Mock Group 2', path: '', subGroups: [] id: 'mock-group-id-2', name: 'Mock Group 2', path: '', subGroups: []
}); };
export const mockGroups = [ export const mockGroups = [
new IdentityGroupModel({ id: 'mock-group-id-1', name: 'Mock Group 1', path: '/mock', subGroups: [] }), <IdentityGroupModel> { id: 'mock-group-id-1', name: 'Mock Group 1', path: '/mock', subGroups: [] },
new IdentityGroupModel({ id: 'mock-group-id-2', name: 'Mock Group 2', path: '', subGroups: [] }) <IdentityGroupModel> { id: 'mock-group-id-2', name: 'Mock Group 2', path: '', subGroups: [] }
]; ];
export const queryUsersMockApi = { export const queryUsersMockApi = {

View File

@@ -17,27 +17,15 @@
import { Pagination } from '@alfresco/js-api'; import { Pagination } from '@alfresco/js-api';
export class IdentityGroupModel { export interface IdentityGroupModel {
id?: string;
id: string; name?: string;
name: string; path?: string;
path: string; realmRoles?: string[];
realmRoles: string[]; clientRoles?: any;
clientRoles: any; access?: any;
access: any; attributes?: any;
attributes: any; readonly?: boolean;
constructor(obj?: any) {
if (obj) {
this.id = obj.id || null;
this.name = obj.name || null;
this.path = obj.path || null;
this.realmRoles = obj.realmRoles || null;
this.clientRoles = obj.clientRoles || null;
this.access = obj.access || null;
this.attributes = obj.attributes || null;
}
}
} }
export interface IdentityGroupSearchParam { export interface IdentityGroupSearchParam {
@@ -50,17 +38,9 @@ export interface IdentityGroupQueryResponse {
pagination: Pagination; pagination: Pagination;
} }
export class IdentityGroupQueryCloudRequestModel { export interface IdentityGroupQueryCloudRequestModel {
first: number; first: number;
max: number; max: number;
constructor(obj?: any) {
if (obj) {
this.first = obj.first;
this.max = obj.max;
}
}
} }
export interface IdentityGroupCountModel { export interface IdentityGroupCountModel {

View File

@@ -4,10 +4,14 @@
<mat-chip-list #groupChipList *ngIf="isMultipleMode()" [disabled]="isDisabled" data-automation-id="adf-cloud-group-chip-list" class="apa-group-chip-list"> <mat-chip-list #groupChipList *ngIf="isMultipleMode()" [disabled]="isDisabled" data-automation-id="adf-cloud-group-chip-list" class="apa-group-chip-list">
<mat-chip <mat-chip
*ngFor="let group of selectedGroups$ | async" *ngFor="let group of selectedGroups$ | async"
[removable]="!(group.readonly)"
(removed)="onRemove(group)" (removed)="onRemove(group)"
[attr.data-automation-id]="'adf-cloud-group-chip-' + group.name"> [attr.data-automation-id]="'adf-cloud-group-chip-' + group.name">
{{group.name}} {{group.name}}
<mat-icon matChipRemove>cancel</mat-icon> <mat-icon
matChipRemove [attr.data-automation-id]="'adf-cloud-group-chip-remove-icon-' + group.name">
cancel
</mat-icon>
</mat-chip> </mat-chip>
<input matInput <input matInput
[formControl]="searchGroupsControl" [formControl]="searchGroupsControl"

View File

@@ -24,10 +24,10 @@ import { GroupCloudModule } from '../group-cloud.module';
import { GroupCloudComponent } from './group-cloud.component'; import { GroupCloudComponent } from './group-cloud.component';
import { import {
setupTestBed, setupTestBed,
AlfrescoApiServiceMock,
IdentityGroupService, IdentityGroupService,
IdentityGroupModel, mockIdentityGroups,
mockIdentityGroups AlfrescoApiService,
CoreModule
} from '@alfresco/adf-core'; } from '@alfresco/adf-core';
import { SimpleChange } from '@angular/core'; import { SimpleChange } from '@angular/core';
@@ -35,61 +35,64 @@ describe('GroupCloudComponent', () => {
let component: GroupCloudComponent; let component: GroupCloudComponent;
let fixture: ComponentFixture<GroupCloudComponent>; let fixture: ComponentFixture<GroupCloudComponent>;
let element: HTMLElement; let element: HTMLElement;
let service: IdentityGroupService; let identityGroupService: IdentityGroupService;
let alfrescoApiService: AlfrescoApiService;
let findGroupsByNameSpy: jasmine.Spy; let findGroupsByNameSpy: jasmine.Spy;
let getClientIdByApplicationNameSpy: jasmine.Spy;
let checkGroupHasAccessSpy: jasmine.Spy; const mock = {
let checkGroupHasGivenRoleSpy: jasmine.Spy; oauth2Auth: {
callCustomApi: () => Promise.resolve(mockIdentityGroups)
}
};
setupTestBed({ setupTestBed({
imports: [ProcessServiceCloudTestingModule, GroupCloudModule], imports: [
providers: [AlfrescoApiServiceMock, IdentityGroupService] CoreModule.forRoot(),
ProcessServiceCloudTestingModule,
GroupCloudModule],
providers: [
IdentityGroupService
]
}); });
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(GroupCloudComponent); fixture = TestBed.createComponent(GroupCloudComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
element = fixture.nativeElement; element = fixture.nativeElement;
service = TestBed.get(IdentityGroupService); identityGroupService = TestBed.get(IdentityGroupService);
findGroupsByNameSpy = spyOn(service, 'findGroupsByName').and.returnValue(of(mockIdentityGroups)); alfrescoApiService = TestBed.get(AlfrescoApiService);
getClientIdByApplicationNameSpy = spyOn(service, 'getClientIdByApplicationName').and.returnValue(of('mock-client-id')); spyOn(alfrescoApiService, 'getInstance').and.returnValue(mock);
checkGroupHasAccessSpy = spyOn(service, 'checkGroupHasClientApp').and.returnValue(of(true));
checkGroupHasGivenRoleSpy = spyOn(service, 'checkGroupHasRole').and.returnValue(of(true));
component.appName = 'mock-app-name';
}); });
it('should create GroupCloudComponent', () => { it('should create GroupCloudComponent', () => {
expect(component instanceof GroupCloudComponent).toBeTruthy(); expect(component instanceof GroupCloudComponent).toBeTruthy();
}); });
it('should be able to fetch client id', async(() => { describe('Search group', () => {
component.ngOnChanges( {
appName: new SimpleChange(null, component.appName, true) beforeEach(async(() => {
});
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { element = fixture.nativeElement;
expect(getClientIdByApplicationNameSpy).toHaveBeenCalled(); findGroupsByNameSpy = spyOn(identityGroupService, 'findGroupsByName').and.returnValue(of(mockIdentityGroups));
expect(component.clientId).toBe('mock-client-id');
});
})); }));
it('should show the groups if the typed result match', async(() => { it('should list the group if the typed result match', (done) => {
fixture.detectChanges(); findGroupsByNameSpy.and.returnValue(of(mockIdentityGroups));
component.searchGroups$.next(<IdentityGroupModel[]> mockIdentityGroups);
const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input'); const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input');
inputHTMLElement.focus(); inputHTMLElement.focus();
inputHTMLElement.dispatchEvent(new Event('input')); inputHTMLElement.value = 'Mock';
inputHTMLElement.dispatchEvent(new Event('keyup')); inputHTMLElement.dispatchEvent(new Event('keyup'));
inputHTMLElement.dispatchEvent(new Event('keydown')); inputHTMLElement.dispatchEvent(new Event('input'));
inputHTMLElement.value = 'M';
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
fixture.detectChanges(); fixture.detectChanges();
expect(fixture.debugElement.query(By.css('mat-option'))).toBeDefined(); expect(fixture.debugElement.queryAll(By.css('mat-option')).length).toEqual(5);
expect(findGroupsByNameSpy).toHaveBeenCalled();
done();
});
}); });
}));
it('should hide result list if input is empty', async(() => { it('should hide result list if input is empty', (done) => {
fixture.detectChanges(); fixture.detectChanges();
const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input'); const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input');
inputHTMLElement.focus(); inputHTMLElement.focus();
@@ -98,148 +101,299 @@ describe('GroupCloudComponent', () => {
inputHTMLElement.dispatchEvent(new Event('input')); inputHTMLElement.dispatchEvent(new Event('input'));
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
expect(fixture.debugElement.query(By.css('mat-option'))).toBeNull(); expect(element.querySelector('mat-option')).toBeNull();
expect(fixture.debugElement.query(By.css('#adf-group-0'))).toBeNull(); done();
});
}); });
}));
it('should emit selectedGroup if option is valid', async(() => { it('should emit selectedGroup if option is valid', (done) => {
fixture.detectChanges(); fixture.detectChanges();
const selectEmitSpy = spyOn(component.selectGroup, 'emit'); const selectEmitSpy = spyOn(component.selectGroup, 'emit');
component.onSelect(new IdentityGroupModel({ name: 'group name'})); component.onSelect({ name: 'groupname' });
fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
expect(selectEmitSpy).toHaveBeenCalled(); expect(selectEmitSpy).toHaveBeenCalled();
done();
});
}); });
}));
it('should show an error message if the group is invalid', async(() => { it('should show an error message if the search result empty', (done) => {
fixture.detectChanges();
checkGroupHasAccessSpy.and.returnValue(of(false));
findGroupsByNameSpy.and.returnValue(of([])); findGroupsByNameSpy.and.returnValue(of([]));
fixture.detectChanges(); fixture.detectChanges();
const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input'); const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input');
inputHTMLElement.focus(); inputHTMLElement.focus();
inputHTMLElement.value = 'ZZZ'; inputHTMLElement.value = 'ZZZ';
inputHTMLElement.dispatchEvent(new Event('keyup'));
inputHTMLElement.dispatchEvent(new Event('input'));
fixture.detectChanges();
fixture.whenStable().then(() => {
inputHTMLElement.blur();
fixture.detectChanges();
const errorMessage = element.querySelector('.adf-cloud-group-error-message');
expect(errorMessage).not.toBeNull();
expect(errorMessage.textContent).toContain(' ADF_CLOUD_GROUPS.ERROR.NOT_FOUND ');
done();
});
});
it('should populate placeholder when title is present', (done) => {
component.title = 'TITLE_KEY';
fixture.detectChanges();
const matLabel: HTMLInputElement = <HTMLInputElement> element.querySelector('mat-label');
fixture.whenStable().then( () => {
fixture.detectChanges();
expect(matLabel.textContent).toEqual('TITLE_KEY');
done();
});
});
});
describe('when application name defined', () => {
let checkGroupHasAnyClientAppRoleSpy: jasmine.Spy;
let checkGroupHasClientAppSpy: jasmine.Spy;
beforeEach(async(() => {
findGroupsByNameSpy = spyOn(identityGroupService, 'findGroupsByName').and.returnValue(of(mockIdentityGroups));
checkGroupHasAnyClientAppRoleSpy = spyOn(identityGroupService, 'checkGroupHasAnyClientAppRole').and.returnValue(of(true));
checkGroupHasClientAppSpy = spyOn(identityGroupService, 'checkGroupHasClientApp').and.returnValue(of(true));
component.preSelectGroups = [];
component.appName = 'mock-app-name';
fixture.detectChanges();
element = fixture.nativeElement;
}));
it('should fetch the client ID if appName specified', async(() => {
const getClientIdByApplicationNameSpy = spyOn(identityGroupService, 'getClientIdByApplicationName').and.callThrough();
component.appName = 'mock-app-name';
const change = new SimpleChange(null, 'mock-app-name', false);
component.ngOnChanges({ 'appName': change });
fixture.detectChanges();
fixture.whenStable().then( () => {
fixture.detectChanges();
expect(getClientIdByApplicationNameSpy).toHaveBeenCalled();
});
}));
it('should list groups who have access to the app when appName is specified', (done) => {
const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input');
inputHTMLElement.focus();
inputHTMLElement.value = 'M';
inputHTMLElement.dispatchEvent(new Event('keyup'));
inputHTMLElement.dispatchEvent(new Event('input')); inputHTMLElement.dispatchEvent(new Event('input'));
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
fixture.detectChanges();
expect(fixture.debugElement.queryAll(By.css('mat-option')).length).toEqual(5);
done();
});
});
it('should not list groups who do not have access to the app when appName is specified', (done) => {
checkGroupHasClientAppSpy.and.returnValue(of(false));
fixture.detectChanges();
const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input');
inputHTMLElement.focus();
inputHTMLElement.value = 'M';
inputHTMLElement.dispatchEvent(new Event('keyup'));
inputHTMLElement.dispatchEvent(new Event('input'));
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(element.querySelectorAll('mat-option').length).toEqual(0);
done();
});
});
it('should list groups if given roles mapped with client roles', (done) => {
component.roles = ['MOCK_ROLE_1', 'MOCK_ROLE_1'];
const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input');
inputHTMLElement.focus();
inputHTMLElement.value = 'M';
inputHTMLElement.dispatchEvent(new Event('keyup'));
inputHTMLElement.dispatchEvent(new Event('input'));
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(fixture.debugElement.queryAll(By.css('mat-option')).length).toEqual(5);
expect(checkGroupHasAnyClientAppRoleSpy).toHaveBeenCalled();
done();
});
});
it('should not list groups if roles are not mapping with client roles', (done) => {
checkGroupHasAnyClientAppRoleSpy.and.returnValue(of(false));
component.roles = ['MOCK_ROLE_1', 'MOCK_ROLE_1'];
const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input');
inputHTMLElement.focus();
inputHTMLElement.value = 'M';
inputHTMLElement.dispatchEvent(new Event('keyup'));
inputHTMLElement.dispatchEvent(new Event('input'));
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(fixture.debugElement.queryAll(By.css('mat-option')).length).toEqual(0);
expect(checkGroupHasAnyClientAppRoleSpy).toHaveBeenCalled();
done();
});
});
it('should not call client role mapping sevice if roles not specified', (done) => {
const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input');
inputHTMLElement.focus();
inputHTMLElement.value = 'M';
inputHTMLElement.dispatchEvent(new Event('keyup'));
inputHTMLElement.dispatchEvent(new Event('input'));
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(checkGroupHasAnyClientAppRoleSpy).not.toHaveBeenCalled();
done();
});
});
it('should validate access to the app when appName is specified', (done) => {
const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input');
inputHTMLElement.focus();
inputHTMLElement.value = 'M';
inputHTMLElement.dispatchEvent(new Event('keyup'));
inputHTMLElement.dispatchEvent(new Event('input'));
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(checkGroupHasClientAppSpy).toHaveBeenCalledTimes(5);
done();
});
});
it('should not validate access to the app when appName is not specified', (done) => {
component.appName = '';
fixture.detectChanges();
const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input');
inputHTMLElement.focus();
inputHTMLElement.value = 'M';
inputHTMLElement.dispatchEvent(new Event('keyup'));
inputHTMLElement.dispatchEvent(new Event('input'));
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(checkGroupHasClientAppSpy).not.toHaveBeenCalled();
done();
});
});
it('should show an error message if the group does not have access', (done) => {
checkGroupHasClientAppSpy.and.returnValue(of(false));
findGroupsByNameSpy.and.returnValue(of([]));
fixture.detectChanges();
const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input');
inputHTMLElement.focus();
inputHTMLElement.value = 'ZZZ';
inputHTMLElement.dispatchEvent(new Event('keyup'));
inputHTMLElement.dispatchEvent(new Event('input'));
fixture.detectChanges();
fixture.whenStable().then(() => {
inputHTMLElement.blur();
fixture.detectChanges(); fixture.detectChanges();
const errorMessage = element.querySelector('.adf-cloud-group-error-message'); const errorMessage = element.querySelector('.adf-cloud-group-error-message');
expect(errorMessage).not.toBeNull(); expect(errorMessage).not.toBeNull();
expect(errorMessage.textContent).toContain('ADF_CLOUD_GROUPS.ERROR.NOT_FOUN'); expect(errorMessage.textContent).toContain(' ADF_CLOUD_GROUPS.ERROR.NOT_FOUND ');
done();
}); });
});
});
describe('Single Mode and Pre-selected groups', () => {
beforeEach(async(() => {
component.mode = 'single';
component.preSelectGroups = <any> mockIdentityGroups;
fixture.detectChanges();
element = fixture.nativeElement;
})); }));
it('should show chip list when mode=multiple', async(() => { it('should not show chip list when mode=single', (done) => {
fixture.detectChanges();
fixture.whenStable().then(() => {
const chip = element.querySelector('mat-chip-list');
expect(chip).toBeNull();
done();
});
});
it('should not pre-select any group when preSelectGroups is empty and mode=single', (done) => {
component.preSelectGroups = [];
fixture.detectChanges();
fixture.whenStable().then(() => {
const selectedUser = component.searchGroupsControl.value;
expect(selectedUser).toBeNull();
done();
});
});
});
describe('Multiple Mode and Pre-selected groups', () => {
const change = new SimpleChange(null, mockIdentityGroups, false);
beforeEach(async(() => {
component.mode = 'multiple'; component.mode = 'multiple';
component.preSelectGroups = <any> mockIdentityGroups;
component.ngOnChanges({ 'preSelectGroups': change });
fixture.detectChanges();
element = fixture.nativeElement;
}));
it('should show chip list when mode=multiple', (done) => {
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
const chip = element.querySelector('mat-chip-list'); const chip = element.querySelector('mat-chip-list');
expect(chip).toBeDefined(); expect(chip).toBeDefined();
done();
}); });
}));
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 preSelectGroups when mode=multiple', async(() => { it('should pre-select all preSelectGroups when mode=multiple', (done) => {
component.mode = 'multiple'; component.mode = 'multiple';
component.preSelectGroups = <any> [{id: mockIdentityGroups[1].id}, {id: mockIdentityGroups[2].id}]; fixture.detectChanges();
component.ngOnChanges({ 'preSelectUsers': change });
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
fixture.detectChanges(); fixture.detectChanges();
const chips = fixture.debugElement.queryAll(By.css('mat-chip')); const chips = fixture.debugElement.queryAll(By.css('mat-chip'));
expect(chips.length).toBe(2); expect(chips.length).toBe(5);
done();
});
}); });
}));
it('should not pre-select any group when preSelectGroups is empty and mode=multiple', async(() => { it('should emit removeGroup when a selected group is removed', (done) => {
const removeSpy = spyOn(component.removeGroup, 'emit');
component.mode = 'multiple'; component.mode = 'multiple';
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
const chip = fixture.debugElement.query(By.css('mat-chip'));
expect(chip).toBeNull();
});
}));
it('should pre-select preSelectGroups[0] when mode=single', async(() => {
component.mode = 'single';
component.preSelectGroups = <any> [{id: mockIdentityGroups[1].id}, {id: mockIdentityGroups[2].id}];
fixture.detectChanges();
fixture.whenStable().then(() => {
const selectedGroup = component.searchGroupsControl.value;
expect(selectedGroup.id).toBe(mockIdentityGroups[1].id);
});
}));
it('should not pre-select any group when preSelectGroups is empty and mode=single', async(() => {
component.mode = 'single';
fixture.detectChanges();
fixture.whenStable().then(() => {
const selectedGroup = component.searchGroupsControl.value;
expect(selectedGroup).toBeNull();
});
}));
it('should emit removeGroup when a selected group is removed if mode=multiple', async(() => {
const removeGroupSpy = spyOn(component.removeGroup, 'emit');
component.mode = 'multiple';
component.preSelectGroups = <any> [{id: mockIdentityGroups[1].id}, {id: mockIdentityGroups[2].id}];
fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
fixture.detectChanges(); fixture.detectChanges();
const removeIcon = fixture.debugElement.query(By.css('mat-chip mat-icon')); const removeIcon = fixture.debugElement.query(By.css('mat-chip mat-icon'));
removeIcon.nativeElement.click(); removeIcon.nativeElement.click();
fixture.detectChanges();
expect(removeGroupSpy).toHaveBeenCalledWith({ id: mockIdentityGroups[1].id }); expect(removeSpy).toHaveBeenCalled();
done();
});
});
}); });
})); describe('When roles defined', () => {
it('should list groups who have access to the app when appName is specified', async(() => { let checkGroupHasRoleSpy: jasmine.Spy;
component.appName = 'sample-app';
fixture.detectChanges();
const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input');
inputHTMLElement.focus();
inputHTMLElement.value = 'M';
inputHTMLElement.dispatchEvent(new Event('input'));
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
const groupsList = fixture.debugElement.queryAll(By.css('mat-option'));
expect(groupsList.length).toBe(mockIdentityGroups.length);
});
}));
it('should not list groups who do not have access to the app when appName is specified', async(() => { beforeEach(async(() => {
checkGroupHasAccessSpy.and.returnValue(of(false));
component.appName = 'sample-app';
fixture.detectChanges();
const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('[data-automation-id="adf-cloud-group-search-input"]');
inputHTMLElement.focus();
inputHTMLElement.value = 'Mock';
inputHTMLElement.dispatchEvent(new Event('input'));
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
const groupsList = fixture.debugElement.queryAll(By.css('mat-option'));
expect(groupsList.length).toBe(0);
});
}));
it('should filter groups when roles are specified', async(() => {
checkGroupHasGivenRoleSpy.and.returnValue(of(true));
component.roles = ['mock-role-1', 'mock-role-2']; component.roles = ['mock-role-1', 'mock-role-2'];
spyOn(identityGroupService, 'findGroupsByName').and.returnValue(of(mockIdentityGroups));
checkGroupHasRoleSpy = spyOn(identityGroupService, 'checkGroupHasRole').and.returnValue(of(true));
fixture.detectChanges();
element = fixture.nativeElement;
}));
it('should filter if groups has any specified role', (done) => {
fixture.detectChanges(); fixture.detectChanges();
const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input'); const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input');
inputHTMLElement.focus(); inputHTMLElement.focus();
@@ -248,14 +402,29 @@ describe('GroupCloudComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
fixture.detectChanges(); fixture.detectChanges();
const groupsList = fixture.debugElement.queryAll(By.css('mat-option')); expect(fixture.debugElement.queryAll(By.css('mat-option')).length).toEqual(5);
expect(groupsList.length).toBe(mockIdentityGroups.length); expect(checkGroupHasRoleSpy).toHaveBeenCalledTimes(5);
expect(checkGroupHasGivenRoleSpy).toHaveBeenCalled(); done();
});
}); });
}));
it('should return groups when roles are not specified', async(() => { it('should not filter groups if user does not have any specified role', (done) => {
checkGroupHasGivenRoleSpy.and.returnValue(of(false)); fixture.detectChanges();
checkGroupHasRoleSpy.and.returnValue(of(false));
const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input');
inputHTMLElement.focus();
inputHTMLElement.value = 'M';
inputHTMLElement.dispatchEvent(new Event('input'));
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(element.querySelectorAll('mat-option').length).toEqual(0);
expect(checkGroupHasRoleSpy).toHaveBeenCalled();
done();
});
});
it('should not call checkGroupHasRole service when roles are not specified', (done) => {
component.roles = []; component.roles = [];
fixture.detectChanges(); fixture.detectChanges();
const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input'); const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input');
@@ -265,55 +434,72 @@ describe('GroupCloudComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
fixture.detectChanges(); fixture.detectChanges();
const groupsList = fixture.debugElement.queryAll(By.css('mat-option')); expect(checkGroupHasRoleSpy).not.toHaveBeenCalled();
expect(groupsList.length).toBe(mockIdentityGroups.length); done();
expect(checkGroupHasGivenRoleSpy).not.toHaveBeenCalled(); });
});
}); });
}));
it('should validate access to the app when appName is specified', async(() => { describe('Multiple Mode with read-only', () => {
findGroupsByNameSpy.and.returnValue(of(mockIdentityGroups));
checkGroupHasAccessSpy.and.returnValue(of(true)); it('Should not be able to remove pre-selected groups if readonly property set to true', (done) => {
fixture.detectChanges(); fixture.detectChanges();
const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input'); const preselectedGroups = [
inputHTMLElement.focus(); { id: mockIdentityGroups[0].id, name: mockIdentityGroups[0].name, readonly: true },
inputHTMLElement.value = 'Mock'; { id: mockIdentityGroups[1].id, name: mockIdentityGroups[1].name, readonly: true }
inputHTMLElement.dispatchEvent(new Event('input')); ];
component.preSelectGroups = preselectedGroups;
const change = new SimpleChange(null, preselectedGroups, false);
component.mode = 'multiple';
const removeGroupSpy = spyOn(component.removeGroup, 'emit');
component.ngOnChanges({ 'preSelectGroups': change });
fixture.detectChanges();
const chipList = fixture.nativeElement.querySelectorAll('mat-chip-list mat-chip');
const removeIcon = <HTMLElement> fixture.nativeElement.querySelector('[data-automation-id="adf-cloud-group-chip-remove-icon-Mock Group 1"]');
expect(chipList.length).toBe(2);
expect(component.preSelectGroups[0].readonly).toBeTruthy();
expect(component.preSelectGroups[1].readonly).toBeTruthy();
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
fixture.detectChanges(); fixture.detectChanges();
expect(checkGroupHasAccessSpy).toHaveBeenCalledTimes(mockIdentityGroups.length); removeIcon.click();
});
}));
it('should not validate access to the app when appName is not specified', async(() => {
fixture.detectChanges(); fixture.detectChanges();
const inputHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('input'); expect(removeGroupSpy).not.toHaveBeenCalled();
inputHTMLElement.focus(); expect(component.preSelectGroups.length).toBe(2);
inputHTMLElement.value = 'M'; expect(component.preSelectGroups[0].readonly).toBe(true, 'Not removable');
inputHTMLElement.dispatchEvent(new Event('input')); expect(component.preSelectGroups[1].readonly).toBe(true, 'Not removable');
expect(fixture.nativeElement.querySelectorAll('mat-chip-list mat-chip').length).toBe(2);
done();
});
});
it('Should be able to remove preselected groups if readonly property set to false', (done) => {
fixture.detectChanges();
const preselectedGroups = [
{ id: mockIdentityGroups[0].id, name: mockIdentityGroups[0].name, readonly: false },
{ id: mockIdentityGroups[1].id, name: mockIdentityGroups[1].name, readonly: false }
];
component.preSelectGroups = preselectedGroups;
const change = new SimpleChange(null, preselectedGroups, false);
component.mode = 'multiple';
const removeGroupSpy = spyOn(component.removeGroup, 'emit');
component.ngOnChanges({ 'preSelectGroups': change });
fixture.detectChanges();
const chipList = fixture.nativeElement.querySelectorAll('mat-chip-list mat-chip');
const removeIcon = <HTMLElement> fixture.nativeElement.querySelector('[data-automation-id="adf-cloud-group-chip-remove-icon-Mock Group 1"]');
expect(chipList.length).toBe(2);
expect(component.preSelectGroups[0].readonly).toBe(false, 'Removable');
expect(component.preSelectGroups[1].readonly).toBe(false, 'Removable');
removeIcon.click();
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
fixture.detectChanges(); fixture.detectChanges();
expect(checkGroupHasAccessSpy).not.toHaveBeenCalled(); removeIcon.click();
fixture.detectChanges();
expect(removeGroupSpy).toHaveBeenCalled();
expect(fixture.nativeElement.querySelectorAll('mat-chip-list mat-chip').length).toBe(1);
done();
}); });
}));
it('should load the clients if appName change', async( () => {
component.appName = 'ADF';
fixture.detectChanges();
fixture.whenStable().then( () => {
fixture.detectChanges();
expect(getClientIdByApplicationNameSpy).toHaveBeenCalled();
}); });
}));
it('should filter users if appName change', async(() => {
component.appName = 'ADF';
fixture.detectChanges();
fixture.whenStable().then( () => {
fixture.detectChanges();
expect(checkGroupHasAccessSpy).toHaveBeenCalled();
}); });
}));
}); });

View File

@@ -25,7 +25,7 @@ describe('InitialGroupNamePipe', () => {
beforeEach(() => { beforeEach(() => {
pipe = new InitialGroupNamePipe(); pipe = new InitialGroupNamePipe();
fakeGroup = new IdentityGroupModel({name: 'mock'}); fakeGroup = <IdentityGroupModel> {name: 'mock'};
}); });
it('should return with the group initial', () => { it('should return with the group initial', () => {