Угловое тестирование с интервалом ()

В моем ngOnInit я проверяю маршрут, делаю кое-что, а затем устанавливаю interval

ngOnInit(): void {
    this.routeSubscription = this.route.paramMap.subscribe(x => {
         ...
         // Reload the data every 60 seconds
         interval(60_000)
             .pipe(takeUntil(this.cancelInterval$))
             .subscribe(() => this.rows$ = this.orderService.active())
    })
}

Когда я пытаюсь выполнить модульное тестирование, jasmine прерывается, потому что метод async не вернулся достаточно быстро. Я делаю это (как подописание основного, которое выполняет все обычные TestBed настройки):

describe('when showing active orders', () => {
    beforeEach(() => {
        activatedRoute.setParamMap({})
        fixture.detectChanges()
    })

    it('...', async () => {
        await fixture.whenStable()
        ...
    })

Вроде застрял из-за антракта. Я думал, что могу просто вызвать discardPeriodicTasks() в конце метода beforeEach, но это не сработало.

Поэтому я ищу либо правильный способ справиться с этим при тестировании, либо способ в производственном коде делать интервальный вызов только в том случае, если он не запускается через тестирование.

Angular CLI: 9.0.7
Узел: 14.4.0
Angular: 9.1.6


person Gargoyle    schedule 17.06.2020    source источник


Ответы (2)


Вы можете использовать fakeAsync и поставить галочку, чтобы имитировать асинхронное поведение.

it('...', fakeAsync () => { tick(60000); doTestStuff(); })

person phhbr    schedule 18.09.2020
comment
В моем понимании это не сработает. Проблема с interval () заключается в том, что он постоянно планирует следующий тайм-аут, а среда модульного тестирования ждет вечно, пока не закончатся все открытые тайм-ауты. - person Vilmantas Baranauskas; 18.09.2020
comment
ну, я бы ожидал ngOnDestroy на компоненте, который закроет интервал (this.cancelInterval $) на компоненте и будет вызван после успешного утверждения .. - person phhbr; 18.09.2020

Вместо прямого вызова RXJS interval() создайте простой промежуточный сервис вроде этого:

import { Injectable } from '@angular/core';
import { interval } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class TimerService {

  interval(ms: number) {
      return interval(ms);
  }

}

Внедрить и использовать его в своем компоненте: timer.interval(60_000)

Теперь просто имитировать необходимое поведение interval() в ваших модульных тестах, например:

providers: [{ provide: TimerService, useValue: { interval: () => of(1) } }],
person Vilmantas Baranauskas    schedule 18.09.2020