Skip to content

Commit 81a353e

Browse files
committed
Feature request : Add possibility to filter by HTTP method
1 parent 0332cc0 commit 81a353e

File tree

4 files changed

+104
-43
lines changed

4 files changed

+104
-43
lines changed

src/lib/components/spinner/spinner.component.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ export class SpinnerComponent implements OnDestroy, OnInit {
3232
@Input()
3333
public filteredUrlPatterns: string[] = [];
3434
@Input()
35+
public filteredMethods: string[] = [];
36+
@Input()
3537
public debounceDelay = 0;
3638
@Input()
3739
public minDuration = 0;
@@ -61,6 +63,11 @@ export class SpinnerComponent implements OnDestroy, OnInit {
6163
this.pendingInterceptorService.filteredUrlPatterns.push(new RegExp(e));
6264
});
6365
}
66+
67+
if (!(this.filteredMethods instanceof Array)) {
68+
throw new TypeError('`filteredMethods` must be an array.');
69+
}
70+
this.pendingInterceptorService.filteredMethods = this.filteredMethods;
6471
}
6572

6673
ngOnDestroy(): void {

src/lib/services/pending-interceptor.service.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export class PendingInterceptorService implements HttpInterceptor {
1919
private _pendingRequests = 0;
2020
private _pendingRequestsStatus: ReplaySubject<boolean> = new ReplaySubject<boolean>(1);
2121
private _filteredUrlPatterns: RegExp[] = [];
22+
private _filteredMethods: string[] = [];
2223
private _forceByPass: boolean;
2324

2425
/** @deprecated Deprecated in favor of pendingRequestsStatus$ */
@@ -38,6 +39,14 @@ export class PendingInterceptorService implements HttpInterceptor {
3839
return this._filteredUrlPatterns;
3940
}
4041

42+
get filteredMethods(): string[] {
43+
return this._filteredMethods;
44+
}
45+
46+
set filteredMethods(httpMethods: string[]) {
47+
this._filteredMethods = httpMethods;
48+
}
49+
4150
set forceByPass(value: boolean) {
4251
this._forceByPass = value;
4352
}
@@ -48,8 +57,16 @@ export class PendingInterceptorService implements HttpInterceptor {
4857
});
4958
}
5059

60+
private shouldBypassMethod(req: HttpRequest<any>): boolean {
61+
return this._filteredMethods.some(e => {
62+
return e.toUpperCase() === req.method.toUpperCase();
63+
});
64+
}
65+
5166
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
52-
const shouldBypass = this.shouldBypassUrl(req.urlWithParams) || this._forceByPass;
67+
const shouldBypass = this.shouldBypassUrl(req.urlWithParams)
68+
|| this.shouldBypassMethod(req)
69+
|| this._forceByPass;
5370

