diff --git a/packages/happy-dom/src/nodes/html-dialog-element/HTMLDialogElement.ts b/packages/happy-dom/src/nodes/html-dialog-element/HTMLDialogElement.ts index abab3c869..bcf8c4d5a 100644 --- a/packages/happy-dom/src/nodes/html-dialog-element/HTMLDialogElement.ts +++ b/packages/happy-dom/src/nodes/html-dialog-element/HTMLDialogElement.ts @@ -49,7 +49,7 @@ export default class HTMLDialogElement extends HTMLElement { * @param value Return value. */ public set returnValue(value: string) { - this[PropertySymbol.returnValue] = value; + this[PropertySymbol.returnValue] = String(value); } /** @@ -79,10 +79,10 @@ export default class HTMLDialogElement extends HTMLElement { * * @param [returnValue] ReturnValue. */ - public close(returnValue = ''): void { + public close(returnValue?: string): void { const wasOpen = this.open; this.removeAttribute('open'); - this.returnValue = returnValue; + this.returnValue = returnValue !== undefined ? String(returnValue) : ''; if (wasOpen) { this.dispatchEvent(new Event('close')); } diff --git a/packages/happy-dom/src/nodes/html-form-element/HTMLFormElement.ts b/packages/happy-dom/src/nodes/html-form-element/HTMLFormElement.ts index de2cd5a27..5ea29f4e1 100644 --- a/packages/happy-dom/src/nodes/html-form-element/HTMLFormElement.ts +++ b/packages/happy-dom/src/nodes/html-form-element/HTMLFormElement.ts @@ -17,6 +17,7 @@ import ClassMethodBinder from '../../utilities/ClassMethodBinder.js'; import Node from '../node/Node.js'; import Element from '../element/Element.js'; import EventTarget from '../../event/EventTarget.js'; +import HTMLDialogElement from '../html-dialog-element/HTMLDialogElement.js'; import ElementEventAttributeUtility from '../element/ElementEventAttributeUtility.js'; /** @@ -573,6 +574,26 @@ export default class HTMLFormElement extends HTMLElement { * @param [submitter] Submitter. */ #submit(submitter?: HTMLInputElement | HTMLButtonElement): void { + const method = submitter?.formMethod || this.method; + + if (method === 'dialog') { + let dialog: HTMLDialogElement | null = null; + let parent: Element = this; + + while (parent) { + if (parent[PropertySymbol.tagName] === 'DIALOG') { + dialog = parent; + break; + } + parent = parent.parentElement; + } + + if (dialog) { + dialog.close(submitter?.value); + return; + } + } + const action = submitter?.hasAttribute('formaction') ? submitter?.formAction || this.action : this.action; @@ -589,7 +610,6 @@ export default class HTMLFormElement extends HTMLElement { return; } - const method = submitter?.formMethod || this.method; const formData = new this[PropertySymbol.window].FormData(this); let targetFrame: IBrowserFrame; diff --git a/packages/happy-dom/test/nodes/html-dialog-element/HTMLDialogElement.test.ts b/packages/happy-dom/test/nodes/html-dialog-element/HTMLDialogElement.test.ts index ca2304af7..f6a847dfe 100644 --- a/packages/happy-dom/test/nodes/html-dialog-element/HTMLDialogElement.test.ts +++ b/packages/happy-dom/test/nodes/html-dialog-element/HTMLDialogElement.test.ts @@ -3,6 +3,7 @@ import HTMLDialogElement from '../../../src/nodes/html-dialog-element/HTMLDialog import Window from '../../../src/window/Window.js'; import Document from '../../../src/nodes/document/Document.js'; import { beforeEach, describe, it, expect } from 'vitest'; +import KeyboardEvent from '../../../src/event/events/KeyboardEvent.js'; describe('HTMLDialogElement', () => { let window: Window; @@ -83,6 +84,8 @@ describe('HTMLDialogElement', () => { it('Should be possible to set manually', () => { element.returnValue = 'foo'; expect(element.returnValue).toBe('foo'); + element.returnValue = (undefined); + expect(element.returnValue).toBe('undefined'); }); }); @@ -105,6 +108,12 @@ describe('HTMLDialogElement', () => { element.show(); element.close('foo'); expect(element.returnValue).toBe('foo'); + element.show(); + element.close(undefined); + expect(element.returnValue).toBe(''); + element.show(); + element.close((null)); + expect(element.returnValue).toBe('null'); }); it('Should be possible to close the modal dialog with a return value', () => { @@ -122,7 +131,7 @@ describe('HTMLDialogElement', () => { expect(((dispatched)).bubbles).toBe(false); }); - it('Should only dispatch a close event when dialog wasnt already closed', () => { + it("Should only dispatch a close event when dialog wasn't already closed", () => { let dispatched: Event | null = null; element.addEventListener('close', (event: Event) => (dispatched = event)); element.close(); diff --git a/packages/happy-dom/test/nodes/html-form-element/HTMLFormElement.test.ts b/packages/happy-dom/test/nodes/html-form-element/HTMLFormElement.test.ts index 8b6f9986f..b684837af 100644 --- a/packages/happy-dom/test/nodes/html-form-element/HTMLFormElement.test.ts +++ b/packages/happy-dom/test/nodes/html-form-element/HTMLFormElement.test.ts @@ -930,6 +930,46 @@ describe('HTMLFormElement', () => { expect(page.mainFrame.url).toBe('about:blank#blocked'); }); + + it('Supports form method "dialog"', () => { + const container = document.body; + container.innerHTML = ` +
+ + +
+
`; + const dialog = container.querySelector('dialog')!; + const form = dialog.querySelector('form')!; + const button = dialog.querySelector('button')!; + const input = dialog.querySelector('input')!; + + input.value = 'test'; + + expect(dialog.returnValue).toBe(''); + expect(dialog.open).toBe(false); + + dialog.showModal(); + + expect(dialog.open).toBe(true); + + let submitEvent: SubmitEvent | null = null; + dialog.addEventListener('submit', (event) => (submitEvent = event)); + button.click(); + expect(dialog.open).toBe(false); + expect(((submitEvent)).submitter).toBe(button); + expect(((submitEvent)).target).toBe(form); + expect(dialog.returnValue).toBe('buttonValue'); + + dialog.showModal(); + expect(dialog.open).toBe(true); + + form.submit(); + expect(dialog.open).toBe(false); + expect(dialog.returnValue).toBe(''); + + expect(input.value).toBe('test'); + }); }); describe('requestSubmit()', () => {