From 30cf82ac3e970a6a3c0f07db1340dd7152d1c35d Mon Sep 17 00:00:00 2001 From: Robert van Hoesel Date: Tue, 23 Apr 2024 22:52:55 +0200 Subject: [PATCH] Prevents inputs from changing ViewTransitions' form method or action (#10856) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Prevents inputs from changing ViewTransitions' form method or action. Fixes #10849 * Consistency 🧘‍♂️ --- .changeset/tasty-swans-refuse.md | 5 +++++ .../astro/components/ViewTransitions.astro | 11 +++++++++-- .../src/pages/form-seven.astro | 11 +++++++++++ .../view-transitions/src/pages/form-six.astro | 11 +++++++++++ packages/astro/e2e/view-transitions.test.js | 19 +++++++++++++++++++ 5 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 .changeset/tasty-swans-refuse.md create mode 100644 packages/astro/e2e/fixtures/view-transitions/src/pages/form-seven.astro create mode 100644 packages/astro/e2e/fixtures/view-transitions/src/pages/form-six.astro diff --git a/.changeset/tasty-swans-refuse.md b/.changeset/tasty-swans-refuse.md new file mode 100644 index 0000000000..8a8d6dde57 --- /dev/null +++ b/.changeset/tasty-swans-refuse.md @@ -0,0 +1,5 @@ +--- +"astro": patch +--- + +Prevents inputs with a name attribute of action or method to break ViewTransitions' form submission diff --git a/packages/astro/components/ViewTransitions.astro b/packages/astro/components/ViewTransitions.astro index c33d9a3f5f..84a68d61e6 100644 --- a/packages/astro/components/ViewTransitions.astro +++ b/packages/astro/components/ViewTransitions.astro @@ -108,9 +108,16 @@ const { fallback = 'animate' } = Astro.props; const form = el as HTMLFormElement; const submitter = ev.submitter; const formData = new FormData(form, submitter); + // form.action and form.method can point to an or + // in which case should fallback to the form attribute + const formAction = + typeof form.action === 'string' ? form.action : form.getAttribute('action'); + const formMethod = + typeof form.method === 'string' ? form.method : form.getAttribute('method'); // Use the form action, if defined, otherwise fallback to current path. - let action = submitter?.getAttribute('formaction') ?? form.action ?? location.pathname; - const method = submitter?.getAttribute('formmethod') ?? form.method; + let action = submitter?.getAttribute('formaction') ?? formAction ?? location.pathname; + // Use the form method, if defined, otherwise fallback to "get" + const method = submitter?.getAttribute('formmethod') ?? formMethod ?? 'get'; // the "dialog" method is a special keyword used within elements // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fs-method diff --git a/packages/astro/e2e/fixtures/view-transitions/src/pages/form-seven.astro b/packages/astro/e2e/fixtures/view-transitions/src/pages/form-seven.astro new file mode 100644 index 0000000000..71befd9247 --- /dev/null +++ b/packages/astro/e2e/fixtures/view-transitions/src/pages/form-seven.astro @@ -0,0 +1,11 @@ +--- +import Layout from '../components/Layout.astro'; + +--- + +
+

This form has an no method defined, but input with `name=method`

+ + +
+
diff --git a/packages/astro/e2e/fixtures/view-transitions/src/pages/form-six.astro b/packages/astro/e2e/fixtures/view-transitions/src/pages/form-six.astro new file mode 100644 index 0000000000..699fb1842a --- /dev/null +++ b/packages/astro/e2e/fixtures/view-transitions/src/pages/form-six.astro @@ -0,0 +1,11 @@ +--- +import Layout from '../components/Layout.astro'; + +--- + +
+

This form has an input with `name=action`

+ + +
+
diff --git a/packages/astro/e2e/view-transitions.test.js b/packages/astro/e2e/view-transitions.test.js index ef76010a58..5e2ea0aceb 100644 --- a/packages/astro/e2e/view-transitions.test.js +++ b/packages/astro/e2e/view-transitions.test.js @@ -1168,6 +1168,25 @@ test.describe('View Transitions', () => { ).toEqual(['application/x-www-form-urlencoded']); }); + + test('form POST that includes an input with name action should not override action', async ({ page, astro }) => { + await page.goto(astro.resolveUrl('/form-six')); + page.on('request', (request) => { + expect(request.url()).toContain('/bar') + }); + // Submit the form + await page.click('#submit'); + }); + + test('form without method that includes an input with name method should not override default method', async ({ page, astro }) => { + await page.goto(astro.resolveUrl('/form-seven')); + page.on('request', (request) => { + expect(request.method()).toBe('GET') + }); + // Submit the form + await page.click('#submit'); + }); + test('Route announcer is invisible on page transition', async ({ page, astro }) => { await page.goto(astro.resolveUrl('/no-directive-one'));