Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion examples/e2e/app-router/sst-env.d.ts

This file was deleted.

1 change: 1 addition & 0 deletions examples/e2e/pages-router/.env.production
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SOME_PROD_VAR=bar
43 changes: 43 additions & 0 deletions examples/e2e/pages-router/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
.open-next
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts

# playwright
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
3 changes: 3 additions & 0 deletions examples/e2e/pages-router/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Pages Router

This project uses the Pages Router exclusively.
9 changes: 9 additions & 0 deletions examples/e2e/pages-router/e2e/404.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { expect, test } from "@playwright/test";

test("should return 404 on a route not corresponding to any route", async ({ page }) => {
const result = await page.goto("/not-existing/route");
expect(result).toBeDefined();
expect(result?.status()).toBe(404);
const headers = result?.headers();
expect(headers?.["cache-control"]).toBe("private, no-cache, no-store, max-age=0, must-revalidate");
});
21 changes: 21 additions & 0 deletions examples/e2e/pages-router/e2e/data.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { expect, test } from "@playwright/test";

test("fix _next/data", async ({ page }) => {
await page.goto("/");

const isrJson = page.waitForResponse("/_next/data/*/en/isr.json");
await page.locator('[href="/isr/"]').click();
const response = await isrJson;
expect(response.ok()).toBe(true);
expect(response.request().url()).toMatch(/\/_next\/data\/.*\/en\/isr\.json$/);
await page.waitForURL("/isr/");

const homeJson = page.waitForResponse("/_next/data/*/en.json");
await page.locator('[href="/"]').click();
const response2 = await homeJson;
expect(response2.ok()).toBe(true);
expect(response2.request().url()).toMatch(/\/_next\/data\/.*\/en\.json$/);
await page.waitForURL("/");
const body = await response2.json();
expect(body).toEqual({ pageProps: { hello: "world" }, __N_SSG: true });
});
12 changes: 12 additions & 0 deletions examples/e2e/pages-router/e2e/header.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { expect, test } from "@playwright/test";

test("should test if poweredByHeader adds the correct headers ", async ({ page }) => {
const result = await page.goto("/");
expect(result).toBeDefined();
expect(result?.status()).toBe(200);
const headers = result?.headers();

// Both these headers should be present cause poweredByHeader is true in pagesRouter
expect(headers?.["x-powered-by"]).toBe("Next.js");
expect(headers?.["x-opennext"]).toBe("1");
});
17 changes: 17 additions & 0 deletions examples/e2e/pages-router/e2e/i18n.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { expect, test } from "@playwright/test";

test("Next config headers with i18n", async ({ page }) => {
const responsePromise = page.waitForResponse((response) => {
return response.status() === 200;
});
await page.goto("/");

const response = await responsePromise;
// Response header should be set
const headers = response.headers();
// Headers from next.config.js should be set
expect(headers["x-custom-header"]).toEqual("my custom header value");

// Headers from middleware should be set
expect(headers["x-from-middleware"]).toEqual("true");
});
41 changes: 41 additions & 0 deletions examples/e2e/pages-router/e2e/isr.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { expect, test } from "@playwright/test";

test("Incremental Static Regeneration", async ({ page }) => {
test.setTimeout(45000);
await page.goto("/");
await page.locator("[href='/isr/']").click();
await page.waitForURL("/isr/");
// Load the page a couple times to regenerate ISR

let el = page.getByText("Time:");
// Track the static time
let time = await el.textContent();
let newTime: typeof time;
let tempTime = time;
do {
await page.waitForTimeout(1000);
await page.reload();
time = tempTime;
el = page.getByText("Time:");
newTime = await el.textContent();
tempTime = newTime;
} while (time !== newTime);
await page.reload();
await page.waitForTimeout(1000);
el = page.getByText("Time:");
const midTime = await el.textContent();
// Expect that the time is still stale
expect(midTime).toEqual(newTime);

// Wait 10 + 1 seconds for ISR to regenerate time
await page.waitForTimeout(11000);
let finalTime = newTime;
do {
await page.waitForTimeout(2000);
el = page.getByText("Time:");
finalTime = await el.textContent();
await page.reload();
} while (newTime === finalTime);

expect(newTime).not.toEqual(finalTime);
});
54 changes: 54 additions & 0 deletions examples/e2e/pages-router/e2e/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { defineConfig, devices } from "@playwright/test";
import type nodeProcess from "node:process";

declare const process: typeof nodeProcess;

/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: "./",
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: "html",
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: "http://localhost:8791",

/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "on-first-retry",
},

/* Configure projects for major browsers */
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
// TODO(vicb): enable all browsers
// {
// name: "firefox",
// use: { ...devices["Desktop Firefox"] },
// },
// {
// name: "webkit",
// use: { ...devices["Desktop Safari"] },
// },
],

