Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
562 views
in Technique[技术] by (71.8m points)

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

I am struggling with unit testing my interceptor since yesterday noon. After following several tutorial and SO answers, I have a code that so far looks the best. BUT, because of some reason I am getting an error:

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

EDIT: I just added Stackblitz example.

my test:

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

NOTE: console.log in the test are not called;

test preparation:

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

NOTE: when using .and.callThrough(); on errorsMock it throws an error:

Cannot read property 'callThrough' of undefined

Why errorsMock is undefined?

Interceptor by himself:

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

And http.service method:

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I took the time to read your interceptor and turns out your implemention is wrong, you should return an observeble:

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
...