Reputation: 883
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?
Upvotes: 0
Views: 2141
Reputation: 26150
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);
});
});
Upvotes: 2