5471
if (!shouldBypass) {
5572
this._pendingRequests++;

src/test/components/spinner/spinner.component.spec.ts

Lines changed: 78 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ describe('SpinnerComponent', () => {
9898
expect(element.style['background-color']).toBe('rgb(255, 0, 0)');
9999
});
100100

101-
it('should show and hide the spinner according to the pending http requests', fakeAsync(inject(
101+
it('should show and hide the spinner according to the pending HTTP requests', fakeAsync(inject(
102102
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
103103

104104
function runQuery(url: string): Observable<any> {
@@ -123,7 +123,7 @@ describe('SpinnerComponent', () => {
123123
}
124124
)));
125125

126-
it('should hide and show a the spinner for a single http request', fakeAsync(inject(
126+
it('should hide and show a the spinner for a single HTTP request', fakeAsync(inject(
127127
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
128128
http.get('/fake').subscribe();
129129

@@ -136,7 +136,7 @@ describe('SpinnerComponent', () => {
136136
}
137137
)));
138138

139-
it('should not show the spinner if the request is filtered', fakeAsync(inject(
139+
it('should not show the spinner if the request is filtered by url', fakeAsync(inject(
140140
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
141141
component.filteredUrlPatterns.push('fake');
142142
fixture.detectChanges();
@@ -148,6 +148,18 @@ describe('SpinnerComponent', () => {
148148
}
149149
)));
150150

151+
it('should not show the spinner if the request is filtered by HTTP method', fakeAsync(inject(
152+
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
153+
component.filteredMethods.push('get');
154+
fixture.detectChanges();
155+
156+
http.get('/fake').subscribe();
157+
tick();
158+
expect(component.isSpinnerVisible).toBeFalsy();
159+
httpMock.expectOne('/fake').flush({});
160+
}
161+
)));
162+
151163
it('should take care of query strings in filteredUrlPatterns', fakeAsync(inject(
152164
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
153165
component.filteredUrlPatterns.push('bar');
@@ -167,7 +179,7 @@ describe('SpinnerComponent', () => {
167179
}
168180
)));
169181

170-
it('should correctly filter with several requests and one pattern', fakeAsync(inject(
182+
it('should correctly filter by URL with several requests and one pattern', fakeAsync(inject(
171183
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
172184
component.filteredUrlPatterns.push('\\d');
173185
fixture.detectChanges();
@@ -187,12 +199,37 @@ describe('SpinnerComponent', () => {
187199
}
188200
)));
189201

202+
it('should correctly filter by HTTP method with several requests', fakeAsync(inject(
203+
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
204+
component.filteredMethods.push('pOsT');
205+
fixture.detectChanges();
206+
207+
http.post('/12345', null).subscribe();
208+
tick();
209+
expect(component.isSpinnerVisible).toBeFalsy();
210+
httpMock.expectOne('/12345').flush({});
211+
212+
http.get('/fake').subscribe();
213+
tick();
214+
expect(component.isSpinnerVisible).toBeTruthy();
215+
httpMock.expectOne('/fake').flush({});
216+
217+
tick();
218+
expect(component.isSpinnerVisible).toBeFalsy();
219+
}
220+
)));
221+
190222
it('should throw an error if filteredUrlPatterns is not an array', () => {
191223
component.filteredUrlPatterns = null;
192224
expect(() => fixture.detectChanges()).toThrow(new Error('`filteredUrlPatterns` must be an array.'));
193225
});
194226

195-
it('should show the spinner even if the component is created after the http request is performed', fakeAsync(inject(
227+
it('should throw an error if filteredMethods is not an array', () => {
228+
component.filteredMethods = null;
229+
expect(() => fixture.detectChanges()).toThrow(new Error('`filteredMethods` must be an array.'));
230+
});
231+
232+
it('should show the spinner even if the component is created after the HTTP request is performed', fakeAsync(inject(
196233
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
197234
http.get('/fake').subscribe();
198235

@@ -209,35 +246,35 @@ describe('SpinnerComponent', () => {
209246
}
210247
)));
211248

212-
it('should correctly handle the debounce delay for a single http request', fakeAsync(inject(
249+
it('should correctly handle the debounce delay for a single HTTP request', fakeAsync(inject(
213250
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
214251
component.debounceDelay = 2000;
215252
http.get('/fake').subscribe();
216253

217-
// the http request is pending for 1 second now
254+
// the HTTP request is pending for 1 second now
218255
tick(1000);
219256
expect(component.isSpinnerVisible).toBeFalsy();
220257

221-
// the http request is pending for 1,999 seconds now
258+
// the HTTP request is pending for 1,999 seconds now
222259
tick(999);
223260
expect(component.isSpinnerVisible).toBeFalsy();
224261

225-
// the http request is pending for 2 seconds now - the spinner will be visible
262+
// the HTTP request is pending for 2 seconds now - the spinner will be visible
226263
tick(1);
227264
expect(component.isSpinnerVisible).toBeTruthy();
228265

229-
// the http request is pending for 5 seconds now - the spinner is still visible
266+
// the HTTP request is pending for 5 seconds now - the spinner is still visible
230267
tick(3000);
231268
expect(component.isSpinnerVisible).toBeTruthy();
232269

233-
// the http request is finally over, the spinner is hidden
270+
// the HTTP request is finally over, the spinner is hidden
234271
httpMock.expectOne('/fake').flush({});
235272
tick();
236273
expect(component.isSpinnerVisible).toBeFalsy();
237274
}
238275
)));
239276

240-
it('should correctly handle the debounce delay for multiple http requests', fakeAsync(inject(
277+
it('should correctly handle the debounce delay for multiple HTTP requests', fakeAsync(inject(
241278
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
242279
component.debounceDelay = 2000;
243280

@@ -250,23 +287,23 @@ describe('SpinnerComponent', () => {
250287
const firstRequest = httpMock.expectOne('/fake');
251288
const secondRequest = httpMock.expectOne('/fake2');
252289

253-
// the http requests are pending for 1 second now
290+
// the HTTP requests are pending for 1 second now
254291
tick(1000);
255292
expect(component.isSpinnerVisible).toBeFalsy();
256293

257-
// the http requests are pending for 1,999 seconds now
294+
// the HTTP requests are pending for 1,999 seconds now
258295
tick(999);
259296
expect(component.isSpinnerVisible).toBeFalsy();
260297

261-
// the http requests are pending for 2 seconds now - the spinner will be visible
298+
// the HTTP requests are pending for 2 seconds now - the spinner will be visible
262299
tick(1);
263300
expect(component.isSpinnerVisible).toBeTruthy();
264301

265-
// the http requests are pending for 5 seconds now - the spinner is still visible
302+
// the HTTP requests are pending for 5 seconds now - the spinner is still visible
266303
tick(3000);
267304
expect(component.isSpinnerVisible).toBeTruthy();
268305

269-
// the first http request is finally over, the spinner is still visible
306+
// the first HTTP request is finally over, the spinner is still visible
270307
firstRequest.flush({});
271308
tick();
272309
expect(component.isSpinnerVisible).toBeTruthy();
@@ -275,7 +312,7 @@ describe('SpinnerComponent', () => {
275312
tick(3000);
276313
expect(component.isSpinnerVisible).toBeTruthy();
277314

278-
// the second http request is finally over, the spinner is hidden
315+
// the second HTTP request is finally over, the spinner is hidden
279316
secondRequest.flush({});
280317
tick();
281318
expect(component.isSpinnerVisible).toBeFalsy();
@@ -292,18 +329,18 @@ describe('SpinnerComponent', () => {
292329
}
293330
));
294331

295-
it('should keep the spinner visible even if an http request ends before calling \'hide\'', fakeAsync(inject(
332+
it('should keep the spinner visible even if an HTTP request ends before calling \'hide\'', fakeAsync(inject(
296333
[SpinnerVisibilityService, HttpClient, HttpTestingController],
297334
(spinner: SpinnerVisibilityService, http: HttpClient, httpMock: HttpTestingController) => {
298335
// we manually show the spinner
299336
spinner.show();
300337
expect(component.isSpinnerVisible).toBeTruthy();
301-
// then an http request is performed
338+
// then an HTTP request is performed
302339
http.get('/fake').subscribe();
303340
tick();
304341
expect(component.isSpinnerVisible).toBeTruthy();
305342

306-
// the http request ends, but we want the spinner to be still visible
343+
// the HTTP request ends, but we want the spinner to be still visible
307344
httpMock.expectOne('/fake').flush({});
308345
tick();
309346
expect(component.isSpinnerVisible).toBeTruthy();
@@ -312,7 +349,7 @@ describe('SpinnerComponent', () => {
312349
// this time the spinner is not visible anymore
313350
expect(component.isSpinnerVisible).toBeFalsy();
314351

315-
// the bypassPendingInterceptorService should be reset for next http requests
352+
// the bypassPendingInterceptorService should be reset for next HTTP requests
316353
http.get('/fake2').subscribe();
317354
tick();
318355
expect(component.isSpinnerVisible).toBeTruthy();
@@ -322,25 +359,25 @@ describe('SpinnerComponent', () => {
322359
}
323360
)));
324361

325-
it('should correctly handle the minimum spinner duration for a single http request', fakeAsync(inject(
362+
it('should correctly handle the minimum spinner duration for a single HTTP request', fakeAsync(inject(
326363
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
327364
component.minDuration = 5000;
328365
http.get('/fake').subscribe();
329366

330-
// the http request is pending for 1 second now
367+
// the HTTP request is pending for 1 second now
331368
tick(1000);
332369
expect(component.isSpinnerVisible).toBeTruthy();
333370

334-
// the http request is pending for 2 seconds now
371+
// the HTTP request is pending for 2 seconds now
335372
tick(1000);
336373
expect(component.isSpinnerVisible).toBeTruthy();
337374

338-
// the http request is finally over, the spinner is still visible
375+
// the HTTP request is finally over, the spinner is still visible
339376
httpMock.expectOne('/fake').flush({});
340377
tick();
341378
expect(component.isSpinnerVisible).toBeTruthy();
342379

343-
// the http request is over but the spinner is still visible after 3 seconds
380+
// the HTTP request is over but the spinner is still visible after 3 seconds
344381
tick(1000);
345382
expect(component.isSpinnerVisible).toBeTruthy();
346383

@@ -358,7 +395,7 @@ describe('SpinnerComponent', () => {
358395
}
359396
)));
360397

361-
it('should correctly handle the minimum spinner duration for multiple http requests', fakeAsync(inject(
398+
it('should correctly handle the minimum spinner duration for multiple HTTP requests', fakeAsync(inject(
362399
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
363400
component.minDuration = 5000;
364401

@@ -371,28 +408,28 @@ describe('SpinnerComponent', () => {
371408
const firstRequest = httpMock.expectOne('/fake');
372409
const secondRequest = httpMock.expectOne('/fake2');
373410

374-
// the http requests are pending for 1 second now
411+
// the HTTP requests are pending for 1 second now
375412
tick(1000);
376413
expect(component.isSpinnerVisible).toBeTruthy();
377414

378-
// the http requests are pending for 2 seconds now
415+
// the HTTP requests are pending for 2 seconds now
379416
tick(1000);
380417
expect(component.isSpinnerVisible).toBeTruthy();
381418

382-
// the first http request is finally over, the spinner is still visible
419+
// the first HTTP request is finally over, the spinner is still visible
383420
firstRequest.flush({});
384421
tick();
385422
expect(component.isSpinnerVisible).toBeTruthy();
386423

387-
// the second http request is still pending after 3 seconds
424+
// the second HTTP request is still pending after 3 seconds
388425
tick(1000);
389426
expect(component.isSpinnerVisible).toBeTruthy();
390427

391-
// the second http request is still pending after 4 seconds
428+
// the second HTTP request is still pending after 4 seconds
392429
tick(1000);
393430
expect(component.isSpinnerVisible).toBeTruthy();
394431

395-
// the second http request is finally over too, the spinner is still visible
432+
// the second HTTP request is finally over too, the spinner is still visible
396433
secondRequest.flush({});
397434
tick();
398435
expect(component.isSpinnerVisible).toBeTruthy();
@@ -403,20 +440,20 @@ describe('SpinnerComponent', () => {
403440
}
404441
)));
405442

406-
it('should still display the spinner when the minimum duration is inferior to the http request duration', fakeAsync(inject(
443+
it('should still display the spinner when the minimum duration is inferior to the HTTP request duration', fakeAsync(inject(
407444
[HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
408445
component.minDuration = 1000;
409446
http.get('/fake').subscribe();
410447

411-
// the http request is pending for 1 second now
448+
// the HTTP request is pending for 1 second now
412449
tick(1000);
413450
expect(component.isSpinnerVisible).toBeTruthy();
414451

415-
// the http request is pending for 2 seconds now
452+
// the HTTP request is pending for 2 seconds now
416453
tick(1000);
417454
expect(component.isSpinnerVisible).toBeTruthy();
418455

419-
// the http request is finally over after 2 seconds, the spinner is hidden
456+
// the HTTP request is finally over after 2 seconds, the spinner is hidden
420457
httpMock.expectOne('/fake').flush({});
421458
tick();
422459
expect(component.isSpinnerVisible).toBeFalsy();
@@ -442,15 +479,15 @@ describe('SpinnerComponent', () => {
442479

443480
http.get('/fake').subscribe();
444481

445-
// the http request is pending for 0,5 second now - spinner not visible because debounce
482+
// the HTTP request is pending for 0,5 second now - spinner not visible because debounce
446483
tick(500);
447484
expect(component.isSpinnerVisible).toBeFalsy();
448485

449-
// the http request is pending for 1 second now - spinner visible
486+
// the HTTP request is pending for 1 second now - spinner visible
450487
tick(500);
451488
expect(component.isSpinnerVisible).toBeTruthy();
452489

453-
// the http request is finally over, the spinner is still visible
490+
// the HTTP request is finally over, the spinner is still visible
454491
httpMock.expectOne('/fake').flush({});
455492
tick();
456493
expect(component.isSpinnerVisible).toBeTruthy();

src/test/services/pending-interceptor.service.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ describe('PendingInterceptorService', () => {
2626
expect(service).toBeTruthy();
2727
}));
2828

29-
it('should be aware of the pending http requests', inject(
29+
it('should be aware of the pending HTTP requests', inject(
3030
[PendingInterceptorService, HttpClient, HttpTestingController],
3131
(service: PendingInterceptorService, http: HttpClient, httpMock: HttpTestingController) => {
3232

0 commit comments

Comments
 (0)