I'm trying to implement a dialog component where user can click escape button to close the popup (I'm using DaisyUI). It works fine when I try it manually, but for some reason I'm not able to create the unit test for it. It fails.
Unit Test:
it('should allow using escape key when allowClosing is set to true', () => {
fixture.componentInstance.allowClosing = true
let dialog: HTMLDialogElement | undefined =
fixture.componentInstance["dialog"]?.nativeElement
expect(dialog?.open).toBeFalse()
dialog?.showModal()
expect(dialog?.open).toBeTrue()
let event = new KeyboardEvent('keydown', {key: 'Escape'});
spyOn(component, 'cancel');
dialog?.dispatchEvent(event);
fixture.detectChanges();
expect(component["cancel"]).toHaveBeenCalled();
expect(dialog?.open).toBeFalse()
});
HTML:
<dialog #dialog id="{{popupId}}" class="tw-modal"
(close)="close()"
(cancel)="cancel($event)">
<form method="dialog" class="tw-modal-box tw-rounded-md tw-p-3">
<div class="tw-flex tw-flex-col tw-justify-center">
<button #closeButton class="tw-self-end" *ngIf="allowClosing">✕</button>
<ng-content class="tw-self-auto"></ng-content>
</div>
</form>
<form method="dialog" class="tw-modal-backdrop">
<button></button>
</form>
</dialog>
ts:
@Component({
selector: 'popup',
templateUrl: './popup.component.html'
})
export class PopupComponent implements AfterViewInit {
@Input() allowClosing: boolean = false;
@Input() popupId: string | undefined;
@Output() onClose: EventEmitter<void> = new EventEmitter()
@ViewChild("dialog") protected dialog: ElementRef<HTMLDialogElement> | undefined
@ViewChild("closeButton") protected closeButton: ElementRef<HTMLButtonElement> | undefined
ngAfterViewInit(): void {
this.dialog?.nativeElement.addEventListener("open", ()=>{
console.log("event listener on ipen")
})
}
public show(){
this.dialog?.nativeElement.showModal()
}
public close(){
this.onClose.emit()
this.dialog?.nativeElement.close()
}
public cancel(event: Event) {
console.log("cancel")
event.preventDefault()
if (!this.allowClosing){
return
}
else{
this.close()
}
}
get isOpen(){
return this.dialog?.nativeElement.open
}
}
What could be wrong? is it not working for security reasons?
The issue could be that when we do:
We are spying on the
cancelmethod to see how it was called, if it was called and how many times it was called.I am thinking the
cancelmethod is what's responsible for setting the open property to false.To potentially fix it, you can do:
Now we have a spy on
cancelmethod and every time it is being called, we are calling the actual implementation (.and.callThrough()) and hopefully this will allow to close the dialog.