指令@Input在测试中始终未定义

时间:2019-10-25 08:48:34

标签: angular typescript unit-testing karma-jasmine directive

我有一条指令可以复制到剪贴板。当我正常使用它时,它可以工作,但是当我想对其进行一些测试时,@ Input属性始终未定义

这是指令 CopyClipboard.directive.ts

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


/**
 * Directive use to copy the content of the event to the clipBoard
 * Source :
 * https://stackoverflow.com/a/52949299/5703228
 *
 * @export
 * @class CopyClipboardDirective
 */
@Directive({
  selector: '[appCopyClipboard]'
})
export class CopyClipboardDirective {

  constructor() {}

  @Input('appCopyClipboard')
  public payload: string;

  @Output() public copied: EventEmitter<string> = new EventEmitter<string>();

  @HostListener('click', ['$event'])
  public onClick(event: MouseEvent): void {

    event.preventDefault();
    if (this.payload == null) {
      return;
    }

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

      this.copied.emit(this.payload);
    };

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

这是对应的测试 Copyclipboard.directive.spec.ts

/* tslint:disable:no-unused-variable */

import { TestBed, async, ComponentFixture } from '@angular/core/testing';
import { CopyClipboardDirective } from './CopyClipboard.directive';
import { Component, DebugElement } from '@angular/core';
import { By } from '@angular/platform-browser';
import { TestUtils } from 'src/app/tests/test-utils';

@Component({
  template: '<button [appCopyClipboard]="getTextToCopy()" (copied)="onCopied($event)">Test button</button>'
})
class TestCopyClipboardDirectiveComponent {

  public textToCopy = 'Test Text';
  public textCopied = '';

  public onCopied(textCopied: string): void {
    this.textCopied = textCopied;
  }

  public getTextToCopy(): string {
    return this.textToCopy;
  }
}

describe('Directive: CopyClipboardDirective', () => {

  let component: TestCopyClipboardDirectiveComponent;
  let fixture: ComponentFixture<TestCopyClipboardDirectiveComponent>;
  let buttonDe: DebugElement;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        CopyClipboardDirective,
        TestCopyClipboardDirectiveComponent
      ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(TestCopyClipboardDirectiveComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();

    buttonDe = fixture.debugElement.query(By.css('button'));
  });

  it('should be created', () => {
    expect(component).toBeTruthy();
    expect(buttonDe).toBeTruthy();
  });

  it('should call callback after copy on click', () => {

    spyOn(component, 'onCopied').and.callThrough();
    const buttonNe: HTMLElement = buttonDe.nativeElement;
    buttonNe.click();
    fixture.detectChanges();

    fixture.whenStable().then(() => {
      expect(component.onCopied).toHaveBeenCalledTimes(1);
      expect(component.onCopied).toHaveBeenCalledWith(component.textToCopy);
      expect(component.textCopied).toBe(component.textToCopy);
    });
  });

  // We cannot access content of ClipBoard as it is a security violation
  // So we cannot test if the data is actually in the clipBoard
  // But we can try to listen for event copy
  it('should emit copy event on document', (done: DoneFn) => {

    spyOn(component, 'onCopied').and.callThrough();
    let success = false;
    const listener = (e: ClipboardEvent) => {

      success = true;
      done();
      document.removeEventListener('copy', listener, false);
    };

    document.addEventListener('copy', listener, false);
    const buttonNe: HTMLElement = buttonDe.nativeElement;
    buttonNe.click();
    fixture.detectChanges();
    /*fixture.whenStable().then(() => {
      expect(success).toBe(true);
    });*/
  });
});

最后一次测试均失败。 当我调试执行程序时,我看到指令中的payload未定义。 为什么指令@Input在测试中未定义?

我在组件中的其他地方使用它,并且效果很好:

<button mat-raised-button color="secondary"
  [appCopyClipboard]="getStringFormattedQuotation()"
  (copied)="notifyCopied($event)">
    <mat-icon>file_copy</mat-icon> Copier
</button>

**编辑** 我按照建议尝试将测试组件模板更改为此:

...[appCopyClipboard]=" \'someText string here\' "...

有了这个,我将@Input设置为此值,但是在指令代码中,仍然永远不会调用文档上设置的侦听器。 我试图删除该行

document.removeEventListener('copy', listener, false);

进行测试,但也没有用。 我注意到的另一件事是在浏览器的控制台中,我得到了两行:

zone.js:3401 Access to XMLHttpRequest at 'ng:///DynamicTestModule/TestCopyClipboardDirectiveComponent.ngfactory.js' from origin 'http://localhost:9876' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.

我的其他任何测试都没有收到此错误。

0 个答案:

没有答案