Commits

Tim Donohue authored 64f968b2467
Fix subgroups-list specs so they align with new members-list specs
No tags

src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.spec.ts

Modified
1 1 import { CommonModule } from '@angular/common';
2 2 import { NO_ERRORS_SCHEMA, DebugElement } from '@angular/core';
3 -import { ComponentFixture, fakeAsync, flush, inject, TestBed, tick, waitForAsync } from '@angular/core/testing';
3 +import { ComponentFixture, fakeAsync, flush, inject, TestBed, waitForAsync } from '@angular/core/testing';
4 4 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
5 5 import { BrowserModule, By } from '@angular/platform-browser';
6 6 import { Router } from '@angular/router';
7 7 import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
8 8 import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';
9 -import { Observable, of as observableOf, BehaviorSubject } from 'rxjs';
9 +import { Observable, of as observableOf } from 'rxjs';
10 10 import { RestResponse } from '../../../../core/cache/response.models';
11 11 import { buildPaginatedList, PaginatedList } from '../../../../core/data/paginated-list.model';
12 12 import { RemoteData } from '../../../../core/data/remote-data';
13 13 import { GroupDataService } from '../../../../core/eperson/group-data.service';
14 14 import { Group } from '../../../../core/eperson/models/group.model';
15 15 import { PageInfo } from '../../../../core/shared/page-info.model';
16 16 import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service';
17 17 import { NotificationsService } from '../../../../shared/notifications/notifications.service';
18 18 import { GroupMock, GroupMock2 } from '../../../../shared/testing/group-mock';
19 19 import { SubgroupsListComponent } from './subgroups-list.component';
20 20 import {
21 - createSuccessfulRemoteDataObject$,
22 - createSuccessfulRemoteDataObject
21 + createSuccessfulRemoteDataObject$
23 22 } from '../../../../shared/remote-data.utils';
24 23 import { RouterMock } from '../../../../shared/mocks/router.mock';
25 24 import { getMockFormBuilderService } from '../../../../shared/mocks/form-builder-service.mock';
26 25 import { getMockTranslateService } from '../../../../shared/mocks/translate.service.mock';
27 26 import { TranslateLoaderMock } from '../../../../shared/testing/translate-loader.mock';
28 27 import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub';
29 -import { map } from 'rxjs/operators';
30 28 import { PaginationService } from '../../../../core/pagination/pagination.service';
31 29 import { PaginationServiceStub } from '../../../../shared/testing/pagination-service.stub';
32 30 import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
33 31 import { DSONameServiceMock } from '../../../../shared/mocks/dso-name.service.mock';
32 +import { EPersonMock2 } from 'src/app/shared/testing/eperson.mock';
34 33
35 34 describe('SubgroupsListComponent', () => {
36 35 let component: SubgroupsListComponent;
37 36 let fixture: ComponentFixture<SubgroupsListComponent>;
38 37 let translateService: TranslateService;
39 38 let builderService: FormBuilderService;
40 39 let ePersonDataServiceStub: any;
41 40 let groupsDataServiceStub: any;
42 - let activeGroup;
41 + let activeGroup: Group;
43 42 let subgroups: Group[];
44 - let allGroups: Group[];
43 + let groupNonMembers: Group[];
45 44 let routerStub;
46 45 let paginationService;
46 + // Define a new mock activegroup for all tests below
47 + let mockActiveGroup: Group = Object.assign(new Group(), {
48 + handle: null,
49 + subgroups: [GroupMock2],
50 + epersons: [EPersonMock2],
51 + selfRegistered: false,
52 + permanent: false,
53 + _links: {
54 + self: {
55 + href: 'https://rest.api/server/api/eperson/groups/activegroupid',
56 + },
57 + subgroups: { href: 'https://rest.api/server/api/eperson/groups/activegroupid/subgroups' },
58 + object: { href: 'https://rest.api/server/api/eperson/groups/activegroupid/object' },
59 + epersons: { href: 'https://rest.api/server/api/eperson/groups/activegroupid/epersons' }
60 + },
61 + _name: 'activegroupname',
62 + id: 'activegroupid',
63 + uuid: 'activegroupid',
64 + type: 'group',
65 + });
47 66
48 67 beforeEach(waitForAsync(() => {
49 - activeGroup = GroupMock;
68 + activeGroup = mockActiveGroup;
50 69 subgroups = [GroupMock2];
51 - allGroups = [GroupMock, GroupMock2];
70 + groupNonMembers = [GroupMock];
52 71 ePersonDataServiceStub = {};
53 72 groupsDataServiceStub = {
54 73 activeGroup: activeGroup,
55 - subgroups$: new BehaviorSubject(subgroups),
74 + subgroups: subgroups,
75 + groupNonMembers: groupNonMembers,
56 76 getActiveGroup(): Observable<Group> {
57 77 return observableOf(this.activeGroup);
58 78 },
59 79 getSubgroups(): Group {
60 - return this.activeGroup;
80 + return this.subgroups;
61 81 },
82 + // This method is used to get all the current subgroups
62 83 findListByHref(_href: string): Observable<RemoteData<PaginatedList<Group>>> {
63 - return this.subgroups$.pipe(
64 - map((currentGroups: Group[]) => {
65 - return createSuccessfulRemoteDataObject(buildPaginatedList<Group>(new PageInfo(), currentGroups));
66 - })
67 - );
84 + return createSuccessfulRemoteDataObject$(buildPaginatedList<Group>(new PageInfo(), groupsDataServiceStub.getSubgroups()));
68 85 },
69 86 getGroupEditPageRouterLink(group: Group): string {
70 87 return '/access-control/groups/' + group.id;
71 88 },
89 + // This method is used to get all groups which are NOT currently a subgroup member
72 90 searchGroups(query: string): Observable<RemoteData<PaginatedList<Group>>> {
73 91 if (query === '') {
74 - return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), allGroups));
92 + return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), groupNonMembers));
75 93 }
76 94 return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), []));
77 95 },
78 - addSubGroupToGroup(parentGroup, subgroup: Group): Observable<RestResponse> {
79 - this.subgroups$.next([...this.subgroups$.getValue(), subgroup]);
96 + addSubGroupToGroup(parentGroup, subgroupToAdd: Group): Observable<RestResponse> {
97 + // Add group to list of subgroups
98 + this.subgroups = [...this.subgroups, subgroupToAdd];
99 + // Remove group from list of non-members
100 + this.groupNonMembers.forEach( (group: Group, index: number) => {
101 + if (group.id === subgroupToAdd.id) {
102 + this.groupNonMembers.splice(index, 1);
103 + }
104 + });
80 105 return observableOf(new RestResponse(true, 200, 'Success'));
81 106 },
82 107 clearGroupsRequests() {
83 108 // empty
84 109 },
85 110 clearGroupLinkRequests() {
86 111 // empty
87 112 },
88 - deleteSubGroupFromGroup(parentGroup, subgroup: Group): Observable<RestResponse> {
89 - this.subgroups$.next(this.subgroups$.getValue().filter((group: Group) => {
90 - if (group.id !== subgroup.id) {
91 - return group;
113 + deleteSubGroupFromGroup(parentGroup, subgroupToDelete: Group): Observable<RestResponse> {
114 + // Remove group from list of subgroups
115 + this.subgroups.forEach( (group: Group, index: number) => {
116 + if (group.id === subgroupToDelete.id) {
117 + this.subgroups.splice(index, 1);
92 118 }
93 - }));
119 + });
120 + // Add group to list of non-members
121 + this.groupNonMembers = [...this.groupNonMembers, subgroupToDelete];
94 122 return observableOf(new RestResponse(true, 200, 'Success'));
95 123 }
96 124 };
97 125 routerStub = new RouterMock();
98 126 builderService = getMockFormBuilderService();
99 127 translateService = getMockTranslateService();
100 128
101 129 paginationService = new PaginationServiceStub();
102 - TestBed.configureTestingModule({
130 + return TestBed.configureTestingModule({
103 131 imports: [CommonModule, NgbModule, FormsModule, ReactiveFormsModule, BrowserModule,
104 132 TranslateModule.forRoot({
105 133 loader: {
106 134 provide: TranslateLoader,
107 135 useClass: TranslateLoaderMock
108 136 }
109 137 }),
110 138 ],
111 139 declarations: [SubgroupsListComponent],
112 140 providers: [SubgroupsListComponent,
130 158 fixture.destroy();
131 159 fixture.debugElement.nativeElement.remove();
132 160 flush();
133 161 component = null;
134 162 }));
135 163
136 164 it('should create SubgroupsListComponent', inject([SubgroupsListComponent], (comp: SubgroupsListComponent) => {
137 165 expect(comp).toBeDefined();
138 166 }));
139 167
140 - it('should show list of subgroups of current active group', () => {
141 - const groupIdsFound = fixture.debugElement.queryAll(By.css('#subgroupsOfGroup tr td:first-child'));
142 - expect(groupIdsFound.length).toEqual(1);
143 - activeGroup.subgroups.map((group: Group) => {
144 - expect(groupIdsFound.find((foundEl) => {
145 - return (foundEl.nativeElement.textContent.trim() === group.uuid);
146 - })).toBeTruthy();
168 + describe('current subgroup list', () => {
169 + it('should show list of subgroups of current active group', () => {
170 + const groupIdsFound = fixture.debugElement.queryAll(By.css('#subgroupsOfGroup tr td:first-child'));
171 + expect(groupIdsFound.length).toEqual(1);
172 + subgroups.map((group: Group) => {
173 + expect(groupIdsFound.find((foundEl) => {
174 + return (foundEl.nativeElement.textContent.trim() === group.uuid);
175 + })).toBeTruthy();
176 + });
147 177 });
148 - });
149 178
150 - describe('if first group delete button is pressed', () => {
151 - let groupsFound: DebugElement[];
152 - beforeEach(fakeAsync(() => {
153 - const addButton = fixture.debugElement.query(By.css('#subgroupsOfGroup tbody .deleteButton'));
154 - addButton.triggerEventHandler('click', {
155 - preventDefault: () => {/**/
156 - }
179 + it('should show a delete button next to each subgroup', () => {
180 + const subgroupsFound = fixture.debugElement.queryAll(By.css('#subgroupsOfGroup tbody tr'));
181 + subgroupsFound.map((foundGroupRowElement: DebugElement) => {
182 + const addButton: DebugElement = foundGroupRowElement.query(By.css('td:last-child .fa-plus'));
183 + const deleteButton: DebugElement = foundGroupRowElement.query(By.css('td:last-child .fa-trash-alt'));
184 + expect(addButton).toBeNull();
185 + expect(deleteButton).not.toBeNull();
186 + });
187 + });
188 +
189 + describe('if first group delete button is pressed', () => {
190 + let groupsFound: DebugElement[];
191 + beforeEach(() => {
192 + const deleteButton = fixture.debugElement.query(By.css('#subgroupsOfGroup tbody .deleteButton'));
193 + deleteButton.nativeElement.click();
194 + fixture.detectChanges();
195 + });
196 + it('then no subgroup remains as a member of the active group', () => {
197 + groupsFound = fixture.debugElement.queryAll(By.css('#subgroupsOfGroup tbody tr'));
198 + expect(groupsFound.length).toEqual(0);
157 199 });
158 - tick();
159 - fixture.detectChanges();
160 - }));
161 - it('one less subgroup in list from 1 to 0 (of 2 total groups)', () => {
162 - groupsFound = fixture.debugElement.queryAll(By.css('#subgroupsOfGroup tbody tr'));
163 - expect(groupsFound.length).toEqual(0);
164 200 });
165 201 });
166 202
167 203 describe('search', () => {
168 204 describe('when searching with empty query', () => {
169 205 let groupsFound: DebugElement[];
170 206 beforeEach(fakeAsync(() => {
171 207 component.search({ query: '' });
208 + fixture.detectChanges();
172 209 groupsFound = fixture.debugElement.queryAll(By.css('#groupsSearch tbody tr'));
173 210 }));
174 211
175 - it('should display all groups', () => {
176 - fixture.detectChanges();
177 - groupsFound = fixture.debugElement.queryAll(By.css('#groupsSearch tbody tr'));
178 - expect(groupsFound.length).toEqual(2);
179 - groupsFound = fixture.debugElement.queryAll(By.css('#groupsSearch tbody tr'));
212 + it('should display only non-member groups (i.e. groups that are not a subgroup)', () => {
180 213 const groupIdsFound: DebugElement[] = fixture.debugElement.queryAll(By.css('#groupsSearch tbody tr td:first-child'));
181 - allGroups.map((group: Group) => {
214 + expect(groupIdsFound.length).toEqual(1);
215 + groupNonMembers.map((group: Group) => {
182 216 expect(groupIdsFound.find((foundEl: DebugElement) => {
183 217 return (foundEl.nativeElement.textContent.trim() === group.uuid);
184 218 })).toBeTruthy();
185 219 });
186 220 });
187 221
188 - describe('if group is already a subgroup', () => {
189 - it('should have delete button, else it should have add button', () => {
222 + it('should display an add button next to non-member groups, not a delete button', () => {
223 + groupsFound.map((foundGroupRowElement: DebugElement) => {
224 + const addButton: DebugElement = foundGroupRowElement.query(By.css('td:last-child .fa-plus'));
225 + const deleteButton: DebugElement = foundGroupRowElement.query(By.css('td:last-child .fa-trash-alt'));
226 + expect(addButton).not.toBeNull();
227 + expect(deleteButton).toBeNull();
228 + });
229 + });
230 +
231 + describe('if first add button is pressed', () => {
232 + beforeEach(() => {
233 + const addButton: DebugElement = fixture.debugElement.query(By.css('#groupsSearch tbody .fa-plus'));
234 + addButton.nativeElement.click();
190 235 fixture.detectChanges();
236 + });
237 + it('then all (two) Groups are subgroups of the active group. No non-members left', () => {
191 238 groupsFound = fixture.debugElement.queryAll(By.css('#groupsSearch tbody tr'));
192 - const getSubgroups = groupsDataServiceStub.getSubgroups().subgroups;
193 - if (getSubgroups !== undefined && getSubgroups.length > 0) {
194 - groupsFound.map((foundGroupRowElement: DebugElement) => {
195 - const groupId: DebugElement = foundGroupRowElement.query(By.css('td:first-child'));
196 - const addButton: DebugElement = foundGroupRowElement.query(By.css('td:last-child .fa-plus'));
197 - const deleteButton: DebugElement = foundGroupRowElement.query(By.css('td:last-child .fa-trash-alt'));
198 - expect(addButton).toBeNull();
199 - if (activeGroup.id === groupId.nativeElement.textContent) {
200 - expect(deleteButton).toBeNull();
201 - } else {
202 - expect(deleteButton).not.toBeNull();
203 - }
204 - });
205 - } else {
206 - const subgroupIds: string[] = activeGroup.subgroups.map((group: Group) => group.id);
207 - groupsFound.map((foundGroupRowElement: DebugElement) => {
208 - const groupId: DebugElement = foundGroupRowElement.query(By.css('td:first-child'));
209 - const addButton: DebugElement = foundGroupRowElement.query(By.css('td:last-child .fa-plus'));
210 - const deleteButton: DebugElement = foundGroupRowElement.query(By.css('td:last-child .fa-trash-alt'));
211 - if (subgroupIds.includes(groupId.nativeElement.textContent)) {
212 - expect(addButton).toBeNull();
213 - expect(deleteButton).not.toBeNull();
214 - } else {
215 - expect(deleteButton).toBeNull();
216 - expect(addButton).not.toBeNull();
217 - }
218 - });
219 - }
239 + expect(groupsFound.length).toEqual(0);
220 240 });
221 241 });
222 242 });
223 243 });
224 244
225 245 });

Everything looks good. We'll let you know here if there's anything you should know about.

Add shortcut