From 658a808c265a2fc26f5928ce35d89679bebfce9b Mon Sep 17 00:00:00 2001 From: Magnus Dahl Eide Date: Mon, 4 Aug 2025 14:09:59 +0200 Subject: [PATCH 1/2] update e2e --- .../app/config-redirect/dest/page.tsx | 13 ++++++++ .../app-router/app/config-redirect/page.tsx | 9 ++++++ .../app-router/e2e/config.redirect.test.ts | 32 +++++++++++++++++++ .../e2e/middleware.redirect.test.ts | 9 ++++++ examples/e2e/app-router/middleware.ts | 6 ++++ examples/e2e/app-router/next.config.ts | 5 +++ 6 files changed, 74 insertions(+) create mode 100644 examples/e2e/app-router/app/config-redirect/dest/page.tsx diff --git a/examples/e2e/app-router/app/config-redirect/dest/page.tsx b/examples/e2e/app-router/app/config-redirect/dest/page.tsx new file mode 100644 index 00000000..e2051a79 --- /dev/null +++ b/examples/e2e/app-router/app/config-redirect/dest/page.tsx @@ -0,0 +1,13 @@ +export default async function Page({ + searchParams, +}: { + searchParams: Promise<{ [key: string]: string | string[] | undefined }>; +}) { + const q = (await searchParams).q; + + return ( + <> +
q: {q}
+ + ); +} diff --git a/examples/e2e/app-router/app/config-redirect/page.tsx b/examples/e2e/app-router/app/config-redirect/page.tsx index b7766ca6..387637c8 100644 --- a/examples/e2e/app-router/app/config-redirect/page.tsx +++ b/examples/e2e/app-router/app/config-redirect/page.tsx @@ -3,6 +3,15 @@ export default function RedirectDestination() {

I was redirected from next.config.js

/next-config-redirect => /config-redirect

+ + /next-config-redirect-encoding?q=äöå€ + + + /next-config-redirect-encoding?q=%C3%A4%C3%B6%C3%A5%E2%82%AC +
); } diff --git a/examples/e2e/app-router/e2e/config.redirect.test.ts b/examples/e2e/app-router/e2e/config.redirect.test.ts index cb6c970e..fb4df8ca 100644 --- a/examples/e2e/app-router/e2e/config.redirect.test.ts +++ b/examples/e2e/app-router/e2e/config.redirect.test.ts @@ -72,4 +72,36 @@ test.describe("Next Config Redirect", () => { }); await expect(el).toBeVisible(); }); + test("Should properly encode the Location header for redirects with query params", async ({ page }) => { + await page.goto("/config-redirect"); + const responsePromise = page.waitForResponse((response) => { + return response.status() === 307; + }); + page.getByTestId("redirect-link").click(); + const res = await responsePromise; + await page.waitForURL("/config-redirect/dest?q=äöå€"); + + const locationHeader = res.headers().location; + expect(locationHeader).toBe("/config-redirect/dest?q=%C3%A4%C3%B6%C3%A5%E2%82%AC"); + expect(res.status()).toBe(307); + + const searchParams = page.getByTestId("searchParams"); + await expect(searchParams).toHaveText("q: äöå€"); + }); + test("Should respect already encoded query params", async ({ page }) => { + await page.goto("/config-redirect"); + const responsePromise = page.waitForResponse((response) => { + return response.status() === 307; + }); + page.getByTestId("redirect-link-already-encoded").click(); + const res = await responsePromise; + await page.waitForURL("/config-redirect/dest?q=äöå€"); + + const locationHeader = res.headers().location; + expect(locationHeader).toBe("/config-redirect/dest?q=%C3%A4%C3%B6%C3%A5%E2%82%AC"); + expect(res.status()).toBe(307); + + const searchParams = page.getByTestId("searchParams"); + await expect(searchParams).toHaveText("q: äöå€"); + }); }); diff --git a/examples/e2e/app-router/e2e/middleware.redirect.test.ts b/examples/e2e/app-router/e2e/middleware.redirect.test.ts index 45159b8a..b9ab181f 100644 --- a/examples/e2e/app-router/e2e/middleware.redirect.test.ts +++ b/examples/e2e/app-router/e2e/middleware.redirect.test.ts @@ -36,3 +36,12 @@ test("Middleware Rewrite External Image", async ({ page }) => { expect(validateMd5(bodyBuffer, OPENNEXT_PNG_MD5)).toBe(true); }); }); + +test("Middleware Rewrite Status Code", async ({ page }) => { + await page.goto("/rewrite-status-code"); + const el = page.getByText("Rewritten Destination", { exact: true }); + await expect(el).toBeVisible(); + page.on("response", async (response) => { + expect(response.status()).toBe(403); + }); +}); diff --git a/examples/e2e/app-router/middleware.ts b/examples/e2e/app-router/middleware.ts index 71081bc4..ace1530d 100644 --- a/examples/e2e/app-router/middleware.ts +++ b/examples/e2e/app-router/middleware.ts @@ -28,6 +28,12 @@ export function middleware(request: NextRequest) { const u = new URL("https://opennext.js.org/share.png"); return NextResponse.rewrite(u); } + if (path === "/rewrite-status-code") { + const u = new URL("/rewrite-destination", `${protocol}://${host}`); + return NextResponse.rewrite(u, { + status: 403, + }); + } if (path === "/cookies") { const res = NextResponse.next(); res.cookies.set("foo", "bar"); diff --git a/examples/e2e/app-router/next.config.ts b/examples/e2e/app-router/next.config.ts index e629b612..fff69ce3 100644 --- a/examples/e2e/app-router/next.config.ts +++ b/examples/e2e/app-router/next.config.ts @@ -59,6 +59,11 @@ const nextConfig: NextConfig = { basePath: false, locale: false, }, + { + source: "/next-config-redirect-encoding", + destination: "/config-redirect/dest", + permanent: false, + }, ]; }, async headers() { From be76a4171cbb46a207602f3d1f4dcb3b0ad7afa2 Mon Sep 17 00:00:00 2001 From: Magnus Dahl Eide Date: Mon, 4 Aug 2025 14:16:08 +0200 Subject: [PATCH 2/2] mv --- .../e2e/middleware.redirect.test.ts | 27 ------------------- .../app-router/e2e/middleware.rewrite.test.ts | 27 +++++++++++++++++++ 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/examples/e2e/app-router/e2e/middleware.redirect.test.ts b/examples/e2e/app-router/e2e/middleware.redirect.test.ts index b9ab181f..44f2dc11 100644 --- a/examples/e2e/app-router/e2e/middleware.redirect.test.ts +++ b/examples/e2e/app-router/e2e/middleware.redirect.test.ts @@ -1,11 +1,4 @@ import { expect, test } from "@playwright/test"; -import { validateMd5 } from "../../utils"; - -/* - * `curl -s https://opennext.js.org/share.png | md5sum` - * This is the MD5 hash of the image. It is used to validate the image content. - */ -const OPENNEXT_PNG_MD5 = "405f45cc3397b09717a13ebd6f1e027b"; test("Middleware Redirect", async ({ page, context }) => { await page.goto("/"); @@ -25,23 +18,3 @@ test("Middleware Redirect", async ({ page, context }) => { el = page.getByText("Redirect Destination", { exact: true }); await expect(el).toBeVisible(); }); - -test("Middleware Rewrite External Image", async ({ page }) => { - await page.goto("/rewrite-external"); - page.on("response", async (response) => { - expect(response.status()).toBe(200); - expect(response.headers()["content-type"]).toBe("image/png"); - expect(response.headers()["cache-control"]).toBe("max-age=600"); - const bodyBuffer = await response.body(); - expect(validateMd5(bodyBuffer, OPENNEXT_PNG_MD5)).toBe(true); - }); -}); - -test("Middleware Rewrite Status Code", async ({ page }) => { - await page.goto("/rewrite-status-code"); - const el = page.getByText("Rewritten Destination", { exact: true }); - await expect(el).toBeVisible(); - page.on("response", async (response) => { - expect(response.status()).toBe(403); - }); -}); diff --git a/examples/e2e/app-router/e2e/middleware.rewrite.test.ts b/examples/e2e/app-router/e2e/middleware.rewrite.test.ts index fb89df14..24c027b8 100644 --- a/examples/e2e/app-router/e2e/middleware.rewrite.test.ts +++ b/examples/e2e/app-router/e2e/middleware.rewrite.test.ts @@ -1,4 +1,11 @@ import { expect, test } from "@playwright/test"; +import { validateMd5 } from "../../utils"; + +/* + * `curl -s https://opennext.js.org/share.png | md5sum` + * This is the MD5 hash of the image. It is used to validate the image content. + */ +const OPENNEXT_PNG_MD5 = "405f45cc3397b09717a13ebd6f1e027b"; test("Middleware Rewrite", async ({ page }) => { await page.goto("/"); @@ -14,3 +21,23 @@ test("Middleware Rewrite", async ({ page }) => { el = page.getByText("Rewritten Destination", { exact: true }); await expect(el).toBeVisible(); }); + +test("Middleware Rewrite External Image", async ({ page }) => { + await page.goto("/rewrite-external"); + page.on("response", async (response) => { + expect(response.status()).toBe(200); + expect(response.headers()["content-type"]).toBe("image/png"); + expect(response.headers()["cache-control"]).toBe("max-age=600"); + const bodyBuffer = await response.body(); + expect(validateMd5(bodyBuffer, OPENNEXT_PNG_MD5)).toBe(true); + }); +}); + +test("Middleware Rewrite Status Code", async ({ page }) => { + await page.goto("/rewrite-status-code"); + const el = page.getByText("Rewritten Destination", { exact: true }); + await expect(el).toBeVisible(); + page.on("response", async (response) => { + expect(response.status()).toBe(403); + }); +});