mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-08-22 14:22:16 +10:00
fix(server): emit initial homepage SEO metadata
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
import fs from "node:fs/promises";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
serveStatic: vi.fn((_options?: unknown) => vi.fn()),
|
||||
}));
|
||||
|
||||
vi.mock("node:fs", () => ({
|
||||
existsSync: vi.fn(() => true),
|
||||
}));
|
||||
@@ -12,10 +16,21 @@ vi.mock("node:fs/promises", () => ({
|
||||
}));
|
||||
|
||||
vi.mock("@hono/node-server/serve-static", () => ({
|
||||
serveStatic: vi.fn(() => vi.fn()),
|
||||
serveStatic: mocks.serveStatic,
|
||||
}));
|
||||
|
||||
type StaticOptions = {
|
||||
onFound?: (
|
||||
path: string,
|
||||
context: {
|
||||
req: { path: string };
|
||||
header: (name: string, value: string) => void;
|
||||
},
|
||||
) => void | Promise<void>;
|
||||
};
|
||||
|
||||
const { handleWebApp } = await import("./web");
|
||||
const staticOptions = mocks.serveStatic.mock.calls[0]?.[0] as StaticOptions | undefined;
|
||||
|
||||
describe("web app fallback classification", () => {
|
||||
beforeEach(() => {
|
||||
@@ -32,6 +47,47 @@ describe("web app fallback classification", () => {
|
||||
expect(await response.text()).toBe("<html>app</html>");
|
||||
});
|
||||
|
||||
it("injects canonical metadata and structured data into tracking-parameter root requests only", async () => {
|
||||
vi.mocked(fs.readFile).mockResolvedValue(`
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Reactive Resume — A free and open-source resume builder</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Reactive Resume is a free and open-source resume builder that simplifies the process of creating, updating, and sharing your resume."
|
||||
>
|
||||
</head>
|
||||
<body><div id="app"></div></body>
|
||||
</html>
|
||||
`);
|
||||
|
||||
const response = await handleWebApp(new Request("https://example.com/?utm_source=search"));
|
||||
const html = await response.text();
|
||||
|
||||
expect(html).toContain('<link rel="canonical" href="https://example.com/">');
|
||||
expect(html).toContain('<link rel="preload" href="/videos/timelapse-v1.webp" as="image" fetchpriority="high">');
|
||||
expect(html).toContain('<meta property="og:url" content="https://example.com/">');
|
||||
expect(html).toContain('<meta property="og:image" content="https://example.com/opengraph/banner.jpg">');
|
||||
expect(html).toContain('id="reactive-resume-structured-data"');
|
||||
expect(html).toContain('"@type":["SoftwareApplication","WebApplication"]');
|
||||
expect(html).not.toContain("utm_source");
|
||||
|
||||
const dashboardResponse = await handleWebApp(new Request("https://example.com/dashboard"));
|
||||
expect(await dashboardResponse.text()).not.toContain('rel="canonical"');
|
||||
});
|
||||
|
||||
it("caches versioned homepage media immutably", async () => {
|
||||
const headers = new Headers();
|
||||
|
||||
await staticOptions?.onFound?.("", {
|
||||
req: { path: "/videos/timelapse-v1.mp4" },
|
||||
header: (name, value) => headers.set(name, value),
|
||||
});
|
||||
|
||||
expect(headers.get("Cache-Control")).toBe("public, max-age=31536000, immutable");
|
||||
});
|
||||
|
||||
it.each(["/", "/alice/resume"])("sets framing and report-only CSP security headers on %s", async (pathname) => {
|
||||
const response = await handleWebApp(new Request(`https://example.com${pathname}`));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user