Как заблокировать асинхронные обратные вызовы внутри конструкторов для тестирования? - PullRequest
2 голосов
/ 06 июня 2019

Я сейчас пытаюсь написать тесты на ионные. Мои автоматически созданные тесты заканчиваются до выполнения асинхронного обратного вызова. Как я могу определить, когда обратные вызовы в конструкторах завершены, чтобы я мог выполнить свои проверки?

Обещания не являются опцией для этого, потому что TestBed.createComponent уже возвращает фиксатор и не может вернуть обещание.

Если бы я реализовал обратный вызов done (), мне пришлось бы изменить сигнатуру конструктора, чтобы включить обратный вызов, и это выглядит как плохая практика.

Тестовый файл:

  it('should initialize the app', () => {

    const fixture = TestBed.createComponent(AppComponent);
    fixture.detectChanges(); 

    of(expect(platformSpy.ready).toHaveBeenCalled()).subscribe(async () => {
      expect(statusBarSpy.styleDefault).toHaveBeenCalled();
      expect(splashScreenSpy.hide).toHaveBeenCalled();
      console.log("Tests have completed execution!");
      return of(null)
    });
  });

Машинописание компонентов:

  constructor(...) {
    this.initializeApp();
  }

  initializeApp() {
    // Check session already setup
    this.platform.ready()
      .then(() => this.store.dispatch(new CheckSessionAction(this)))
      .then(() => {
        /** StatusBar and SplashScreen is only for Mobile Devices */
        console.log("isMobileDevice: " + this.helper.isMobileDevice());

        if (this.helper.isMobileDevice()) {
          this.statusBar.styleDefault();
          this.splashScreen.hide();
        }

        console.log("Initialization has completed execution");
      });
  }

Файл console.logs печатается в следующем порядке:

Испытания завершены

isMobileDevice: true

Инициализация завершила выполнение

Ответы [ 2 ]

3 голосов
/ 06 июня 2019

Вы должны поместить вызов функции initializeApp в хук жизненного цикла ngOnInit. Это лучший способ совершать такие звонки. Тогда при тестировании вам не нужно беспокоиться о том, что конструктор делает такие вызовы.

Кроме того, если у вас есть асинхронный вызов, с которым вам нужно поработать, вы можете заключить тест в async или fakeAsync и tick, чтобы заставить тест дождаться завершения вызова. Их можно импортировать из библиотеки тестирования Angular.

0 голосов
/ 07 июня 2019

Во-первых, решение @ pjlamb12 работает, у меня работает следующий код

it('should initialize the app: mobile', fakeAsync(() => {
  utilSpy.isMobileDevice.and.returnValue(true);

  const fixture = TestBed.createComponent(AppComponent);
  fixture.detectChanges(); 

  expect(platformSpy.ready).toHaveBeenCalled()

  of(expect(platformSpy.ready).toHaveBeenCalled()).subscribe(() => {
    tick()
    expect(statusBarSpy.styleDefault).toHaveBeenCalled();
    expect(splashScreenSpy.hide).toHaveBeenCalled();
    return of(null)
  });

  fixture.destroy();
  flush();
}));

Я также нашел другое решение, используя fixture.whenStable(), чтобы определить, когда компонент завершил рендеринг.Этот на самом деле выполняет обратные вызовы во времени вместо имитации времени, что может быть полезно в некоторых случаях.

it('should initialize the app: mobile', async(() => {
  utilSpy.isMobileDevice.and.returnValue(true);

  const fixture = TestBed.createComponent(AppComponent);
  fixture.detectChanges(); 

  expect(platformSpy.ready).toHaveBeenCalled()

  fixture.whenStable().then(() => {
    expect(statusBarSpy.styleDefault).toHaveBeenCalled();
    expect(splashScreenSpy.hide).toHaveBeenCalled();
    return of(null)
  });
}));
...