diff --git a/packages/fresh/src/runtime/client/partials.ts b/packages/fresh/src/runtime/client/partials.ts index 008e23a9592..31879bf87b7 100644 --- a/packages/fresh/src/runtime/client/partials.ts +++ b/packages/fresh/src/runtime/client/partials.ts @@ -304,7 +304,14 @@ document.addEventListener("submit", async (e) => { // TODO: Looks like constructor type for URLSearchParam is wrong // deno-lint-ignore no-explicit-any const qs = new URLSearchParams(new FormData(el, e.submitter) as any); - qs.forEach((value, key) => partialUrl.searchParams.append(key, value)); + qs.forEach((value, key) => { + partialUrl.searchParams.append(key, value); + // The address bar has to reflect the submitted values too, the way a + // native GET form navigation does. Without this the page URL keeps + // the bare action and the submitted state is lost on reload, on + // copying the link, or on back/forward. + actionUrl.searchParams.append(key, value); + }); } else { init = { body: new FormData(el, e.submitter), method: lowerMethod }; } diff --git a/packages/fresh/tests/partials_test.tsx b/packages/fresh/tests/partials_test.tsx index 9b4a17d510b..b6cdbda9bd9 100644 --- a/packages/fresh/tests/partials_test.tsx +++ b/packages/fresh/tests/partials_test.tsx @@ -2745,6 +2745,51 @@ Deno.test({ }, }); +Deno.test({ + name: "partials - form submit puts values into the page url", + fn: async () => { + const app = testApp() + .get("/", (ctx) => { + const name = ctx.url.searchParams.get("name"); + return ctx.render( + +
+
+ + +
+ +

{name ?? "init"}

+
+ +
+
, + ); + }); + + await withBrowserApp(app, async (page, address) => { + await page.goto(address, { waitUntil: "load" }); + await page.locator(".ready").wait(); + + await page.locator(".increment").click(); + await waitForText(page, ".output", "1"); + + await page.locator(".update").click(); + await page.locator(".done").wait(); + + // Same URL a native GET form navigation would produce. + const rawUrl = await page.evaluate(() => window.location.href); + const url = new URL(rawUrl); + expect(`${url.pathname}${url.search}`).toEqual("/?name=foo"); + + // Still a partial update, not a full page load. + await waitForText(page, ".output", "1"); + }); + }, +}); + Deno.test({ name: "partials - backwards navigation should keep URLs", fn: async () => {