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
57 changes: 57 additions & 0 deletions web/src/app/journal/[slug]/opengraph-image.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// The card a post shows when its link is shared printed the frontmatter date
// as it is written: "2026-05-14T01:30:00+09:00" across the top right of all
// 37 cards, on 27 October.

import { isValidElement, type ReactElement, type ReactNode } from "react";
import { afterEach, describe, expect, it, vi } from "vitest";
import { getAllJournalPosts } from "@/lib/journal";
import OpenGraphImage from "./opengraph-image";

vi.mock("next/og", () => ({
ImageResponse: class {
element: ReactElement;
constructor(element: ReactElement) {
this.element = element;
}
},
}));

function strings(node: ReactNode): string[] {
if (typeof node === "string" || typeof node === "number") return [String(node)];
if (Array.isArray(node)) return node.flatMap(strings);
if (isValidElement(node)) return strings((node.props as { children?: ReactNode }).children);
return [];
}

async function cardText(slug: string) {
const card = (await OpenGraphImage({ params: Promise.resolve({ slug }) })) as unknown as {
element: ReactElement;
};
return strings(card.element);
}

afterEach(() => {
vi.unstubAllEnvs();
});

describe("journal share card", () => {
it("prints the day the post was written in Seoul, not the frontmatter string", async () => {
vi.stubEnv("TZ", "UTC");
const text = await cardText("headache");

expect(text).toContain("May 14, 2026");
expect(text).not.toContain("2026-05-14T01:30:00+09:00");
});

it("gives no card a raw timestamp", async () => {
vi.stubEnv("TZ", "UTC");
const raw: string[] = [];

for (const post of getAllJournalPosts({ includeDrafts: true })) {
const text = await cardText(post.slug);
if (text.some((line) => /\d{4}-\d{2}-\d{2}T/.test(line))) raw.push(post.slug);
}

expect(raw).toEqual([]);
});
});
6 changes: 4 additions & 2 deletions web/src/app/journal/[slug]/opengraph-image.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ImageResponse } from "next/og";
import { getAllJournalPosts, getJournalSlugs } from "@/lib/journal";
import { formatJournalDate, getAllJournalPosts, getJournalSlugs } from "@/lib/journal";

export const runtime = "nodejs";
export const size = {
Expand Down Expand Up @@ -51,7 +51,9 @@ export default async function OpenGraphImage({ params }: OpenGraphImageProps) {
}}
>
<span>patternflow / journal</span>
<span>{post?.date ?? ""}</span>
{/* The Korean and the English page share this card, and its top
line is English capitals, so the date is the English one. */}
<span>{post ? formatJournalDate(post.date, "en") : ""}</span>
</div>
<div
style={{
Expand Down
Loading