-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test: import app-router e2e tests from aws (#289)
- Loading branch information
Showing
26 changed files
with
734 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { expect, test } from "@playwright/test"; | ||
|
||
test("Next after", async ({ request }) => { | ||
const initialSSG = await request.get("/api/after/ssg"); | ||
expect(initialSSG.status()).toEqual(200); | ||
const initialSSGJson = await initialSSG.json(); | ||
|
||
// We then fire a post request that will revalidate the SSG page 5 seconds after, but should respond immediately | ||
const dateNow = Date.now(); | ||
const revalidateSSG = await request.post("/api/after/revalidate"); | ||
expect(revalidateSSG.status()).toEqual(200); | ||
const revalidateSSGJson = await revalidateSSG.json(); | ||
expect(revalidateSSGJson.success).toEqual(true); | ||
// This request should take less than 5 seconds to respond | ||
expect(Date.now() - dateNow).toBeLessThan(5000); | ||
|
||
// We want to immediately check if the SSG page has been revalidated, it should not have been | ||
const notRevalidatedSSG = await request.get("/api/after/ssg"); | ||
expect(notRevalidatedSSG.status()).toEqual(200); | ||
const notRevalidatedSSGJson = await notRevalidatedSSG.json(); | ||
expect(notRevalidatedSSGJson.date).toEqual(initialSSGJson.date); | ||
|
||
// We then wait for 5 seconds to ensure the SSG page has been revalidated | ||
await new Promise((resolve) => setTimeout(resolve, 5000)); | ||
const revalidatedSSG = await request.get("/api/after/ssg"); | ||
expect(revalidatedSSG.status()).toEqual(200); | ||
const revalidatedSSGJson = await revalidatedSSG.json(); | ||
expect(revalidatedSSGJson.date).not.toEqual(initialSSGJson.date); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { expect, test } from "@playwright/test"; | ||
|
||
test("API call from client", async ({ page }) => { | ||
await page.goto("/"); | ||
await page.getByRole("link", { name: "/API" }).click(); | ||
|
||
await page.waitForURL("/api"); | ||
|
||
let el = page.getByText("API: N/A"); | ||
await expect(el).toBeVisible(); | ||
|
||
await page.getByRole("button", { name: "Call /api/client" }).click(); | ||
el = page.getByText('API: { "hello": "client" }'); | ||
await expect(el).toBeVisible(); | ||
}); | ||
|
||
test("API call from middleware", async ({ page }) => { | ||
await page.goto("/"); | ||
await page.getByRole("link", { name: "/API" }).click(); | ||
|
||
await page.waitForURL("/api"); | ||
|
||
let el = page.getByText("API: N/A"); | ||
await expect(el).toBeVisible(); | ||
|
||
await page.getByRole("button", { name: "Call /api/middleware" }).click(); | ||
el = page.getByText('API: { "hello": "middleware" }'); | ||
await expect(el).toBeVisible(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { expect, test } from "@playwright/test"; | ||
/** | ||
* This tests that the "redirect" config in next.config.js works | ||
* | ||
* redirects: () => { | ||
return [ | ||
{ | ||
source: "/next-config-redirect", | ||
destination: "/config-redirect", | ||
permanent: true, | ||
missing: [{ type: "cookie", key: "missing-cookie" }], | ||
}, | ||
]; | ||
}, | ||
*/ | ||
test.describe("Next Config Redirect", () => { | ||
test("Missing cookies", async ({ page }) => { | ||
await page.goto("/"); | ||
await page.goto("/next-config-redirect-missing"); | ||
|
||
await page.waitForURL("/config-redirect?missing=true"); | ||
|
||
const el = page.getByText("I was redirected from next.config.js", { | ||
exact: true, | ||
}); | ||
await expect(el).toBeVisible(); | ||
}); | ||
test("Not missing cookies", async ({ page }) => { | ||
await page.goto("/"); | ||
await page.goto("/next-config-redirect-not-missing"); | ||
|
||
// the cookie was not missing, so no redirects | ||
await page.waitForURL("/next-config-redirect-not-missing"); | ||
|
||
const el = page.getByText("This page could not be found.", { | ||
exact: true, | ||
}); | ||
await expect(el).toBeVisible(); | ||
}); | ||
test("Has cookies", async ({ page }) => { | ||
await page.goto("/"); | ||
await page.goto("/next-config-redirect-has"); | ||
|
||
await page.waitForURL("/config-redirect?has=true"); | ||
|
||
const el = page.getByText("I was redirected from next.config.js", { | ||
exact: true, | ||
}); | ||
await expect(el).toBeVisible(); | ||
}); | ||
test("Has cookies with value", async ({ page }) => { | ||
await page.goto("/"); | ||
await page.goto("/next-config-redirect-has-with-value"); | ||
|
||
await page.waitForURL("/config-redirect?hasWithValue=true"); | ||
|
||
const el = page.getByText("I was redirected from next.config.js", { | ||
exact: true, | ||
}); | ||
await expect(el).toBeVisible(); | ||
}); | ||
test("Has cookies with bad value", async ({ page }) => { | ||
await page.goto("/"); | ||
await page.goto("/next-config-redirect-has-with-bad-value"); | ||
|
||
// did not redirect | ||
await page.waitForURL("/next-config-redirect-has-with-bad-value"); | ||
|
||
// 404 not found | ||
const el = page.getByText("This page could not be found.", { | ||
exact: true, | ||
}); | ||
await expect(el).toBeVisible(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { expect, test } from "@playwright/test"; | ||
|
||
/** | ||
* Tests that the headers are available in RSC and response headers | ||
*/ | ||
test("Headers", async ({ page }) => { | ||
const responsePromise = page.waitForResponse((response) => { | ||
return response.status() === 200; | ||
}); | ||
await page.goto("/headers"); | ||
|
||
const response = await responsePromise; | ||
// Response header should be set | ||
const headers = response.headers(); | ||
expect(headers["response-header"]).toEqual("response-header"); | ||
|
||
// The next.config.js headers should be also set in response | ||
expect(headers["e2e-headers"]).toEqual("next.config.js"); | ||
|
||
// Request header should be available in RSC | ||
const el = page.getByText("request-header"); | ||
await expect(el).toBeVisible(); | ||
|
||
// Both these headers should not be present cause poweredByHeader is false in appRouter | ||
expect(headers["x-powered-by"]).toBeFalsy(); | ||
expect(headers["x-opennext"]).toBeFalsy(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { expect, test } from "@playwright/test"; | ||
|
||
/** | ||
* Tests that the request.url is the deployed host and not localhost | ||
*/ | ||
test("Request.url is host", async ({ baseURL, page }) => { | ||
await page.goto("/api/host"); | ||
|
||
const el = page.getByText(`{"url":"${baseURL}/api/host"}`); | ||
await expect(el).toBeVisible(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { expect, test } from "@playwright/test"; | ||
|
||
test("Image Optimization", async ({ page }) => { | ||
await page.goto("/"); | ||
|
||
const imageResponsePromise = page.waitForResponse(/https%3A%2F%2Fopennext.js.org%2Farchitecture.png/); | ||
await page.locator('[href="/image-optimization"]').click(); | ||
const imageResponse = await imageResponsePromise; | ||
|
||
await page.waitForURL("/image-optimization"); | ||
|
||
const imageContentType = imageResponse.headers()["content-type"]; | ||
expect(imageContentType).toBe("image/webp"); | ||
|
||
const el = page.locator("img"); | ||
await expect(el).toHaveJSProperty("complete", true); | ||
await expect(el).not.toHaveJSProperty("naturalWidth", 0); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { expect, test } from "@playwright/test"; | ||
|
||
test("Test revalidate", async ({ request }) => { | ||
const result = await request.get("/api/isr"); | ||
|
||
expect(result.status()).toEqual(200); | ||
const json = await result.json(); | ||
const body = json.body; | ||
|
||
expect(json.status).toEqual(200); | ||
expect(body.result).toEqual(true); | ||
expect(body.cacheControl).toEqual("private, no-cache, no-store, max-age=0, must-revalidate"); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { expect, test } from "@playwright/test"; | ||
|
||
test("Incremental Static Regeneration", async ({ page }) => { | ||
test.setTimeout(45000); | ||
await page.goto("/"); | ||
await page.locator("[href='/isr']").click(); | ||
// 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); | ||
}); | ||
|
||
test("headers", async ({ page }) => { | ||
let responsePromise = page.waitForResponse((response) => { | ||
return response.status() === 200; | ||
}); | ||
await page.goto("/isr"); | ||
|
||
while (true) { | ||
const response = await responsePromise; | ||
const headers = response.headers(); | ||
|
||
// this was set in middleware | ||
if (headers["cache-control"] === "max-age=10, stale-while-revalidate=999") { | ||
break; | ||
} | ||
await page.waitForTimeout(1000); | ||
responsePromise = page.waitForResponse((response) => { | ||
return response.status() === 200; | ||
}); | ||
await page.reload(); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { expect, test } from "@playwright/test"; | ||
|
||
test("Cookies", async ({ page, context }) => { | ||
await page.goto("/"); | ||
|
||
const cookies = await context.cookies(); | ||
const from = cookies.find(({ name }) => name === "from"); | ||
expect(from?.value).toEqual("middleware"); | ||
|
||
const love = cookies.find(({ name }) => name === "with"); | ||
expect(love?.value).toEqual("love"); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { expect, test } from "@playwright/test"; | ||
|
||
test("Middleware Redirect", async ({ page, context }) => { | ||
await page.goto("/"); | ||
await page.getByRole("link", { name: "/Redirect" }).click(); | ||
|
||
// URL is immediately redirected | ||
await page.waitForURL("/redirect-destination"); | ||
let el = page.getByText("Redirect Destination", { exact: true }); | ||
await expect(el).toBeVisible(); | ||
|
||
// Loading page should also redirect | ||
await page.goto("/redirect"); | ||
await page.waitForURL("/redirect-destination"); | ||
expect(await context.cookies().then((res) => res.find((cookie) => cookie.name === "test")?.value)).toBe( | ||
"success" | ||
); | ||
el = page.getByText("Redirect Destination", { exact: true }); | ||
await expect(el).toBeVisible(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { expect, test } from "@playwright/test"; | ||
|
||
test("Middleware Rewrite", async ({ page }) => { | ||
await page.goto("/"); | ||
await page.getByRole("link", { name: "/Rewrite" }).click(); | ||
|
||
await page.waitForURL("/rewrite"); | ||
let el = page.getByText("Rewritten Destination", { exact: true }); | ||
await expect(el).toBeVisible(); | ||
|
||
// Loading page should also rewrite | ||
await page.goto("/rewrite"); | ||
await page.waitForURL("/rewrite"); | ||
el = page.getByText("Rewritten Destination", { exact: true }); | ||
await expect(el).toBeVisible(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { expect, test } from "@playwright/test"; | ||
|
||
test("Route modal and interception", async ({ page }) => { | ||
await page.goto("/"); | ||
await page.getByRole("link", { name: "Albums" }).click(); | ||
await page.getByRole("link", { name: "Song: I'm never gonna give you up Year: 1965" }).click(); | ||
|
||
await page.waitForURL(`/albums/Hold%20Me%20In%20Your%20Arms/I'm%20never%20gonna%20give%20you%20up`); | ||
|
||
const modal = page.getByText("Modal", { exact: true }); | ||
await expect(modal).toBeVisible(); | ||
|
||
// Reload the page to load non intercepted modal | ||
await page.reload(); | ||
await page.waitForURL(`/albums/Hold%20Me%20In%20Your%20Arms/I'm%20never%20gonna%20give%20you%20up`); | ||
const notModal = page.getByText("Not Modal", { exact: true }); | ||
await expect(notModal).toBeVisible(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { expect, test } from "@playwright/test"; | ||
import { validateMd5 } from "../../utils"; | ||
|
||
// This is the md5sums of the expected PNGs generated with `md5sum <file>` | ||
const OG_MD5 = "6e5e794ac0c27598a331690f96f05d00"; | ||
const API_OG_MD5 = "cac95fc3e2d4d52870c0536bb18ba85b"; | ||
|
||
test("Open-graph image to be in metatags and present", async ({ page, request }) => { | ||
await page.goto("/og"); | ||
|
||
// Wait for meta tags to be present | ||
const ogImageSrc = await page.locator('meta[property="og:image"]').getAttribute("content"); | ||
const ogImageAlt = await page.locator('meta[property="og:image:alt"]').getAttribute("content"); | ||
const ogImageType = await page.locator('meta[property="og:image:type"]').getAttribute("content"); | ||
const ogImageWidth = await page.locator('meta[property="og:image:width"]').getAttribute("content"); | ||
const ogImageHeight = await page.locator('meta[property="og:image:height"]').getAttribute("content"); | ||
|
||
// Verify meta tag exists and is the correct values | ||
expect(ogImageSrc).not.toBe(null); | ||
expect(ogImageAlt).toBe("OpenNext"); | ||
expect(ogImageType).toBe("image/png"); | ||
expect(ogImageWidth).toBe("1200"); | ||
expect(ogImageHeight).toBe("630"); | ||
|
||
// Check if the image source is working | ||
const response = await request.get(`/og/${ogImageSrc?.split("/").at(-1)}`); | ||
expect(response.status()).toBe(200); | ||
expect(response.headers()["content-type"]).toBe("image/png"); | ||
expect(response.headers()["cache-control"]).toBe("public, immutable, no-transform, max-age=31536000"); | ||
expect(validateMd5(await response.body(), OG_MD5)).toBe(true); | ||
}); | ||
|
||
test("next/og (vercel/og) to work in API route", async ({ request }) => { | ||
const response = await request.get("api/og?title=opennext"); | ||
expect(response.status()).toBe(200); | ||
expect(response.headers()["content-type"]).toBe("image/png"); | ||
expect(response.headers()["cache-control"]).toBe("public, immutable, no-transform, max-age=31536000"); | ||
expect(validateMd5(await response.body(), API_OG_MD5)).toBe(true); | ||
}); |
Oops, something went wrong.