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);
})
);
}
从昨天中午开始,我一直在努力对我的拦截器进行单元测试。在遵循了几个教程和 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);
})
);
}