diff --git a/README.md b/README.md index febea83ab5..711799511e 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ I'm open to contributions. - [a routing guard](#how-to-test-a-routing-guard) - [a routing resolver](#how-to-test-a-routing-resolver) - [a http request](#how-to-test-a-http-request) + - [a http interceptor](#how-to-test-a-http-interceptor) --- @@ -1380,6 +1381,13 @@ beforeEach(() => // at all? The answer is to exclude `NG_GUARDS` token, it will removal // all the guards from routes except the explicitly configured ones. beforeEach(() => MockBuilder(MyGuard, MyModule).exclude(NG_GUARDS)); +// The same thing if we want to test interceptors. If we exclude +// `NG_INTERCEPTORS` token, then all interceptors with `useValue` or +// `useFactory` will be excluded together with other interceptors +// except the explicitly configured ones. +beforeEach(() => + MockBuilder(MyInterceptor, MyModule).exclude(NG_INTERCEPTORS) +); // If we want to replace something with something, // we should use .replace. diff --git a/examples/TestHttpInterceptor/test.spec.ts b/examples/TestHttpInterceptor/test.spec.ts index 0f547c322d..82f5742acc 100644 --- a/examples/TestHttpInterceptor/test.spec.ts +++ b/examples/TestHttpInterceptor/test.spec.ts @@ -10,7 +10,7 @@ import { import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { Injectable, NgModule } from '@angular/core'; import { TestBed } from '@angular/core/testing'; -import { MockBuilder } from 'ng-mocks'; +import { MockBuilder, NG_INTERCEPTORS } from 'ng-mocks'; import { Observable } from 'rxjs'; // An interceptor we want to test. @@ -29,15 +29,37 @@ class TargetInterceptor implements HttpInterceptor { } } +// An interceptor we want to ignore. +@Injectable() +class MockedInterceptor implements HttpInterceptor { + protected value = 'Ignore'; + + public intercept(request: HttpRequest, next: HttpHandler): Observable> { + return next.handle( + request.clone({ + setHeaders: { + 'My-Mocked': this.value, + }, + }) + ); + } +} + // A module with its definition. @NgModule({ imports: [HttpClientModule], providers: [ TargetInterceptor, + MockedInterceptor, + { + multi: true, + provide: HTTP_INTERCEPTORS, + useExisting: TargetInterceptor, + }, { multi: true, provide: HTTP_INTERCEPTORS, - useClass: TargetInterceptor, + useExisting: MockedInterceptor, }, ], }) @@ -51,6 +73,7 @@ describe('TestHttpInterceptor', () => { // with HttpClientTestingModule. beforeEach(() => MockBuilder(TargetInterceptor, TargetModule) + .exclude(NG_INTERCEPTORS) .keep(HTTP_INTERCEPTORS) .replace(HttpClientModule, HttpClientTestingModule) ); diff --git a/lib/mock-service/mock-service.ts b/lib/mock-service/mock-service.ts index f7db3e8d06..94509b77cf 100644 --- a/lib/mock-service/mock-service.ts +++ b/lib/mock-service/mock-service.ts @@ -1,6 +1,6 @@ import { Injector, Provider } from '@angular/core'; -import { isNgInjectionToken, NG_GUARDS } from '../common'; +import { isNgInjectionToken, NG_GUARDS, NG_INTERCEPTORS } from '../common'; import { ngMocksUniverse } from '../common/ng-mocks-universe'; import { MockProvider } from '../mock-module'; @@ -310,6 +310,30 @@ const mockServiceHelperPrototype = { return; } + if ( + ngMocksUniverse.builder.has(NG_INTERCEPTORS) && + ngMocksUniverse.builder.get(NG_INTERCEPTORS) === null && + isNgInjectionToken(provider) && + provider.toString() === 'InjectionToken HTTP_INTERCEPTORS' && + provider !== def + ) { + const interceptor = def.useExisting || def.useClass; + if (!ngMocksUniverse.builder.has(interceptor) || ngMocksUniverse.builder.get(interceptor) === null) { + /* istanbul ignore else */ + if (changed) { + changed(true); + } + return; + } + if (def.useFactory || def.useValue) { + /* istanbul ignore else */ + if (changed) { + changed(true); + } + return; + } + } + ngMocksUniverse.touches.add(provider); // Then we check decisions whether we should keep or replace a def.