Директива модульного тестирования с аргументами в Angular 2+ - PullRequest
1 голос
/ 22 апреля 2020

У меня есть директива, которая меняет цвет фона элемента при наведении мыши, как показано ниже.

import {Directive, ElementRef, HostListener, Input} from '@angular/core';

@Directive({
  selector: '[appHighlightme]'
})
export class HighlightmeDirective {

  @Input('appHighlightme') color : string
  constructor(private el:ElementRef) { }

  @HostListener('mouseenter') onMouseEnter(){
    this.highlight(this.color || 'yellow');
  }

  @HostListener('mouseleave') onMouseLeave(){
    this.highlight('inherit');
  }

  highlight(color){
    this.el.nativeElement.style.backgroundColor = color;
  }
}

Я пытался написать пример модульного теста для этой директивы, как показано ниже

import { HighlightmeDirective } from './highlightme.directive';
import {ChangeDetectionStrategy, Component, DebugElement, ViewChild} from '@angular/core';
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {By} from '@angular/platform-browser';

@Component({
  selector: 'my-test-component',
  template: '<a [appHighlightme]="color" >test</a>'
})
export class TestComponent {
  color:string = 'blue';
}

describe('HighlightmeDirective', () => {

  let component: TestComponent;
  let fixture: ComponentFixture<TestComponent>;
  let inputEl: DebugElement;

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [
        TestComponent,
        HighlightmeDirective
      ]
    })

    fixture = TestBed.createComponent(TestComponent);
    component = fixture.componentInstance;
    inputEl = fixture.debugElement.query(By.directive(HighlightmeDirective));

  });

  it('detect hover changes', () => {
    inputEl.triggerEventHandler('mouseenter', {});
    fixture.detectChanges();
    expect(inputEl.nativeElement.style.backgroundColor).toBe(component.color);
    inputEl.triggerEventHandler('mouseleave', {});
    fixture.detectChanges();
    expect(inputEl.nativeElement.style.backgroundColor).toBe('inherit');
  });

  it('should create an instance', () => {
    const directive = new HighlightmeDirective(inputEl);
    expect(directive).toBeTruthy();
  });
});

Директива работает нормально в других компонентах. он принимает переменную аргумента цвета, определенную в файле ts, и использует его в качестве цвета bg при наведении курсора на элемент. Но когда я пытаюсь выполнить тот же модульный тест, переданный из TestComponent цветовой аргумент не обнаруживается директивой, а тестовый пример завершается неудачно со следующим сообщением об ошибке.

Ошибка: ожидается «желтый» быть «синим». - Так как желтый цвет установлен как цвет при наведении по умолчанию

Ответы [ 2 ]

1 голос
/ 29 апреля 2020

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

Допустим, у нас есть тег привязки с классом, поэтому нам нужно создать событие для этого тега.

@Component({
  selector: 'my-test-component',
  template: '<a class="mytag" [appHighlightme]="color" >test</a>'
})
export class TestComponent {
  color:string = 'blue';
}

describe('HighlightmeDirective', () => {

  let component: TestComponent;
  let fixture: ComponentFixture<TestComponent>;
  let inputEl: DebugElement;

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [
        TestComponent,
        HighlightmeDirective
      ]
    })

    fixture = TestBed.createComponent(TestComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();   // trigger change detection so that UI renders and you can access element in next step.
    inputEl = fixture.debugElement.query(By.css('.mytag'));

  });

  it('detect hover changes', () => {
    inputEl.triggerEventHandler('mouseenter', {});
    fixture.detectChanges();
    expect(inputEl.nativeElement.style.backgroundColor).toBe(component.color);
    inputEl.triggerEventHandler('mouseleave', {});
    fixture.detectChanges();
    expect(inputEl.nativeElement.style.backgroundColor).toBe('inherit');
  });

  it('should create an instance', () => {
    const directive = new HighlightmeDirective(inputEl);
    expect(directive).toBeTruthy();
  });
});

Я надеюсь, что это поможет вам.

1 голос
/ 29 апреля 2020

Прежде чем запускать какие-либо события, вам необходимо убедиться, что @Input('appHighlightme') color свойства инициализированы. Эта инициализация происходит во время первого цикла обнаружения изменений.

Таким образом, вы должны инициировать обнаружение изменений и только затем запускать событие mouseenter. Другое наблюдение состоит в том, что, поскольку вы манипулируете стилем непосредственно через this.el.nativeElement.style.backgroundColor, вам даже не нужно использовать другие fixture.detectChanges(); вызовы.

it('detect hover changes', () => {
  fixture.detectChanges(); // !!! initialize 'color' property

  inputEl.triggerEventHandler('mouseenter', {});  
  // fixture.detectChanges();  <-- useless here
  expect(inputEl.nativeElement.style.backgroundColor).toBe(component.color);

  inputEl.triggerEventHandler('mouseleave', {});
  // fixture.detectChanges();  <-- useless here
  expect(inputEl.nativeElement.style.backgroundColor).toBe('inherit');
});
...