Как выполнить модульное тестирование угловой директивы с помощью входа? - PullRequest
0 голосов
/ 04 ноября 2019

У меня есть директива ниже, которая добавляется к элементу с помощью атрибута copy-to-clipboard и копирует содержимое атрибута в буфер обмена пользователя при нажатии:

@Directive({
  selector: '[copy-to-clipboard]'
})
export class CopyToClipboardDirective {
  @Input('copy-to-clipboard') public payload: string;

  @HostListener('click', ['$event'])
  onClick(event: MouseEvent): void {
    event.preventDefault();
    if (!this.payload) {
      return;
    }

    const listener = (e: ClipboardEvent) => {
      const clipboard = e.clipboardData;
      clipboard.setData('text', this.payload.toString());
      e.preventDefault();
    };

    document.addEventListener('copy', listener, false);
    document.execCommand('copy');
    document.removeEventListener('copy', listener, false);
  }
}

И мой модульный тест настроенкак следующее:

import {ComponentFixture, TestBed} from '@angular/core/testing';
import {CopyToClipboardDirective} from './copy-to-clipboard.directive';
import {Component} from '@angular/core';

@Component({
  template: `<input [copy-to-clipboard]="'this is the passed string'" role="button" type="button">`
})
class MockCopyToClipboardComponent {}

fdescribe('Directive: CopyToClipboard', () => {
  let fixture: ComponentFixture<MockCopyToClipboardComponent>;
  let component: MockCopyToClipboardComponent;
  let element;

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [CopyToClipboardDirective, MockCopyToClipboardComponent]
    });
    fixture = TestBed.createComponent(MockCopyToClipboardComponent);
    element = fixture.debugElement.nativeElement;
    component = fixture.componentInstance;
  });

  it('should run the copy command', () => {
    spyOn(document, 'execCommand');
    element.querySelector('input').click();
    fixture.detectChanges();
    expect(document.execCommand).toHaveBeenCalled();
  });
});

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

1 Ответ

1 голос
/ 07 ноября 2019

Я запустил ваш тест и обнаружил, что значение CopyToClipboardDirective#payload никогда не устанавливалось. Вы можете сделать это, поместив fixture.detectChanges() в конце функции beforeEach.

beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [CopyToClipboardDirective, MockCopyToClipboardComponent]
    });
    fixture = TestBed.createComponent(MockCopyToClipboardComponent);
    element = fixture.debugElement.nativeElement;
    component = fixture.componentInstance;
    fixture.detectChanges(); // >>>>>> ADD this line 
});

it('should run the copy command', () => {
    spyOn(document, 'execCommand');
    element.querySelector('input').click();
    // fixture.detectChanges(); // >>>>>> REMOVE this line
    expect(document.execCommand).toHaveBeenCalledWith('copy');
});

Чтобы проверить, какой текст был скопирован в буфер обмена, вы можете попробовать прочитать его обратно, используя Clipboard#readText. Поскольку readText возвращает Promise, вам необходимо разобраться с его асинхронной природой. В следующем примере для этого используется функция done.

it('should run the copy command', (done) => {
    spyOn(document, 'execCommand');
    element.querySelector('input').click();
    expect(document.execCommand).toHaveBeenCalledWith('copy');

    element.querySelector('input').focus();
    navigator.clipboard.readText()
    .then(t => {
      expect(t).toBe('this is the passed string');
      done();
    })
    .catch(err => {
      fail(err);
    });
});
...