Skip to content

Commit a4d3514

Browse files
dsteelma-umdPerplexity AI
andcommitted
LIBDRUM-1005. Added additional test to cover "no filename" branch
The RestrictedAccessComponent has a code branch (and a specific message) when a filename is not provided, so added a test to verify that part of the code. Co-authored-by: Perplexity AI <noreply@perplexity.ai> https://umd-dit.atlassian.net/browse/LIBDRUM-1005
1 parent 555fe32 commit a4d3514

2 files changed

Lines changed: 93 additions & 99 deletions

File tree

src/app/restricted-access/restricted-access.component.spec.ts

Lines changed: 71 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ describe('RestrictedAccessComponent', () => {
116116

117117
// Helper function for setting up anonymous tests with a specific embargo
118118
// restriction
119-
function setupAnonymous(bitstreamOverrides) {
119+
function setupAnonymous(bitstreamOverrides: Partial<Bitstream>) {
120120
beforeEach(waitForAsync(() => {
121121
init(bitstreamOverrides);
122122
(authService.isAuthenticated as jasmine.Spy).and.returnValue(observableOf(false));
@@ -134,17 +134,11 @@ describe('RestrictedAccessComponent', () => {
134134
// Helper function verifying that a HTTP 401 Unauthorized status code is
135135
// set, and that a redirect to the bitstream is not performed.
136136
function verify401StatusCodeAndNoRedirectToDownload() {
137-
it('should set 401 Unauthorized and not redirect to the file', waitForAsync(() => {
138-
fixture.whenStable().then(() => {
139-
expect(serverResponseService.setUnauthorized).toHaveBeenCalled();
140-
});
141-
fixture.whenStable().then(() => {
142-
expect(serverResponseService.setForbidden).not.toHaveBeenCalled();
143-
});
144-
fixture.whenStable().then(() => {
145-
expect(hardRedirectService.redirect).not.toHaveBeenCalled();
146-
});
147-
}));
137+
it('should set 401 Unauthorized and not redirect to the file', () => {
138+
expect(serverResponseService.setUnauthorized).toHaveBeenCalled();
139+
expect(serverResponseService.setForbidden).not.toHaveBeenCalled();
140+
expect(hardRedirectService.redirect).not.toHaveBeenCalled();
141+
});
148142
}
149143

150144
describe('when the user is anonymous (not logged in)', () => {
@@ -154,9 +148,7 @@ describe('RestrictedAccessComponent', () => {
154148
verify401StatusCodeAndNoRedirectToDownload();
155149

156150
it('should set the restrictedAccessMessage indicating the file is embargoed forever', waitForAsync(() => {
157-
fixture.whenStable().then(() => {
158-
expect(component.restrictedAccessMessage.value).toBe('bitstream.restricted-access.embargo.forever.message');
159-
});
151+
expect(component.restrictedAccessMessage.value).toBe('bitstream.restricted-access.embargo.forever.message');
160152
}));
161153
});
162154

@@ -165,39 +157,33 @@ describe('RestrictedAccessComponent', () => {
165157

166158
verify401StatusCodeAndNoRedirectToDownload();
167159

168-
it('should set the restrictedAccessMessage indicating an end date', waitForAsync(() => {
169-
fixture.whenStable().then(() => {
170-
expect(component.restrictedAccessMessage.value).toBe(
171-
'bitstream.restricted-access.embargo.restricted-until.message');
172-
});
173-
}));
160+
it('should set the restrictedAccessMessage indicating an end date', () => {
161+
expect(component.restrictedAccessMessage.value).toBe(
162+
'bitstream.restricted-access.embargo.restricted-until.message');
163+
});
174164
});
175165

176166
describe('when embargoRestriction is NONE (embargo over, but file is restricted for another reason)', () => {
177167
setupAnonymous({ embargoRestriction: 'NONE' });
178168

179169
verify401StatusCodeAndNoRedirectToDownload();
180170

181-
it('should set the restrictedAccessMessage to a simple "forbidden" message', waitForAsync(() => {
182-
fixture.whenStable().then(() => {
183-
expect(component.restrictedAccessMessage.value).toBe('bitstream.restricted-access.anonymous.forbidden.message');
184-
});
185-
}));
171+
it('should set the restrictedAccessMessage to a simple "forbidden" message', () => {
172+
expect(component.restrictedAccessMessage.value).toBe('bitstream.restricted-access.anonymous.forbidden.message');
173+
});
186174
});
187175

188176
describe('when file is restricted for non-embargo reasons (such as Campus IP restriction)', () => {
189177
setupAnonymous({ embargoRestriction:null });
190178

191179
verify401StatusCodeAndNoRedirectToDownload();
192180

193-
it('should set the restrictedAccessMessage to a simple "forbidden" message', waitForAsync(() => {
194-
fixture.whenStable().then(() => {
195-
expect(component.restrictedAccessMessage.value).toBe('bitstream.restricted-access.anonymous.forbidden.message');
196-
});
197-
}));
181+
it('should set the restrictedAccessMessage to a simple "forbidden" message', () => {
182+
expect(component.restrictedAccessMessage.value).toBe('bitstream.restricted-access.anonymous.forbidden.message');
183+
});
198184
});
199185

200-
describe('when the user is authorized (even if there is an embargo)', () => {
186+
describe('but the user is authorized (even if there is an embargo)', () => {
201187
beforeEach(waitForAsync(() => {
202188
init();
203189
(authService.isAuthenticated as jasmine.Spy).and.returnValue(observableOf(false));
@@ -211,23 +197,17 @@ describe('RestrictedAccessComponent', () => {
211197
fixture.detectChanges();
212198
});
213199

214-
it('should redirect to the content link', waitForAsync(() => {
215-
fixture.whenStable().then(() => {
216-
expect(hardRedirectService.redirect).toHaveBeenCalled();
217-
});
218-
}));
200+
it('should redirect to the content link', () => {
201+
expect(hardRedirectService.redirect).toHaveBeenCalled();
202+
});
219203

220-
it('should NOT call setUnauthorized', waitForAsync(() => {
221-
fixture.whenStable().then(() => {
222-
expect(serverResponseService.setUnauthorized).not.toHaveBeenCalled();
223-
});
224-
}));
204+
it('should NOT call setUnauthorized', () => {
205+
expect(serverResponseService.setUnauthorized).not.toHaveBeenCalled();
206+
});
225207

226-
it('should NOT call setForbidden', waitForAsync(() => {
227-
fixture.whenStable().then(() => {
228-
expect(serverResponseService.setForbidden).not.toHaveBeenCalled();
229-
});
230-
}));
208+
it('should NOT call setForbidden', () => {
209+
expect(serverResponseService.setForbidden).not.toHaveBeenCalled();
210+
});
231211
});
232212
});
233213

@@ -246,34 +226,45 @@ describe('RestrictedAccessComponent', () => {
246226
fixture.detectChanges();
247227
});
248228

249-
it('should call setForbidden on ServerResponseService', waitForAsync(() => {
250-
fixture.whenStable().then(() => {
251-
expect(serverResponseService.setForbidden).toHaveBeenCalled();
252-
});
253-
}));
229+
it('should call setForbidden on ServerResponseService', () => {
230+
expect(serverResponseService.setForbidden).toHaveBeenCalled();
231+
});
254232

255-
it('should NOT call setUnauthorized on ServerResponseService', waitForAsync(() => {
256-
fixture.whenStable().then(() => {
257-
expect(serverResponseService.setUnauthorized).not.toHaveBeenCalled();
258-
});
259-
}));
233+
it('should NOT call setUnauthorized on ServerResponseService', () => {
234+
expect(serverResponseService.setUnauthorized).not.toHaveBeenCalled();
235+
});
260236

261-
it('should NOT redirect to a download', waitForAsync(() => {
262-
fixture.whenStable().then(() => {
263-
expect(hardRedirectService.redirect).not.toHaveBeenCalled();
264-
});
265-
}));
237+
it('should NOT redirect to a download', () => {
238+
expect(hardRedirectService.redirect).not.toHaveBeenCalled();
239+
});
240+
241+
it('should set the restrictedAccessHeader', () => {
242+
expect(component.restrictedAccessHeader.value).toBe('bitstream.restricted-access.user.forbidden.header');
243+
});
244+
245+
it('should set the restrictedAccessMessage', () => {
246+
expect(component.restrictedAccessMessage.value).toBe(
247+
'bitstream.restricted-access.user.forbidden.with_file.message');
248+
});
249+
});
266250

267-
it('should set the restrictedAccessHeader', waitForAsync(() => {
268-
fixture.whenStable().then(() => {
269-
expect(component.restrictedAccessHeader.value).toBe('bitstream.restricted-access.user.forbidden.header');
270-
});
251+
describe('returns 403 Forbidden with a generic message when no filename is not provided', () => {
252+
beforeEach(waitForAsync(() => {
253+
init({ metadata: {} });
254+
(authService.isAuthenticated as jasmine.Spy).and.returnValue(observableOf(true));
255+
(authorizationService.isAuthorized as jasmine.Spy).and.returnValue(observableOf(false));
256+
initTestBed();
271257
}));
272-
it('should set the restrictedAccessMessage', waitForAsync(() => {
273-
fixture.whenStable().then(() => {
274-
expect(component.restrictedAccessMessage.value).toBe(
275-
'bitstream.restricted-access.user.forbidden.with_file.message');
276-
});
258+
259+
beforeEach(() => {
260+
fixture = TestBed.createComponent(RestrictedAccessComponent);
261+
component = fixture.componentInstance;
262+
fixture.detectChanges();
263+
});
264+
265+
it('should set the generic forbidden message', waitForAsync(() => {
266+
expect(component.restrictedAccessMessage.value).toBe(
267+
'bitstream.restricted-access.user.forbidden.generic.message');
277268
}));
278269
});
279270

@@ -291,23 +282,17 @@ describe('RestrictedAccessComponent', () => {
291282
fixture.detectChanges();
292283
});
293284

294-
it('should NOT call setUnauthorized', waitForAsync(() => {
295-
fixture.whenStable().then(() => {
296-
expect(serverResponseService.setUnauthorized).not.toHaveBeenCalled();
297-
});
298-
}));
285+
it('should NOT call setUnauthorized', () => {
286+
expect(serverResponseService.setUnauthorized).not.toHaveBeenCalled();
287+
});
299288

300-
it('should NOT call setForbidden', waitForAsync(() => {
301-
fixture.whenStable().then(() => {
302-
expect(serverResponseService.setForbidden).not.toHaveBeenCalled();
303-
});
304-
}));
289+
it('should NOT call setForbidden', () => {
290+
expect(serverResponseService.setForbidden).not.toHaveBeenCalled();
291+
});
305292

306-
it('should redirect to the file download link', waitForAsync(() => {
307-
fixture.whenStable().then(() => {
308-
expect(hardRedirectService.redirect).toHaveBeenCalledWith('content-url-with-headers');
309-
});
310-
}));
293+
it('should redirect to the file download link', () => {
294+
expect(hardRedirectService.redirect).toHaveBeenCalledWith('content-url-with-headers');
295+
});
311296
});
312297
});
313298

src/app/restricted-access/restricted-access.component.ts

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@ import {
55
} from '@angular/common';
66
import {
77
Component,
8+
DestroyRef,
9+
inject,
810
OnInit,
911
} from '@angular/core';
12+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
1013
import {
1114
ActivatedRoute,
1215
Router,
@@ -18,6 +21,7 @@ import {
1821
import {
1922
BehaviorSubject,
2023
combineLatest as observableCombineLatest,
24+
EMPTY,
2125
filter,
2226
map,
2327
Observable,
@@ -68,6 +72,8 @@ export class RestrictedAccessComponent implements OnInit {
6872
bitstreamRD$: Observable<RemoteData<Bitstream>>;
6973
bitstream$: Observable<Bitstream>;
7074

75+
private destroyRef = inject(DestroyRef);
76+
7177
constructor(
7278
private route: ActivatedRoute,
7379
protected router: Router,
@@ -112,15 +118,17 @@ export class RestrictedAccessComponent implements OnInit {
112118
return [isAuthorized, isLoggedIn, bitstream, fileLink];
113119
}));
114120
} else {
115-
return [[isAuthorized, isLoggedIn, bitstream, '']];
121+
return observableOf([isAuthorized, isLoggedIn, bitstream, ''] as [boolean, boolean, Bitstream, string]);
116122
}
117123
}),
118-
).subscribe(([isAuthorized, isLoggedIn, bitstream, fileLink]: [boolean, boolean, Bitstream, string]) => {
119-
if (isAuthorized && isNotEmpty(fileLink)) {
120-
// This shouldn't happen, as the download is authorized, and the file link is available, so just redirect to
121-
// actual download page.
122-
this.hardRedirectService.redirect(fileLink);
123-
} else {
124+
switchMap(([isAuthorized, isLoggedIn, bitstream, fileLink]: [boolean, boolean, Bitstream, string]) => {
125+
if (isAuthorized && isNotEmpty(fileLink)) {
126+
// This shouldn't happen, as the download is authorized, and the file link is available, so just redirect to
127+
// actual download page.
128+
this.hardRedirectService.redirect(fileLink);
129+
return EMPTY;
130+
}
131+
124132
let header$: Observable<string>;
125133
let message$: Observable<string>;
126134

@@ -130,7 +138,7 @@ export class RestrictedAccessComponent implements OnInit {
130138
this.responseService.setForbidden();
131139
header$ = this.translateService.get('bitstream.restricted-access.user.forbidden.header', {});
132140

133-
if (bitstream && bitstream.metadata['dc.title'] && bitstream.metadata['dc.title'][0] && bitstream.metadata['dc.title'][0].value) {
141+
if (bitstream && bitstream.metadata['dc.title'] && bitstream.metadata['dc.title'][0] && bitstream.metadata['dc.title'][0].value) {
134142
const filename = bitstream.metadata['dc.title'][0].value;
135143
message$ = this.translateService.get(
136144
'bitstream.restricted-access.user.forbidden.with_file.message', { 'filename': filename });
@@ -145,11 +153,12 @@ export class RestrictedAccessComponent implements OnInit {
145153
[header$, message$] = this.configureAnonymous(bitstream);
146154
}
147155

148-
zip(header$, message$).subscribe(([header, message]) => {
149-
this.restrictedAccessHeader.next(header);
150-
this.restrictedAccessMessage.next(message);
151-
});
152-
}
156+
return zip(header$, message$);
157+
}),
158+
takeUntilDestroyed(this.destroyRef),
159+
).subscribe(([header, message]: [string, string]) => {
160+
this.restrictedAccessHeader.next(header);
161+
this.restrictedAccessMessage.next(message);
153162
});
154163
}
155164

0 commit comments

Comments
 (0)