为什么我在 http 拦截器的 Jasmine 单元测试中收到错误:超时?

问题描述

从昨天中午开始,我就一直在努力对我的拦截器进行单元测试。在遵循几个教程和 SO 答案之后,我有一个迄今为止看起来最好的代码。但是,由于某种原因,我收到了一个错误

错误:超时 - 异步功能未在 5000 毫秒内完成(由 jasmine.DEFAULT_TIMEOUT_INTERVAL) 错误:超时 - 异步函数做了 未在 5000 毫秒内完成(由 jasmine.DEFAULT_TIMEOUT_INTERVAL 设置) 在茉莉花

编辑:我刚刚添加Stackblitz example

我的测试:

it('should display an error message if the request is unauthorized',(done) => {
    service.getGameState('1').subscribe(
      (data) => {
        console.log(data);
        expect(data).toBeNull();
        expect(errorsMock.handleAuthError).toHaveBeenCalledWith('dupa');
        done();
      },(error: HttpErrorResponse) => {
        console.log(error);
        done();
      }
    );

    const testRequest = httpMock.expectOne(
      'http://localhost:50962/api/game/join?id=1'
    );
    expect(testRequest.request.method).toBe('GET');
    testRequest.flush(null,{
      status: 401,statusText: 'Unauthorized request',});
  });

注意:测试中的console.log不被调用

考试准备:

describe('ErrorInterceptor',() => {
  let httpMock: HttpTestingController;
  let injector: Testbed;
  let service: HttpService;
  const errorsMock = jasmine.createSpyObj('ErrorService',[
    'handleBackendError','handleAuthError','handleBotError','handleOtherError',]);

  beforeEach(() => {
    Testbed.configureTestingModule({
      imports: [HttpClientTestingModule,RouterTestingModule.withRoutes([])],providers: [
        HttpService,{
          provide: HTTP_INTERCEPTORS,useClass: ErrorInterceptor,multi: true,},{ provide: ErrorService,useValue: errorsMock },],});

    injector = getTestbed();
    httpMock = injector.inject(HttpTestingController);
    service = Testbed.inject(HttpService);
  });

  afterEach(() => {
    httpMock.verify();
  });

  it('Injector_ShouldBeCreated',() => {
    expect(injector).toBeTruthy();
    expect(service).toBeTruthy();
  });

注意:在 .and.callThrough(); 上使用 errorsMock 时会引发错误

无法读取未定义的属性“callThrough”

为什么 errorsMock 未定义?

自己拦截器:

@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
  constructor(private error: ErrorService) {}

  public intercept(
    request: HttpRequest<any>,next: HttpHandler
  ): Observable<HttpEvent<any>> {
    return new Observable((observer) => {
      next.handle(request).subscribe(
        (res: HttpResponse<any>) => {
          if (res instanceof HttpResponse) {
            observer.next(res);
          }
        },(err: HttpErrorResponse) => {
          this.handleResponseError(err,request,next);
        }
      );
    });
  }

  private handleResponseError(
    error: HttpErrorResponse,request: HttpRequest<any>,next: HttpHandler
  ): any {
    if (request.url.indexOf('refresh') !== -1) {
      return next.handle(request);
    }

    if (error.status === 0) {
      this.error.handleBackendError(error);
    } else if (error.status === 401 || error.status === 403) {
      this.error.handleAuthError(error,next,request);
    } else if (error.status === 429) {
      this.error.handleBotError(error);
    } else {
      this.error.handleOtherError(error);
    }
  }
}

http.service 方法

public getGameState(id: string): Observable<any> {
    const url: string = environment.apiUrl + 'api/game/join?id=' + id;
    return this.http.get(url);
  }

解决方法

我花时间阅读了您的拦截器,结果发现您的实现是错误的,您应该返回一个可观察对象:

 import { catchError } from 'rxjs/operators';

  public intercept(
    request: HttpRequest<any>,next: HttpHandler
  ): Observable<HttpEvent<any>> {
    return next.handle(request).pipe(
        catchError((err) => {
          this.handleResponseError(err,request,next);
          return throwError(err);
        })
      );
  }

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...