Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/capricorn86/happy-dom int…
Browse files Browse the repository at this point in the history
…o task/450-typeerror-targetownerdocumentcreaterange-is-not-a-function
  • Loading branch information
capricorn86 committed Jun 30, 2022
2 parents 16a7c2f + cbe5b7a commit eaaf255
Show file tree
Hide file tree
Showing 9 changed files with 205 additions and 3 deletions.
3 changes: 2 additions & 1 deletion packages/happy-dom/src/config/ElementTag.ts
Expand Up @@ -16,6 +16,7 @@ import HTMLBaseElement from '../nodes/html-base-element/HTMLBaseElement';
import HTMLSelectElement from '../nodes/html-select-element/HTMLSelectElement';
import HTMLOptionElement from '../nodes/html-option-element/HTMLOptionElement';
import HTMLOptGroupElement from '../nodes/html-opt-group-element/HTMLOptGroupElement';
import HTMLDialogElement from '../nodes/html-dialog-element/HTMLDialogElement';

export default {
A: HTMLElement,
Expand Down Expand Up @@ -67,7 +68,7 @@ export default {
DEL: HTMLElement,
DETAILS: HTMLElement,
DFN: HTMLElement,
DIALOG: HTMLElement,
DIALOG: HTMLDialogElement,
DIV: HTMLElement,
DL: HTMLElement,
DT: HTMLElement,
Expand Down
6 changes: 5 additions & 1 deletion packages/happy-dom/src/index.ts
Expand Up @@ -105,6 +105,8 @@ import DOMRect from './nodes/element/DOMRect';
import { URLSearchParams } from 'url';
import Selection from './selection/Selection';
import Range from './range/Range';
import HTMLDialogElement from './nodes/html-dialog-element/HTMLDialogElement';
import IHTMLDialogElement from './nodes/html-dialog-element/IHTMLDialogElement';

export {
GlobalWindow,
Expand Down Expand Up @@ -213,5 +215,7 @@ export {
DOMRect,
URLSearchParams,
Selection,
Range
Range,
HTMLDialogElement,
IHTMLDialogElement
};
2 changes: 1 addition & 1 deletion packages/happy-dom/src/location/URL.ts
Expand Up @@ -85,7 +85,7 @@ export default class URL {
this.protocol = match[1] || '';
this.hostname = hostnamePart.length > 1 ? hostnamePart[1] : hostnamePart[0];
this.port = match[3] || '';
this.pathname = match[4] || '';
this.pathname = match[4] || '/';
this.search = match[5] || '';
this.hash = match[6] || '';
this.username = credentialsPart ? credentialsPart[0] : '';
Expand Down
@@ -0,0 +1,52 @@
import Event from '../../event/Event';
import HTMLElement from '../html-element/HTMLElement';
import IHTMLDialogElement from './IHTMLDialogElement';

/**
* HTML Dialog Element.
*
* Reference:
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement.
*/
export default class HTMLDialogElement extends HTMLElement implements IHTMLDialogElement {
/**
* Returns returnValue.
*
* @returns ReturnValue.
*/
public returnValue: string;

/**
* Returns open.
*
* @returns Open.
*/
public get open(): boolean {
return this.hasAttributeNS(null, 'open');
}

/**
* Closes the dialog.
*
* @param returnValue ReturnValue.
*/
public close(returnValue?: string): void {
this.removeAttributeNS(null, 'open');
this.returnValue = returnValue;
this.dispatchEvent(new Event('close', { bubbles: false, cancelable: false }));
}

/**
* Shows the modal.
*/
public showModal(): void {
this.setAttributeNS(null, 'open', '');
}

/**
* Shows the dialog.
*/
public show(): void {
this.setAttributeNS(null, 'open', '');
}
}
@@ -0,0 +1,15 @@
import IHTMLElement from '../html-element/IHTMLElement';

/**
* HTML Dialog Element.
*
* Reference:
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement.
*/
export default interface IHTMLDialogElement extends IHTMLElement {
open: boolean;
returnValue: string;
close(returnValue?: string): void;
showModal(): void;
show(): void;
}
2 changes: 2 additions & 0 deletions packages/happy-dom/src/window/IWindow.ts
Expand Up @@ -24,6 +24,7 @@ import HTMLBaseElement from '../nodes/html-base-element/HTMLBaseElement';
import SVGSVGElement from '../nodes/svg-element/SVGSVGElement';
import SVGElement from '../nodes/svg-element/SVGElement';
import HTMLScriptElement from '../nodes/html-script-element/HTMLScriptElement';
import HTMLDialogElement from '../nodes/html-dialog-element/HTMLDialogElement';
import HTMLImageElement from '../nodes/html-image-element/HTMLImageElement';
import Image from '../nodes/html-image-element/Image';
import DocumentFragment from '../nodes/document-fragment/DocumentFragment';
Expand Down Expand Up @@ -113,6 +114,7 @@ export default interface IWindow extends IEventTarget, NodeJS.Global {
readonly HTMLLabelElement: typeof HTMLLabelElement;
readonly HTMLMetaElement: typeof HTMLMetaElement;
readonly HTMLBaseElement: typeof HTMLBaseElement;
readonly HTMLDialogElement: typeof HTMLDialogElement;
readonly SVGSVGElement: typeof SVGSVGElement;
readonly SVGElement: typeof SVGElement;
readonly Image: typeof Image;
Expand Down
2 changes: 2 additions & 0 deletions packages/happy-dom/src/window/Window.ts
Expand Up @@ -21,6 +21,7 @@ import HTMLSlotElement from '../nodes/html-slot-element/HTMLSlotElement';
import HTMLLabelElement from '../nodes/html-label-element/HTMLLabelElement';
import HTMLMetaElement from '../nodes/html-meta-element/HTMLMetaElement';
import HTMLBaseElement from '../nodes/html-base-element/HTMLBaseElement';
import HTMLDialogElement from '../nodes/html-dialog-element/HTMLDialogElement';
import SVGSVGElement from '../nodes/svg-element/SVGSVGElement';
import SVGElement from '../nodes/svg-element/SVGElement';
import HTMLScriptElement from '../nodes/html-script-element/HTMLScriptElement';
Expand Down Expand Up @@ -135,6 +136,7 @@ export default class Window extends EventTarget implements IWindow {
public readonly HTMLSlotElement = HTMLSlotElement;
public readonly HTMLMetaElement = HTMLMetaElement;
public readonly HTMLBaseElement = HTMLBaseElement;
public readonly HTMLDialogElement = HTMLDialogElement;
public readonly SVGSVGElement = SVGSVGElement;
public readonly SVGElement = SVGElement;
public readonly Text = Text;
Expand Down
16 changes: 16 additions & 0 deletions packages/happy-dom/test/location/URL.test.ts
Expand Up @@ -49,5 +49,21 @@ describe('URL', () => {
expect(url.host).toBe('google.com:8080');
expect(url.origin).toBe('https://google.com:8080');
});
it('Parses "https://google.com".', () => {
const formatHref = 'https://google.com/';
const href = 'https://google.com';
const url = new URL(href);
expect(url.href).toBe(formatHref);
expect(url.protocol).toBe('https:');
expect(url.hostname).toBe('google.com');
expect(url.port).toBe('');
expect(url.pathname).toBe('/');
expect(url.search).toBe('');
expect(url.hash).toBe('');
expect(url.username).toBe('');
expect(url.password).toBe('');
expect(url.host).toBe('google.com');
expect(url.origin).toBe('https://google.com');
});
});
});
@@ -0,0 +1,110 @@
import { Event } from 'src';
import Document from '../../../src/nodes/document/Document';
import HTMLDialogElement from '../../../src/nodes/html-dialog-element/HTMLDialogElement';
import Window from '../../../src/window/Window';

describe('HTMLDialogElement', () => {
let window: Window;
let document: Document;
let element: HTMLDialogElement;

beforeEach(() => {
window = new Window();
document = window.document;
element = <HTMLDialogElement>document.createElement('dialog');
});

describe('open', () => {
it('Should be closed by default', () => {
expect(element.open).toBe(false);
});

it('Should be open when show has been called', () => {
element.show();
expect(element.open).toBe(true);
});

it('Should be open when showModal has been called', () => {
element.showModal();
expect(element.open).toBe(true);
});
});

describe('returnValue', () => {
it('Should be undefined by default', () => {
expect(element.returnValue).toBe(undefined);
});

it('Should be set when close has been called with a return value', () => {
element.close('foo');
expect(element.returnValue).toBe('foo');
});

it('Should be possible to set manually', () => {
element.returnValue = 'foo';
expect(element.returnValue).toBe('foo');
});
});

describe('close', () => {
it('Should be possible to close an open dialog', () => {
element.show();
element.close();
expect(element.open).toBe(false);
expect(element.getAttributeNS(null, 'open')).toBe(null);
});

it('Should be possible to close an open modal dialog', () => {
element.showModal();
element.close();
expect(element.open).toBe(false);
expect(element.getAttributeNS(null, 'open')).toBe(null);
});

it('Should be possible to close the dialog with a return value', () => {
element.show();
element.close('foo');
expect(element.returnValue).toBe('foo');
});

it('Should be possible to close the modal dialog with a return value', () => {
element.showModal();
element.close('foo');
expect(element.returnValue).toBe('foo');
});

it('Should dispatch a close event', () => {
let dispatched: Event = null;
element.addEventListener('close', (event: Event) => (dispatched = event));
element.show();
element.close();
expect(dispatched.cancelable).toBe(false);
expect(dispatched.bubbles).toBe(false);
});

it('Should dispatch a close event when closing a modal', () => {
let dispatched: Event = null;
element.addEventListener('close', (event: Event) => (dispatched = event));
element.showModal();
element.close();
expect(dispatched.cancelable).toBe(false);
expect(dispatched.bubbles).toBe(false);
});
});

describe('showModal', () => {
it('Should be possible to show a modal dialog', () => {
element.showModal();
expect(element.open).toBe(true);
expect(element.getAttributeNS(null, 'open')).toBe('');
});
});

describe('show', () => {
it('Should be possible to show a dialog', () => {
element.show();
expect(element.open).toBe(true);
expect(element.getAttributeNS(null, 'open')).toBe('');
});
});
});

0 comments on commit eaaf255

Please sign in to comment.