Why am I getting Error: Timeout in my Jasmine unit test of http interceptor?

Why am I getting Error: Timeout in my Jasmine unit test of http interceptor?

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

Error: Timeout - Async function did not complete within 5000ms (set by jasmine.DEFAULT_TIMEOUT_INTERVAL) Error: Timeout - Async function did not complete within 5000ms (set by jasmine.DEFAULT_TIMEOUT_INTERVAL) at Jasmine

编辑:我刚刚添加了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();
  });

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

Cannot read property 'callThrough' of undefined

为什么 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);
  }

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

 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);
        })
      );
  }