Как покрыть функцию setTimeout шпионом документа в Jasmine / Angular?

#javascript #angular #unit-testing #jasmine #karma-jasmine

#javascript #angular #модульное тестирование #jasmine #карма-жасмин

Вопрос:

У меня есть setTimeout внутри ngOnInit , чтобы определить некоторые свойства и запустить функцию. Я хочу протестировать это, но это не входит в setTimeout , пытался использовать tick() и fakeAsync .

Мой код для покрытия модульным тестом Jasmine:

 ngOnInit() {
    setTimeout(() => {
      this.container = document.querySelector(`#field-${this.id}`);
      this.inputField = document.querySelector(`#${this.id}`);

      this.getState();
    }, 50);
}

getState() {
    this.inputField.addEventListener('focus', () => {
      const tooltip = this.container.querySelector('.tooltip');
      const tooltipHeight = tooltip.querySelector('p').clientHeight;

      tooltip.style.height = tooltipHeight   'px';
    });

    this.inputField.addEventListener('blur', () => {
      const tooltip = this.container.querySelector('.tooltip');

      tooltip.style.height = '0px';
    });
}
 

Что я сделал, чтобы покрыть это:

 it('should ', fakeAsync(() => {
    const fixture = TestBed.createComponent(TooltipComponent);
    const componentInst = fixture.componentInstance;
    componentInst.id = 'fieldId';

    
    tick();
    fixture.detectChanges();

    
    fixture.whenStable().then(() => {
        const tooltipContainer = fixture.debugElement.query(By.css('#fieldId'));
        expect(componentInst.container ).toBe(tooltipContainer );
    });
}));
 

Но это не входит в setTimeout функцию, я думаю, мне нужно шпионить document.querySelector .

Как я могу покрыть эту setTimeout функцию?

Комментарии:

1. вам нужно вызвать tick() после регистрации таймера, который после ngOnInit() вызывается (помещается tick() после fixture.detectChanges() )

2. @MikeS. да, я пробовал и это, но все то же самое. Это не входит в setTimeout(() => {

3. tick() просто разрешает обещания. Вы должны указать число, чтобы указать, сколько времени вы хотите пройти. Так что делайте то, что @MikeS. сказано так же, как tick(50) и вместо tick() .

Ответ №1:

Вам нужно вызвать ngOnInit метод компонента, затем вызвать tick(50) ;

Чтобы вызвать ngOnInit , вы должны fixture.detectChanges() сначала вызвать.

Документ о detectChanges :

Вызовите его для инициализации компонента (он вызывает ngOnInit) и после вашего тестового кода измените значения свойств компонента, связанные с данными

Рабочий пример:

tooltip.component.ts :

 import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-tooltip',
  template: `<div [id]="'field-'   id">
    <input [id]="id" />
  </div>`,
})
export class TooltipComponent implements OnInit {
  id = 'name';
  container: any;
  inputField: any;
  ngOnInit() {
    setTimeout(() => {
      this.container = document.querySelector(`#field-${this.id}`);
      this.inputField = document.querySelector(`#${this.id}`);

      this.getState();
    }, 50);
  }

  getState() {
    this.inputField.addEventListener('focus', () => {
      const tooltip = this.container.querySelector('.tooltip');
      const tooltipHeight = tooltip.querySelector('p').clientHeight;

      tooltip.style.height = tooltipHeight   'px';
    });

    this.inputField.addEventListener('blur', () => {
      const tooltip = this.container.querySelector('.tooltip');

      tooltip.style.height = '0px';
    });
  }
}
 

tooltip.component.spec.ts :

 import { fakeAsync, TestBed, tick } from '@angular/core/testing';
import { TooltipComponent } from './tooltip.component';

fdescribe('65212730', () => {
  it('should pass', fakeAsync(() => {
    const fixture = TestBed.createComponent(TooltipComponent);
    const componentInst = fixture.componentInstance;
    componentInst.id = 'fieldId';
    const getStateStub = spyOn(componentInst, 'getState').and.stub();

    fixture.detectChanges();
    tick(50);

    fixture.whenStable().then(() => {
      expect(componentInst.container.nodeName).toBe('DIV');
      expect(componentInst.inputField.nodeName).toBe('INPUT');
      expect(getStateStub).toHaveBeenCalledTimes(1);
    });
  }));
});
 

результат модульного теста с покрытием:

введите описание изображения здесь

Комментарии:

1. хорошо, что это работает, но функция getState() не покрыта, this.container и this.inputField свойства задаются с помощью a querySelector , которые оба поступают из другого компонента в DOM. Теперь вы определили это в компоненте всплывающей подсказки. TooltipComponent Включает только сообщение всплывающей подсказки. Как я могу покрыть функцию getState() ?

2. Потому что я заглушил getState() метод и только ngOnInit метод тестирования.