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 8d082f582..4d0f78cb5 100644
--- a/packages/happy-dom/src/nodes/html-form-element/HTMLFormElement.ts
+++ b/packages/happy-dom/src/nodes/html-form-element/HTMLFormElement.ts
@@ -436,6 +436,7 @@ export default class HTMLFormElement extends HTMLElement implements IHTMLFormEle
let targetFrame: IBrowserFrame;
switch (submitter?.formTarget || this.target) {
+ default:
case '_self':
targetFrame = this.#browserFrame;
break;
@@ -450,9 +451,6 @@ export default class HTMLFormElement extends HTMLElement implements IHTMLFormEle
targetFrame = newPage.mainFrame;
targetFrame[PropertySymbol.openerFrame] = this.#browserFrame;
break;
- default:
- targetFrame = this.#browserFrame;
- break;
}
if (method === 'get') {
diff --git a/packages/happy-dom/test/CustomElement.ts b/packages/happy-dom/test/CustomElement.ts
index a337a1e9d..399bd1990 100644
--- a/packages/happy-dom/test/CustomElement.ts
+++ b/packages/happy-dom/test/CustomElement.ts
@@ -62,8 +62,8 @@ export default class CustomElement extends HTMLElement {
key1 is "${this.getAttribute('key1')}" and key2 is "${this.getAttribute(
- 'key2'
- )}".
+ 'key2'
+ )}".
${this.childNodes
.map(
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 e7533259a..10c9a2eb6 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
@@ -382,6 +382,12 @@ describe('HTMLFormElement', () => {
describe('submit()', () => {
it('Fallbacks to set location URL when in the main frame of a detached Window.', () => {
+ vi.spyOn(Fetch.prototype, 'send').mockImplementation(function (): Promise {
+ throw new Error('Request should not be sent.');
+ });
+
+ expect(window.location.href).toBe('about:blank');
+
element.action = 'https://localhost:3000';
element.submit();
@@ -603,6 +609,106 @@ describe('HTMLFormElement', () => {
);
});
+ it(`Supports "_parent" as target.`, async () => {
+ let request: IRequest | null = null;
+
+ vi.spyOn(Fetch.prototype, 'send').mockImplementation(function (): Promise {
+ request = this.request;
+ return Promise.resolve({
+ url: request?.url,
+ text: () =>
+ new Promise((resolve) =>
+ setTimeout(
+ () =>
+ resolve(
+ request?.url === 'http://example.com/iframe'
+ ? `
+
+
+ `
+ : 'Test'
+ ),
+ 2
+ )
+ )
+ });
+ });
+
+ const browser = new Browser();
+ const page = browser.newPage();
+ const oldWindow = page.mainFrame.window;
+
+ page.mainFrame.url = 'http://example.com';
+
+ oldWindow.document.write(``);
+
+ await new Promise((resolve) =>
+ oldWindow.document.querySelector('iframe')?.addEventListener('load', resolve)
+ );
+
+ ((
+ (oldWindow.document.body.children[0]).contentWindow
+ )).document.body
+ .querySelector('button')
+ ?.click();
+
+ await page.mainFrame.waitForNavigation();
+
+ expect(page.mainFrame.url).toBe(
+ 'http://example.com/?text1=value1&text2=value2&checkbox1=value1&radio1=value2'
+ );
+ });
+
+ it(`Supports "_blank" as target.`, async () => {
+ let request: IRequest | null = null;
+
+ vi.spyOn(Fetch.prototype, 'send').mockImplementation(function (): Promise {
+ request = this.request;
+ return Promise.resolve({
+ url: request?.url,
+ text: () =>
+ new Promise((resolve) => setTimeout(() => resolve('Test'), 2))
+ });
+ });
+
+ const browser = new Browser();
+ const page = browser.newPage();
+ const oldWindow = page.mainFrame.window;
+
+ oldWindow.document.write(`
+
+ `);
+
+ oldWindow.document.body.querySelector('button')?.click();
+
+ const newPage = page.context.pages[1];
+
+ expect(newPage.mainFrame.url).toBe(
+ 'http://example.com/?text1=value1&text2=value2&checkbox1=value1&radio1=value2'
+ );
+
+ await newPage.waitForNavigation();
+
+ expect(newPage.mainFrame.document.body.innerHTML).toBe('Test');
+ });
+
it(`Uses "action" from button when "formaction" is set as an attribute on the button.`, async () => {
let request: IRequest | null = null;
@@ -639,6 +745,29 @@ describe('HTMLFormElement', () => {
expect(page.mainFrame.url).toBe('http://button.example.com/');
expect(page.mainFrame.window.location.href).toBe('http://button.example.com/');
});
+
+ it(`Sets hash to "#blocked" when action is invalid.`, async () => {
+ const browser = new Browser();
+ const page = browser.newPage();
+ const oldWindow = page.mainFrame.window;
+
+ oldWindow.document.write(`
+
+ `);
+
+ oldWindow.document.querySelector('button')?.click();
+
+ expect(page.mainFrame.url).toBe('about:blank#blocked');
+ });
});
describe('requestSubmit()', () => {
@@ -720,6 +849,80 @@ describe('HTMLFormElement', () => {
expect(((submitEvent)).type).toBe('submit');
});
+
+ it('Fallbacks to set location URL when in the main frame of a detached Window.', () => {
+ vi.spyOn(Fetch.prototype, 'send').mockImplementation(function (): Promise {
+ throw new Error('Request should not be sent.');
+ });
+
+ expect(window.location.href).toBe('about:blank');
+
+ element.action = 'https://localhost:3000';
+ element.requestSubmit();
+
+ expect(window.location.href).toBe('https://localhost:3000/');
+ });
+
+ it('Submits form as query string when method is "GET".', async () => {
+ let request: IRequest | null = null;
+
+ vi.spyOn(Fetch.prototype, 'send').mockImplementation(function (): Promise {
+ request = this.request;
+ return Promise.resolve({
+ url: request?.url,
+ text: () =>
+ new Promise((resolve) => setTimeout(() => resolve('Test'), 2))
+ });
+ });
+
+ const browser = new Browser();
+ const page = browser.newPage();
+ const oldWindow = page.mainFrame.window;
+
+ page.mainFrame.url = 'http://referrer.example.com';
+
+ oldWindow.document.write(`
+
+ `);
+
+ (oldWindow.document.querySelector('input[name="text1"]')).value =
+ 'invalid';
+
+ oldWindow.document.body.children[0]['button1'].click();
+
+ await new Promise((resolve) => setTimeout(resolve, 2));
+
+ expect(page.mainFrame.url).toBe('http://referrer.example.com/');
+
+ (oldWindow.document.querySelector('input[name="text1"]')).value = 'test';
+
+ oldWindow.document.body.children[0]['button1'].click();
+
+ await page.mainFrame.waitForNavigation();
+
+ expect(((request)).referrer).toBe('about:client');
+ expect(((request)).referrerPolicy).toBe('origin');
+ expect(((request)).method).toBe('GET');
+
+ expect(page.mainFrame.url).toBe(
+ 'http://example.com/?text1=test&text2=value2&checkbox1=value1&radio1=value2'
+ );
+ expect(page.mainFrame.window).not.toBe(oldWindow);
+ expect(oldWindow.location.href).toBe('http://referrer.example.com/');
+ expect(page.mainFrame.window.location.href).toBe(
+ 'http://example.com/?text1=test&text2=value2&checkbox1=value1&radio1=value2'
+ );
+ expect(page.mainFrame.window.document.body.innerHTML).toBe('Test');
+ });
});
describe('reset()', () => {