Как ждать xhr-запроса в угловом тесте - PullRequest
0 голосов
/ 04 января 2019

У меня есть компонент с кнопкой.Когда кнопка нажата, делается 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
}))

Ответы [ 3 ]

0 голосов
/ 12 января 2019

Вы можете использовать fakeAsync вместо async().Я создал компонент HTTP_INTERCEPTOR для возврата ответа через 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), это улучшит виртуальные часы

https://angular.io/guide/testing#the-tick-function

Вам нужнодо import 'zone.js/dist/zone-testing';.Если бы проект был создан с использованием angular-cli, он уже был бы там в test.ts

Прочтите здесь руководство, чтобы узнать больше о тестировании asyc-сервисов:

https://angular.io/guide/testing#component-with-async-service

0 голосов
/ 12 января 2019

Оберните свой тест с помощью 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

0 голосов
/ 08 января 2019

Редактировать: Мой плохой, я что-то не так понял.Но я все еще думаю, что вы можете решить эту проблему с помощью шпиона на компоненте, где происходит щелчок, а затем просто подписаться в тесте на сервисную функцию, см. 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();
});
...