如何在 angular 测试中等待 xhr 请求
How to wait for an xhr request in an angular test
我有一个带按钮的组件。单击按钮时,会发出 HTTP 请求:
this.tokensService.create(this.userInCreation).subscribe(nextCb, errorCb);
如何等待这个请求完成?使用 async
实用程序和 fixture.whenStable
对我没有帮助。
例如:
it('', async( async () => {
fixture.detectChanges();
appPage.loginButtonEl.click(); // XHR request is initiated here
fixture.detectChanges();
await fixture.whenStable();
// HTTP request is still pending here
}))
编辑:糟糕,我误会了什么。但我仍然认为您可以通过监视发生点击的组件来解决它,然后在测试中订阅服务功能,请参阅 stackblitz。
对于您的测试,这意味着以下内容:
it('', (done) => {
fixture.detectChanges();
// set up spy for the function that gets called in your click() function
// and basically replacing it with your own implementation here so you can
// subscribe to it and wait for completion
let spy = spyOn(appPage, 'myFunction').and.callFake(() => {
tokensService.create(appPage.userInCreation)
.subscribe(data => {
fixture.detectChanges();
// more expect statements or whatever you need here
done();
});
});
appPage.loginButtonEl.click();
});
您可以使用 fakeAsync
而不是 async()
。我创建了一个组件,一个 HTTP_INTERCEPTOR 到 return 1000 毫秒后的响应。这是代码
noop-interceptor.ts
import { Injectable } from '@angular/core';
import {
HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpResponse
} from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { delay } from 'rxjs/operators';
/** Pass untouched request through to the next request handler. */
@Injectable()
export class NoopInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler):
Observable<HttpEvent<any>> {
let response = new HttpResponse();
response = response.clone({body: 'body'});
return of(response).pipe(delay(1000));
}
}
app.component.ts
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
data;
constructor(private http: HttpClient){}
getData(){
this.http.post('asd',{}).subscribe(data => {
console.log(data);
this.data = data;
});
}
}
app.component.html
<input type='button' (click)='getData()' value='Get Data' />
<div class='response'>{{data}}</div>
app.component.spec.ts
import { TestBed, async, ComponentFixture, tick, fakeAsync } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { NoopInterceptor } from './noop-interceptor';
import { By } from '@angular/platform-browser';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
imports: [
HttpClientModule
],
providers: [{ provide: HTTP_INTERCEPTORS, useClass: NoopInterceptor, multi: true }],
}).compileComponents();
}));
it('should create the app', async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
}));
it('should return response',fakeAsync(()=>{
const fixture = TestBed.createComponent(AppComponent);
const component = fixture.debugElement.componentInstance;
fixture.detectChanges();
component.getData();
tick(1000);
fixture.detectChanges();
expect(component.data).toBe('body');
}));
it('should display response',fakeAsync(()=>{
const fixture = TestBed.createComponent(AppComponent);
const component = fixture.debugElement.componentInstance;
fixture.detectChanges();
component.getData();
tick(1000);
fixture.detectChanges();
let element = fixture.debugElement.query(By.css('.response')).nativeElement;
expect(element.textContent).toBe('body');
}));
});
注意tick(1000)
,这将提前虚拟时钟
你需要import 'zone.js/dist/zone-testing';
。如果项目是使用 angular-cli 创建的,那么它已经存在于 test.ts
中
阅读此处的指南以了解有关测试异步服务的更多信息:
https://angular.io/guide/testing#component-with-async-service
用 fakeAsync
包装你的测试并在你的测试中添加 tick()
。
it('', fakeAsync( async () => {
fixture.detectChanges();
appPage.loginButtonEl.click(); // XHR request is initiated here
tick();
fixture.detectChanges();
await fixture.whenStable();
// HTTP request is still pending here
}))
参考:
https://angular.io/api/core/testing/tick
https://angular.io/api/core/testing/fakeAsync
我有一个带按钮的组件。单击按钮时,会发出 HTTP 请求:
this.tokensService.create(this.userInCreation).subscribe(nextCb, errorCb);
如何等待这个请求完成?使用 async
实用程序和 fixture.whenStable
对我没有帮助。
例如:
it('', async( async () => {
fixture.detectChanges();
appPage.loginButtonEl.click(); // XHR request is initiated here
fixture.detectChanges();
await fixture.whenStable();
// HTTP request is still pending here
}))
编辑:糟糕,我误会了什么。但我仍然认为您可以通过监视发生点击的组件来解决它,然后在测试中订阅服务功能,请参阅 stackblitz。
对于您的测试,这意味着以下内容:
it('', (done) => {
fixture.detectChanges();
// set up spy for the function that gets called in your click() function
// and basically replacing it with your own implementation here so you can
// subscribe to it and wait for completion
let spy = spyOn(appPage, 'myFunction').and.callFake(() => {
tokensService.create(appPage.userInCreation)
.subscribe(data => {
fixture.detectChanges();
// more expect statements or whatever you need here
done();
});
});
appPage.loginButtonEl.click();
});
您可以使用 fakeAsync
而不是 async()
。我创建了一个组件,一个 HTTP_INTERCEPTOR 到 return 1000 毫秒后的响应。这是代码
noop-interceptor.ts
import { Injectable } from '@angular/core';
import {
HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpResponse
} from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { delay } from 'rxjs/operators';
/** Pass untouched request through to the next request handler. */
@Injectable()
export class NoopInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler):
Observable<HttpEvent<any>> {
let response = new HttpResponse();
response = response.clone({body: 'body'});
return of(response).pipe(delay(1000));
}
}
app.component.ts
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
data;
constructor(private http: HttpClient){}
getData(){
this.http.post('asd',{}).subscribe(data => {
console.log(data);
this.data = data;
});
}
}
app.component.html
<input type='button' (click)='getData()' value='Get Data' />
<div class='response'>{{data}}</div>
app.component.spec.ts
import { TestBed, async, ComponentFixture, tick, fakeAsync } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { NoopInterceptor } from './noop-interceptor';
import { By } from '@angular/platform-browser';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
imports: [
HttpClientModule
],
providers: [{ provide: HTTP_INTERCEPTORS, useClass: NoopInterceptor, multi: true }],
}).compileComponents();
}));
it('should create the app', async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
}));
it('should return response',fakeAsync(()=>{
const fixture = TestBed.createComponent(AppComponent);
const component = fixture.debugElement.componentInstance;
fixture.detectChanges();
component.getData();
tick(1000);
fixture.detectChanges();
expect(component.data).toBe('body');
}));
it('should display response',fakeAsync(()=>{
const fixture = TestBed.createComponent(AppComponent);
const component = fixture.debugElement.componentInstance;
fixture.detectChanges();
component.getData();
tick(1000);
fixture.detectChanges();
let element = fixture.debugElement.query(By.css('.response')).nativeElement;
expect(element.textContent).toBe('body');
}));
});
注意tick(1000)
,这将提前虚拟时钟
你需要import 'zone.js/dist/zone-testing';
。如果项目是使用 angular-cli 创建的,那么它已经存在于 test.ts
阅读此处的指南以了解有关测试异步服务的更多信息:
https://angular.io/guide/testing#component-with-async-service
用 fakeAsync
包装你的测试并在你的测试中添加 tick()
。
it('', fakeAsync( async () => {
fixture.detectChanges();
appPage.loginButtonEl.click(); // XHR request is initiated here
tick();
fixture.detectChanges();
await fixture.whenStable();
// HTTP request is still pending here
}))
参考:
https://angular.io/api/core/testing/tick
https://angular.io/api/core/testing/fakeAsync