/* Run your local dev server before starting the tests */
webServer: {
command: "pnpm preview",
url: "http://localhost:8791",
reuseExistingServer: !process.env.CI,
timeout: 70_000,
},
});
25 changes: 25 additions & 0 deletions examples/e2e/pages-router/e2e/redirect.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { expect, test } from "@playwright/test";

test("Single redirect", async ({ page }) => {
await page.goto("/next-config-redirect-without-locale-support/");

await page.waitForURL("https://opennext.js.org/");
const el = page.getByRole("heading", { name: "OpenNext" });
await expect(el).toBeVisible();
});

test("Redirect with default locale support", async ({ page }) => {
await page.goto("/redirect-with-locale/");

await page.waitForURL("/ssr/");
const el = page.getByText("SSR");
await expect(el).toBeVisible();
});

test("Redirect with locale support", async ({ page }) => {
await page.goto("/nl/redirect-with-locale/");

await page.waitForURL("/nl/ssr/");
const el = page.getByText("SSR");
await expect(el).toBeVisible();
});
25 changes: 25 additions & 0 deletions examples/e2e/pages-router/e2e/rewrite.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { expect, test } from "@playwright/test";
import { validateMd5 } from "../../utils";

const EXT_PNG_MD5 = "405f45cc3397b09717a13ebd6f1e027b";

test("Single Rewrite", async ({ page }) => {
await page.goto("/rewrite");

const el = page.getByText("Nextjs Pages Router");
await expect(el).toBeVisible();
});

test("Rewrite with query", async ({ page }) => {
await page.goto("/rewriteUsingQuery?d=ssr");

const el = page.getByText("SSR");
await expect(el).toBeVisible();
});

test("Rewrite to external image", async ({ request }) => {
const response = await request.get("/external-on-image");
expect(response.status()).toBe(200);
expect(response.headers()["content-type"]).toBe("image/png");
expect(validateMd5(await response.body(), EXT_PNG_MD5)).toBe(true);
});
33 changes: 33 additions & 0 deletions examples/e2e/pages-router/e2e/ssr.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { expect, test } from "@playwright/test";

test("Server Side Render", async ({ page }) => {
await page.goto("/");
await page.locator('[href="/ssr/"]').click();

await page.waitForURL("/ssr/");
let el = page.getByText("Time:");
await expect(el).toBeVisible();
let time = await el.textContent();

await page.reload();

el = page.getByText("Time:");
let newTime = await el.textContent();
await expect(el).toBeVisible();

for (let i = 0; i < 5; i++) {
await page.reload();
el = page.getByText("Time:");
newTime = await el.textContent();
await expect(el).toBeVisible();
expect(time).not.toEqual(newTime);
time = newTime;
await page.waitForTimeout(250);
}
});

test("Server Side Render with env", async ({ page }) => {
await page.goto("/ssr/");
const el = page.getByText("Env:");
expect(await el.textContent()).toEqual("Env: bar");
});
15 changes: 15 additions & 0 deletions examples/e2e/pages-router/e2e/trailing.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { expect, test } from "@playwright/test";

test("trailingSlash redirect", async ({ page }) => {
const response = await page.goto("/ssr");

expect(response?.request().redirectedFrom()?.url()).toMatch(/\/ssr$/);
expect(response?.request().url()).toMatch(/\/ssr\/$/);
});

test("trailingSlash redirect with search parameters", async ({ page }) => {
const response = await page.goto("/ssr?happy=true");

expect(response?.request().redirectedFrom()?.url()).toMatch(/\/ssr\?happy=true$/);
expect(response?.request().url()).toMatch(/\/ssr\/\?happy=true$/);
});
67 changes: 67 additions & 0 deletions examples/e2e/pages-router/next.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
transpilePackages: ["@example/shared", "react", "react-dom"],
i18n: {
locales: ["en", "nl"],
defaultLocale: "en",
},
cleanDistDir: true,
reactStrictMode: true,
output: "standalone",
// outputFileTracingRoot: "../sst",
typescript: {
ignoreBuildErrors: true,
},
eslint: {
ignoreDuringBuilds: true,
},
headers: async () => [
{
source: "/",
headers: [
{
key: "x-custom-header",
value: "my custom header value",
},
],
},
],
rewrites: async () => [
{ source: "/rewrite", destination: "/", locale: false },
{
source: "/rewriteUsingQuery",
destination: "/:destination/",
locale: false,
has: [
{
type: "query",
key: "d",
value: "(?<destination>\\w+)",
},
],
},
{
source: "/external-on-image",
destination: "https://opennext.js.org/share.png",
},
],
redirects: async () => [
{
source: "/next-config-redirect-without-locale-support/",
destination: "https://opennext.js.org/",
permanent: false,
basePath: false,
locale: false,
},
{
source: "/redirect-with-locale/",
destination: "/ssr/",
permanent: false,
},
],
trailingSlash: true,
poweredByHeader: true,
};

export default nextConfig;
Loading
Loading