Skip to content

Commit 4cc5a38

Browse files
authored
Merge pull request DSpace#2371 from alexandrevryghem/fix-specs-without-expectations_contribute-main
Fix Spec has no expectations errors
2 parents f6f3962 + 371e766 commit 4cc5a38

54 files changed

Lines changed: 494 additions & 452 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

karma.conf.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ module.exports = function (config) {
1515
],
1616
client: {
1717
clearContext: false, // leave Jasmine Spec Runner output visible in browser
18-
captureConsole: false
18+
captureConsole: false,
19+
jasmine: {
20+
failSpecWithNoExpectations: true
21+
}
1922
},
2023
coverageIstanbulReporter: {
2124
dir: require('path').join(__dirname, './coverage/dspace-angular'),

src/app/access-control/epeople-registry/epeople-registry.component.spec.ts

Lines changed: 22 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
55
import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing';
66
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
77
import { BrowserModule, By } from '@angular/platform-browser';
8-
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
9-
import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';
8+
import { NgbModule, NgbModal } from '@ng-bootstrap/ng-bootstrap';
9+
import { TranslateModule } from '@ngx-translate/core';
1010
import { buildPaginatedList, PaginatedList } from '../../core/data/paginated-list.model';
1111
import { RemoteData } from '../../core/data/remote-data';
1212
import { EPersonDataService } from '../../core/eperson/eperson-data.service';
@@ -18,8 +18,6 @@ import { EPeopleRegistryComponent } from './epeople-registry.component';
1818
import { EPersonMock, EPersonMock2 } from '../../shared/testing/eperson.mock';
1919
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
2020
import { getMockFormBuilderService } from '../../shared/mocks/form-builder-service.mock';
21-
import { getMockTranslateService } from '../../shared/mocks/translate.service.mock';
22-
import { TranslateLoaderMock } from '../../shared/mocks/translate-loader.mock';
2321
import { NotificationsServiceStub } from '../../shared/testing/notifications-service.stub';
2422
import { RouterStub } from '../../shared/testing/router.stub';
2523
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
@@ -31,17 +29,15 @@ import { FindListOptions } from '../../core/data/find-list-options.model';
3129
describe('EPeopleRegistryComponent', () => {
3230
let component: EPeopleRegistryComponent;
3331
let fixture: ComponentFixture<EPeopleRegistryComponent>;
34-
let translateService: TranslateService;
3532
let builderService: FormBuilderService;
3633

37-
let mockEPeople;
34+
let mockEPeople: EPerson[];
3835
let ePersonDataServiceStub: any;
3936
let authorizationService: AuthorizationDataService;
40-
let modalService;
37+
let modalService: NgbModal;
38+
let paginationService: PaginationServiceStub;
4139

42-
let paginationService;
43-
44-
beforeEach(waitForAsync(() => {
40+
beforeEach(waitForAsync(async () => {
4541
jasmine.getEnv().allowRespy(true);
4642
mockEPeople = [EPersonMock, EPersonMock2];
4743
ePersonDataServiceStub = {
@@ -99,7 +95,7 @@ describe('EPeopleRegistryComponent', () => {
9995
deleteEPerson(ePerson: EPerson): Observable<boolean> {
10096
this.allEpeople = this.allEpeople.filter((ePerson2: EPerson) => {
10197
return (ePerson2.uuid !== ePerson.uuid);
102-
});
98+
});
10399
return observableOf(true);
104100
},
105101
editEPerson(ePerson: EPerson) {
@@ -119,17 +115,11 @@ describe('EPeopleRegistryComponent', () => {
119115
isAuthorized: observableOf(true)
120116
});
121117
builderService = getMockFormBuilderService();
122-
translateService = getMockTranslateService();
123118

124119
paginationService = new PaginationServiceStub();
125-
TestBed.configureTestingModule({
120+
await TestBed.configureTestingModule({
126121
imports: [CommonModule, NgbModule, FormsModule, ReactiveFormsModule, BrowserModule,
127-
TranslateModule.forRoot({
128-
loader: {
129-
provide: TranslateLoader,
130-
useClass: TranslateLoaderMock
131-
}
132-
}),
122+
TranslateModule.forRoot(),
133123
],
134124
declarations: [EPeopleRegistryComponent],
135125
providers: [
@@ -148,7 +138,7 @@ describe('EPeopleRegistryComponent', () => {
148138
beforeEach(() => {
149139
fixture = TestBed.createComponent(EPeopleRegistryComponent);
150140
component = fixture.componentInstance;
151-
modalService = (component as any).modalService;
141+
modalService = TestBed.inject(NgbModal);
152142
spyOn(modalService, 'open').and.returnValue(Object.assign({ componentInstance: Object.assign({ response: observableOf(true) }) }));
153143
fixture.detectChanges();
154144
});
@@ -158,18 +148,18 @@ describe('EPeopleRegistryComponent', () => {
158148
});
159149

160150
it('should display list of ePeople', () => {
161-
const ePeopleIdsFound = fixture.debugElement.queryAll(By.css('#epeople tr td:first-child'));
151+
const ePeopleIdsFound: DebugElement[] = fixture.debugElement.queryAll(By.css('#epeople tr td:first-child'));
162152
expect(ePeopleIdsFound.length).toEqual(2);
163153
mockEPeople.map((ePerson: EPerson) => {
164-
expect(ePeopleIdsFound.find((foundEl) => {
154+
expect(ePeopleIdsFound.find((foundEl: DebugElement) => {
165155
return (foundEl.nativeElement.textContent.trim() === ePerson.uuid);
166156
})).toBeTruthy();
167157
});
168158
});
169159

170160
describe('search', () => {
171161
describe('when searching with scope/query (scope metadata)', () => {
172-
let ePeopleIdsFound;
162+
let ePeopleIdsFound: DebugElement[];
173163
beforeEach(fakeAsync(() => {
174164
component.search({ scope: 'metadata', query: EPersonMock2.name });
175165
tick();
@@ -179,14 +169,14 @@ describe('EPeopleRegistryComponent', () => {
179169

180170
it('should display search result', () => {
181171
expect(ePeopleIdsFound.length).toEqual(1);
182-
expect(ePeopleIdsFound.find((foundEl) => {
172+
expect(ePeopleIdsFound.find((foundEl: DebugElement) => {
183173
return (foundEl.nativeElement.textContent.trim() === EPersonMock2.uuid);
184174
})).toBeTruthy();
185175
});
186176
});
187177

188178
describe('when searching with scope/query (scope email)', () => {
189-
let ePeopleIdsFound;
179+
let ePeopleIdsFound: DebugElement[];
190180
beforeEach(fakeAsync(() => {
191181
component.search({ scope: 'email', query: EPersonMock.email });
192182
tick();
@@ -196,7 +186,7 @@ describe('EPeopleRegistryComponent', () => {
196186

197187
it('should display search result', () => {
198188
expect(ePeopleIdsFound.length).toEqual(1);
199-
expect(ePeopleIdsFound.find((foundEl) => {
189+
expect(ePeopleIdsFound.find((foundEl: DebugElement) => {
200190
return (foundEl.nativeElement.textContent.trim() === EPersonMock.uuid);
201191
})).toBeTruthy();
202192
});
@@ -228,19 +218,12 @@ describe('EPeopleRegistryComponent', () => {
228218
});
229219
});
230220

231-
describe('delete EPerson button when the isAuthorized returns false', () => {
232-
let ePeopleDeleteButton;
233-
beforeEach(() => {
234-
spyOn(authorizationService, 'isAuthorized').and.returnValue(observableOf(false));
235-
component.initialisePage();
236-
fixture.detectChanges();
237-
});
238221

239-
it('should be disabled', () => {
240-
ePeopleDeleteButton = fixture.debugElement.queryAll(By.css('#epeople tr td div button.delete-button'));
241-
ePeopleDeleteButton.forEach((deleteButton: DebugElement) => {
242-
expect(deleteButton.nativeElement.disabled).toBe(true);
243-
});
244-
});
222+
it('should hide delete EPerson button when the isAuthorized returns false', () => {
223+
spyOn(authorizationService, 'isAuthorized').and.returnValue(observableOf(false));
224+
component.initialisePage();
225+
fixture.detectChanges();
226+
227+
expect(fixture.debugElement.query(By.css('#epeople tr td div button.delete-button'))).toBeNull();
245228
});
246229
});

src/app/community-page/sections/sub-com-col-section/sub-collection-list/community-page-sub-collection-list.component.spec.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
22
import { TranslateModule } from '@ngx-translate/core';
3-
import { NO_ERRORS_SCHEMA } from '@angular/core';
3+
import { DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
44
import { By } from '@angular/platform-browser';
55
import { RouterTestingModule } from '@angular/router/testing';
66
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
@@ -30,7 +30,7 @@ import { ConfigurationProperty } from '../../../../core/shared/configuration-pro
3030
import { createPaginatedList } from '../../../../shared/testing/utils.test';
3131
import { SearchConfigurationServiceStub } from '../../../../shared/testing/search-configuration-service.stub';
3232

33-
describe('CommunityPageSubCollectionList Component', () => {
33+
describe('CommunityPageSubCollectionListComponent', () => {
3434
let comp: CommunityPageSubCollectionListComponent;
3535
let fixture: ComponentFixture<CommunityPageSubCollectionListComponent>;
3636
let collectionDataServiceStub: any;
@@ -177,19 +177,19 @@ describe('CommunityPageSubCollectionList Component', () => {
177177
});
178178

179179

180-
it('should display a list of collections', () => {
181-
waitForAsync(() => {
182-
subCollList = collections;
183-
fixture.detectChanges();
180+
it('should display a list of collections', async () => {
181+
subCollList = collections;
182+
fixture.detectChanges();
183+
await fixture.whenStable();
184+
fixture.detectChanges();
184185

185-
const collList = fixture.debugElement.queryAll(By.css('li'));
186-
expect(collList.length).toEqual(5);
187-
expect(collList[0].nativeElement.textContent).toContain('Collection 1');
188-
expect(collList[1].nativeElement.textContent).toContain('Collection 2');
189-
expect(collList[2].nativeElement.textContent).toContain('Collection 3');
190-
expect(collList[3].nativeElement.textContent).toContain('Collection 4');
191-
expect(collList[4].nativeElement.textContent).toContain('Collection 5');
192-
});
186+
const collList: DebugElement[] = fixture.debugElement.queryAll(By.css('ul[data-test="objects"] li'));
187+
expect(collList.length).toEqual(5);
188+
expect(collList[0].nativeElement.textContent).toContain('Collection 1');
189+
expect(collList[1].nativeElement.textContent).toContain('Collection 2');
190+
expect(collList[2].nativeElement.textContent).toContain('Collection 3');
191+
expect(collList[3].nativeElement.textContent).toContain('Collection 4');
192+
expect(collList[4].nativeElement.textContent).toContain('Collection 5');
193193
});
194194

195195
it('should not display the header when list of collections is empty', () => {

src/app/community-page/sections/sub-com-col-section/sub-community-list/community-page-sub-community-list.component.spec.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
22
import { TranslateModule } from '@ngx-translate/core';
3-
import { NO_ERRORS_SCHEMA } from '@angular/core';
3+
import { DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
44
import { RouterTestingModule } from '@angular/router/testing';
55
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
66
import { By } from '@angular/platform-browser';
@@ -30,7 +30,7 @@ import { SearchConfigurationServiceStub } from '../../../../shared/testing/searc
3030
import { ConfigurationProperty } from '../../../../core/shared/configuration-property.model';
3131
import { createPaginatedList } from '../../../../shared/testing/utils.test';
3232

33-
describe('CommunityPageSubCommunityListComponent Component', () => {
33+
describe('CommunityPageSubCommunityListComponent', () => {
3434
let comp: CommunityPageSubCommunityListComponent;
3535
let fixture: ComponentFixture<CommunityPageSubCommunityListComponent>;
3636
let communityDataServiceStub: any;
@@ -179,19 +179,19 @@ describe('CommunityPageSubCommunityListComponent Component', () => {
179179
});
180180

181181

182-
it('should display a list of sub-communities', () => {
183-
waitForAsync(() => {
184-
subCommList = subcommunities;
185-
fixture.detectChanges();
182+
it('should display a list of sub-communities', async () => {
183+
subCommList = subcommunities;
184+
fixture.detectChanges();
185+
await fixture.whenStable();
186+
fixture.detectChanges();
186187

187-
const subComList = fixture.debugElement.queryAll(By.css('li'));
188-
expect(subComList.length).toEqual(5);
189-
expect(subComList[0].nativeElement.textContent).toContain('SubCommunity 1');
190-
expect(subComList[1].nativeElement.textContent).toContain('SubCommunity 2');
191-
expect(subComList[2].nativeElement.textContent).toContain('SubCommunity 3');
192-
expect(subComList[3].nativeElement.textContent).toContain('SubCommunity 4');
193-
expect(subComList[4].nativeElement.textContent).toContain('SubCommunity 5');
194-
});
188+
const subComList: DebugElement[] = fixture.debugElement.queryAll(By.css('ul[data-test="objects"] li'));
189+
expect(subComList.length).toEqual(5);
190+
expect(subComList[0].nativeElement.textContent).toContain('SubCommunity 1');
191+
expect(subComList[1].nativeElement.textContent).toContain('SubCommunity 2');
192+
expect(subComList[2].nativeElement.textContent).toContain('SubCommunity 3');
193+
expect(subComList[3].nativeElement.textContent).toContain('SubCommunity 4');
194+
expect(subComList[4].nativeElement.textContent).toContain('SubCommunity 5');
195195
});
196196

197197
it('should not display the header when list of sub-communities is empty', () => {

src/app/core/auth/auth.interceptor.spec.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@ describe(`AuthInterceptor`, () => {
2020

2121
const authServiceStub = new AuthServiceStub();
2222
const store: Store<TruncatablesState> = jasmine.createSpyObj('store', {
23-
/* eslint-disable no-empty,@typescript-eslint/no-empty-function */
2423
dispatch: {},
25-
/* eslint-enable no-empty, @typescript-eslint/no-empty-function */
2624
select: observableOf(true)
2725
});
2826

@@ -46,6 +44,10 @@ describe(`AuthInterceptor`, () => {
4644
httpMock = TestBed.inject(HttpTestingController);
4745
});
4846

47+
afterEach(() => {
48+
httpMock.verify();
49+
});
50+
4951
describe('when has a valid token', () => {
5052

5153
it('should not add an Authorization header when we’re sending a HTTP request to \'authn\' endpoint that is not the logout endpoint', () => {
@@ -95,14 +97,11 @@ describe(`AuthInterceptor`, () => {
9597
});
9698

9799
it('should redirect to login', () => {
98-
99-
service.request(RestRequestMethod.POST, 'dspace-spring-rest/api/submission/workspaceitems', 'password=password&user=user').subscribe((response) => {
100-
expect(response).toBeTruthy();
101-
});
102-
103100
service.request(RestRequestMethod.POST, 'dspace-spring-rest/api/submission/workspaceitems', 'password=password&user=user');
104101

105102
httpMock.expectNone('dspace-spring-rest/api/submission/workspaceitems');
103+
// HttpTestingController.expectNone will throw an error when a requests is made
104+
expect().nothing();
106105
});
107106
});
108107

src/app/core/cache/object-cache.reducer.spec.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ describe('objectCacheReducer', () => {
126126
deepFreeze(state);
127127

128128
objectCacheReducer(state, action);
129+
130+
// no expect required, deepFreeze will ensure an exception is thrown if the state
131+
// is mutated, and any uncaught exception will cause the test to fail
132+
expect().nothing();
129133
});
130134

131135
it('should remove the specified object from the cache in response to the REMOVE action', () => {
@@ -149,6 +153,10 @@ describe('objectCacheReducer', () => {
149153
const action = new RemoveFromObjectCacheAction(selfLink1);
150154
// testState has already been frozen above
151155
objectCacheReducer(testState, action);
156+
157+
// no expect required, deepFreeze will ensure an exception is thrown if the state
158+
// is mutated, and any uncaught exception will cause the test to fail
159+
expect().nothing();
152160
});
153161

154162
it('should set the timestamp of all objects in the cache in response to a RESET_TIMESTAMPS action', () => {
@@ -164,6 +172,10 @@ describe('objectCacheReducer', () => {
164172
const action = new ResetObjectCacheTimestampsAction(new Date().getTime());
165173
// testState has already been frozen above
166174
objectCacheReducer(testState, action);
175+
176+
// no expect required, deepFreeze will ensure an exception is thrown if the state
177+
// is mutated, and any uncaught exception will cause the test to fail
178+
expect().nothing();
167179
});
168180

169181
it('should perform the ADD_PATCH action without affecting the previous state', () => {
@@ -174,6 +186,10 @@ describe('objectCacheReducer', () => {
174186
}]);
175187
// testState has already been frozen above
176188
objectCacheReducer(testState, action);
189+
190+
// no expect required, deepFreeze will ensure an exception is thrown if the state
191+
// is mutated, and any uncaught exception will cause the test to fail
192+
expect().nothing();
177193
});
178194

179195
it('should when the ADD_PATCH action dispatched', () => {

src/app/core/cache/server-sync-buffer.reducer.spec.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,20 @@ describe('serverSyncBufferReducer', () => {
5252
const action = new AddToSSBAction(selfLink1, RestRequestMethod.POST);
5353
// testState has already been frozen above
5454
serverSyncBufferReducer(testState, action);
55+
56+
// no expect required, deepFreeze will ensure an exception is thrown if the state
57+
// is mutated, and any uncaught exception will cause the test to fail
58+
expect().nothing();
5559
});
5660

5761
it('should perform the EMPTY action without affecting the previous state', () => {
5862
const action = new EmptySSBAction();
5963
// testState has already been frozen above
6064
serverSyncBufferReducer(testState, action);
65+
66+
// no expect required, deepFreeze will ensure an exception is thrown if the state
67+
// is mutated, and any uncaught exception will cause the test to fail
68+
expect().nothing();
6169
});
6270

6371
it('should empty the buffer if the EmptySSBAction is dispatched without a payload', () => {

0 commit comments

Comments
 (0)