【问题标题】:Could not test angular http interceptor with Karma and Jasmine无法使用 Karma 和 Jasmine 测试 Angular http 拦截器
【发布时间】:2018-12-05 10:21:06
【问题描述】:

我正在尝试测试 http 拦截器,但找不到任何方法。

我不知道为什么 url 不匹配,因为我的令牌是在控制台中登录的,并且请求 url 也是一样的。我在没有拦截器的情况下使用此方法测试了所有其他 http 服务,一切都通过了...

这是拦截器类,代码工作并在每个请求中添加我的不记名令牌,它使用在测试中模拟的 Ionic Platform 原生类:

@Injectable()
export class AddHeaderInterceptor implements HttpInterceptor {

  public constructor(
      private auth: AuthService, private platform: Platform, 
      private config: ConfigurationService
  ) {}

  public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    console.debug('req', req.url);
    return Observable.fromPromise(this.platform.ready())
      .switchMap(() => Observable.fromPromise(this.auth.getToken()))
      .switchMap((tokens: TokenCacheItem[]) => {
        const baseUrl = new RegExp(this.config.getValue('baseUrl'), 'g');
        if (! req.url.match(baseUrl)) {
          return Observable.of(null);
        }
        if (tokens.length > 0) {
          return Observable.of(tokens[0].accessToken);
        }
        return Observable.throw(null);
      })
      .switchMap((token: string) => {
        console.debug('token', token);
        if (!token || token === null) {
          return next.handle(req);
        }
        const headers = req.headers
          .set('Authorization', `Bearer ${token}`)
          .append('Content-Type', 'application/json');
        const clonedRequest = req.clone({ headers });
        return next.handle(clonedRequest);
    });
  }
}

令牌被记录在业力控制台,我也检查了 url 并且总是有好的 url,但是测试失败了。

这是我的身份验证服务模拟:

export class AuthServiceMock {
  getToken() {
    return Promise.resolve([
      { accessToken: 'TEST' }
    ]);
  }
}

平台模拟:

export class PlatformMock {
  public ready(): Promise<string> {
    return Promise.resolve('READY');
  }
}

这是测试:

describe('AddHeaderInterceptor Service', () => {

  let http: HttpTestingController;
  let httpClient: HttpClient;
  let auth: AuthService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [
        ConfigurationService,
        {
          provide: HTTP_INTERCEPTORS,
          useClass: AddHeaderInterceptor,
          multi: true,
        },
        { provide: Platform, useClass: PlatformMock },
        { provide: LogService, useClass: LogServiceMock },
        { provide: AuthService, useClass: AuthServiceMock }
      ],
    });
    http = TestBed.get(HttpTestingController);
    httpClient = TestBed.get(HttpClient);
    auth = TestBed.get(AuthService);
  });

  it('should add Auth header to request', () => {
    httpClient.get('/test').subscribe(res => expect(res).toBeTruthy());
    const req = http.expectOne({ method: 'GET' });
    expect(req.request.url.includes('test')).toBeTruthy();
    expect(req.request.headers.has('Authorization')).toBeTruthy();
    expect(req.request.headers.get('Authorization')).toEqual('Bearer TEST');
    req.flush({
      hello: 'world'
    });
  });
});

我总是遇到同样的错误:

错误:预期有一个对条件“匹配方法:GET,URL:(any)”的匹配请求,但没有找到。

看起来请求从未启动,我试图创建一个类实例并直接调用拦截方法,但我已经得到了同样的错误。 我试图从身份验证服务中窥探getTokenmethod,但它从未被调用过。 所以我不知道为什么它失败了。

我尝试使用另一个 url 调用另一个服务,但仍然遇到同样的错误。

我尝试在http.expectOne('http://localhost:8080/test') 中使用绝对或相对网址,但还是一样:

预期有一个条件匹配请求“匹配 URL: http://localhost:8080/test",没有找到。

有人有想法吗?

【问题讨论】:

    标签: angular unit-testing typescript ionic3 karma-jasmine


    【解决方案1】:

    我找到了一个使用 karma done 函数并直接构造 Addheader 对象的解决方案:

    fdescribe('AddHeaderInterceptor Service', () => {
    
      let http: HttpTestingController;
      let httpClient: HttpClient;
      let auth: AuthService;
      let logger: LogService;
      let config: ConfigurationService;
      let platform: Platform;
      let interceptor: AddHeaderInterceptor;
    
      beforeEach(() => {
        TestBed.configureTestingModule({
          imports: [HttpClientTestingModule],
          providers: [
            ConfigurationService,
            {
              provide: HTTP_INTERCEPTORS,
              useClass: AddHeaderInterceptor,
              multi: true,
            },
            { provide: Platform, useClass: PlatformMocked },
            { provide: LogService, useClass: LogServiceMock },
            { provide: AuthService, useClass: AuthServiceMock }
          ],
        });
        config = TestBed.get(ConfigurationService);
        auth = TestBed.get(AuthService);
        logger = TestBed.get(LogService);
        platform = TestBed.get(Platform);
        httpClient = TestBed.get(HttpClient);
        http = TestBed.get(HttpTestingController);
        interceptor = new AddHeaderInterceptor(logger, auth, platform, config);
      });
    
      fit('should add header to request', (done) => {
        expect((interceptor as any) instanceof AddHeaderInterceptor).toBeTruthy();
        const next: any = {
          handle: (request: HttpRequest<any>) => {
            expect(request.headers.has('Authorization')).toBeTruthy();
            expect(request.headers.get('Authorization')).toEqual('Bearer TESTO');
            return Observable.of({ hello: 'world' });
          }
        };
        const req = new HttpRequest<any>('GET', config.getValue('baseUrl') + 'test');
        interceptor.intercept(req, next).subscribe(obj => done());
      });
    
    });
    

    【讨论】:

      【解决方案2】:

      当我开始在拦截器中使用相同的 fromPromise -> switchMap 模式时,我遇到了同样的情况。这似乎导致了测试问题(尽管代码似乎工作正常)。没有对承诺的调用,它可以正常工作。

      不知道为什么 - 但您的测试解决方案对我有用。谢谢!

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-05
      • 2018-10-25
      • 1970-01-01
      相关资源
      最近更新 更多