Skip to content

Commit

Permalink
e2e: add open-graph image tests (#692)
Browse files Browse the repository at this point in the history
* add og to app router

* add e2e

* md5 checksum

* review
  • Loading branch information
sommeeeer authored Jan 8, 2025
1 parent e8f6dc8 commit 8530f7c
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 0 deletions.
72 changes: 72 additions & 0 deletions examples/app-router/app/api/og/route.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { ImageResponse } from "next/og";
// App router includes @vercel/og.
// No need to install it.
// ?title=<title>

export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url);

// ?title=<title>
const hasTitle = searchParams.has("title");
const title = hasTitle
? searchParams.get("title")?.slice(0, 100)
: "My default title";

return new ImageResponse(
<div
style={{
backgroundColor: "black",
backgroundSize: "150px 150px",
height: "100%",
width: "100%",
display: "flex",
textAlign: "center",
alignItems: "center",
justifyContent: "center",
flexDirection: "column",
flexWrap: "nowrap",
}}
>
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
justifyItems: "center",
}}
>
<img
alt="Vercel"
height={200}
src="data:image/svg+xml,%3Csvg width='116' height='100' fill='white' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M57.5 0L115 100H0L57.5 0z' /%3E%3C/svg%3E"
style={{ margin: "0 30px" }}
width={232}
/>
</div>
<div
style={{
fontSize: 60,
fontStyle: "normal",
letterSpacing: "-0.025em",
color: "white",
marginTop: 30,
padding: "0 120px",
lineHeight: 1.4,
whiteSpace: "pre-wrap",
}}
>
{title}
</div>
</div>,
{
width: 1200,
height: 630,
},
);
} catch (e: any) {
return new Response("Failed to generate the image", {
status: 500,
});
}
}
36 changes: 36 additions & 0 deletions examples/app-router/app/og/opengraph-image.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { ImageResponse } from "next/og";

// Image metadata
export const alt = "OpenNext";
export const size = {
width: 1200,
height: 630,
};

export const contentType = "image/png";

// Image generation
export default async function Image() {
return new ImageResponse(
// ImageResponse JSX element
<div
style={{
fontSize: 128,
background: "white",
width: "100%",
height: "100%",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
OpenNext
</div>,
// ImageResponse options
{
// For convenience, we can re-use the exported opengraph-image
// size config to also set the ImageResponse's width and height.
...size,
},
);
}
3 changes: 3 additions & 0 deletions examples/app-router/app/og/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Page() {
return <div></div>;
}
60 changes: 60 additions & 0 deletions packages/tests-e2e/tests/appRouter/og.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { createHash } from "node:crypto";
import { expect, test } from "@playwright/test";

// This is the md5sums of the expected PNGs generated with `md5sum <file>`
const OG_MD5 = "6e5e794ac0c27598a331690f96f05d00";
const API_OG_MD5 = "cac95fc3e2d4d52870c0536bb18ba85b";

function validateMd5(data: Buffer, expectedHash: string) {
return createHash("md5").update(data).digest("hex") === expectedHash;
}

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);
});

0 comments on commit 8530f7c

Please sign in to comment.