0

I have the below directive which is added to an element using the copy-to-clipboard attribute, and copies the content of the attribute to the users clipboard on click:

@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);
  }
}

And my unit test is setup as the following:

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();
  });
});

I'm getting an error back to say that the expected condition never occurs. I'm trying to set up the test to confirm that the document.execCommand has in fact been called, and not sure how I can confirm that the copied value matches that of the input string?

1 Answer 1

2

I run your test and found that the value of CopyToClipboardDirective#payload was never set. You can make this work by placing fixture.detectChanges() at the end of the beforeEach function.

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');
});

To check, what text was copied to the clipboard, you can try to read it back using Clipboard#readText. Since readText returns a Promise, you need to deal with its asynchronous nature. The following example used the done function to do this.

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);
    });
});
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.