diff --git a/packages/happy-dom/src/config/ElementTag.ts b/packages/happy-dom/src/config/ElementTag.ts index 92ba25b92..3080d5aed 100644 --- a/packages/happy-dom/src/config/ElementTag.ts +++ b/packages/happy-dom/src/config/ElementTag.ts @@ -17,6 +17,7 @@ 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'; +import HTMLButtonElement from '../nodes/html-button-element/HTMLButtonElement'; export default { A: HTMLElement, @@ -55,7 +56,7 @@ export default { META: HTMLMetaElement, BLOCKQUOTE: HTMLElement, BR: HTMLElement, - BUTTON: HTMLElement, + BUTTON: HTMLButtonElement, CANVAS: HTMLElement, CAPTION: HTMLElement, CITE: HTMLElement, diff --git a/packages/happy-dom/src/nodes/html-button-element/HTMLButtonElement.ts b/packages/happy-dom/src/nodes/html-button-element/HTMLButtonElement.ts new file mode 100644 index 000000000..c91cc159d --- /dev/null +++ b/packages/happy-dom/src/nodes/html-button-element/HTMLButtonElement.ts @@ -0,0 +1,86 @@ +import HTMLElement from '../html-element/HTMLElement'; +import IHTMLButtonElement from './IHTMLButtonElement'; + +const BUTTON_TYPES = ['submit', 'reset', 'button', 'menu']; + +/** + +We can improve performance a bit if we make the types as a constant. + * HTML Button Element. + * + * Reference: + * https://developer.mozilla.org/en-US/docs/Web/API/HTMLButtonElement. + */ +export default class HTMLButtonElement extends HTMLElement implements IHTMLButtonElement { + /** + * Returns value. + * + * @returns Value. + */ + public get value(): string { + return this.getAttributeNS(null, 'value'); + } + + /** + * Sets value. + * + * @param value Value. + */ + public set value(value: string) { + this.setAttributeNS(null, 'value', value); + } + + /** + * Returns disabled. + * + * @returns Disabled. + */ + public get disabled(): boolean { + return this.getAttributeNS(null, 'disabled') !== null; + } + + /** + * Sets disabled. + * + * @param disabled Disabled. + */ + public set disabled(disabled: boolean) { + if (!disabled) { + this.removeAttributeNS(null, 'disabled'); + } else { + this.setAttributeNS(null, 'disabled', ''); + } + } + + /** + * Returns type + * + * @returns Type + */ + public get type(): string { + return this._sanitizeType(this.getAttributeNS(null, 'type')); + } + + /** + * Sets type + * + * @param v Type + */ + public set type(v: string) { + this.setAttributeNS(null, 'type', this._sanitizeType(v)); + } + + /** + * + * @param type + */ + protected _sanitizeType(type: string): string { + type = (type && type.toLowerCase()) || 'submit'; + + if (!BUTTON_TYPES.includes(type)) { + type = 'submit'; + } + + return type; + } +} diff --git a/packages/happy-dom/src/nodes/html-button-element/IHTMLButtonElement.ts b/packages/happy-dom/src/nodes/html-button-element/IHTMLButtonElement.ts new file mode 100644 index 000000000..e92f8e159 --- /dev/null +++ b/packages/happy-dom/src/nodes/html-button-element/IHTMLButtonElement.ts @@ -0,0 +1,13 @@ +import IHTMLElement from '../html-element/IHTMLElement'; + +/** + * HTML Button Element. + * + * Reference: + * https://developer.mozilla.org/en-US/docs/Web/API/HTMLButtonElement. + */ +export default interface IHTMLButtonElement extends IHTMLElement { + type: string; + disabled: boolean; + value: string; +} diff --git a/packages/happy-dom/test/nodes/html-button-element/HTMLButtonElement.test.ts b/packages/happy-dom/test/nodes/html-button-element/HTMLButtonElement.test.ts new file mode 100644 index 000000000..b14c89558 --- /dev/null +++ b/packages/happy-dom/test/nodes/html-button-element/HTMLButtonElement.test.ts @@ -0,0 +1,91 @@ +import Window from '../../../src/window/Window'; +import Document from '../../../src/nodes/document/Document'; +import HTMLButtonElement from '../../../src/nodes/html-button-element/HTMLButtonElement'; + +describe('HTMLButtonElement', () => { + let window: Window; + let document: Document; + let element: HTMLButtonElement; + + beforeEach(() => { + window = new Window(); + document = window.document; + element = document.createElement('button'); + }); + + describe('get value()', () => { + it(`Returns the attribute "value".`, () => { + element.setAttribute('value', 'VALUE'); + expect(element.value).toBe('VALUE'); + }); + }); + + describe('set value()', () => { + it(`Sets the attribute "value".`, () => { + element.value = 'VALUE'; + expect(element.getAttribute('value')).toBe('VALUE'); + }); + }); + + describe(`get disabled()`, () => { + it('Returns attribute value.', () => { + expect(element.disabled).toBe(false); + element.setAttribute('disabled', ''); + expect(element.disabled).toBe(true); + }); + }); + + describe(`set disabled()`, () => { + it('Sets attribute value.', () => { + element.disabled = true; + expect(element.getAttribute('disabled')).toBe(''); + }); + }); + + describe('get type()', () => { + it(`Defaults to "submit".`, () => { + expect(element.type).toBe('submit'); + }); + + it(`Returns the attribute "type".`, () => { + element.setAttribute('type', 'menu'); + expect(element.type).toBe('menu'); + }); + + it(`Sanitizes the value before returning.`, () => { + element.setAttribute('type', 'reset'); + expect(element.type).toBe('reset'); + + element.setAttribute('type', 'button'); + expect(element.type).toBe('button'); + + element.setAttribute('type', 'submit'); + expect(element.type).toBe('submit'); + + element.setAttribute('type', 'MeNu'); + expect(element.type).toBe('menu'); + + element.setAttribute('type', 'foobar'); + expect(element.type).toBe('submit'); + }); + }); + + describe('set type()', () => { + it(`Sets the attribute "type" after sanitizing.`, () => { + element.type = 'SuBmIt'; + expect(element.getAttribute('type')).toBe('submit'); + + element.type = 'reset'; + expect(element.getAttribute('type')).toBe('reset'); + + element.type = 'button'; + expect(element.getAttribute('type')).toBe('button'); + + element.type = 'menu'; + expect(element.getAttribute('type')).toBe('menu'); + + element.type = null; + expect(element.getAttribute('type')).toBe('submit'); + }); + }); +});