feat: add race cover image extraction
Some checks failed
CI / build-and-test (pull_request) Has been cancelled
Some checks failed
CI / build-and-test (pull_request) Has been cancelled
This commit is contained in:
@@ -2,6 +2,7 @@ import assert from "node:assert/strict";
|
||||
import { test } from "node:test";
|
||||
import request from "supertest";
|
||||
import { createApp } from "../src/app";
|
||||
import { extractRaceCoverImageFromHtml } from "../src/raceCoverImage";
|
||||
|
||||
const app = createApp();
|
||||
|
||||
@@ -45,3 +46,124 @@ test("GET /api/races/:id returns not_found", async () => {
|
||||
assert.equal(res.body.error, "not_found");
|
||||
assert.ok(Array.isArray(res.body.details));
|
||||
});
|
||||
|
||||
test("extractRaceCoverImageFromHtml prefers runc.run intro image", () => {
|
||||
const html = `
|
||||
<meta property="og:image" content="https://example.com/og.jpg">
|
||||
<div class="run-intro__image">
|
||||
<div class="run-intro__image-left-shadow"></div>
|
||||
<img src="/uploads/race_landing_header_backgrounds/header.jpg" alt="">
|
||||
<div class="run-intro__image-right-shadow"></div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
assert.equal(
|
||||
extractRaceCoverImageFromHtml(html, "https://aprilrun5km.runc.run/"),
|
||||
"https://aprilrun5km.runc.run/uploads/race_landing_header_backgrounds/header.jpg",
|
||||
);
|
||||
});
|
||||
|
||||
test("extractRaceCoverImageFromHtml reads Open Graph and Twitter images", () => {
|
||||
assert.equal(
|
||||
extractRaceCoverImageFromHtml(
|
||||
'<meta property="og:image" content="/cover.png">',
|
||||
"https://example.com/race",
|
||||
),
|
||||
"https://example.com/cover.png",
|
||||
);
|
||||
assert.equal(
|
||||
extractRaceCoverImageFromHtml(
|
||||
'<meta name="twitter:image" content="https://cdn.example.com/twitter.jpg">',
|
||||
"https://example.com/race",
|
||||
),
|
||||
"https://cdn.example.com/twitter.jpg",
|
||||
);
|
||||
});
|
||||
|
||||
test("POST /api/races stores manual coverImageUrl", async () => {
|
||||
const coverImageUrl = "https://example.com/manual.jpg";
|
||||
const res = await request(app)
|
||||
.post("/api/races")
|
||||
.send({
|
||||
id: "2026-06-01-manual-cover",
|
||||
date: "2026-06-01",
|
||||
title: "Manual Cover",
|
||||
distanceKm: 10,
|
||||
officialUrl: "https://example.com/race",
|
||||
coverImageUrl,
|
||||
})
|
||||
.expect(201);
|
||||
|
||||
assert.equal(res.body.coverImageUrl, coverImageUrl);
|
||||
});
|
||||
|
||||
test("POST /api/races auto extracts coverImageUrl from officialUrl", async () => {
|
||||
const originalFetch = globalThis.fetch;
|
||||
globalThis.fetch = async () =>
|
||||
new Response('<meta property="og:image" content="/auto.jpg">', {
|
||||
status: 200,
|
||||
headers: { "content-type": "text/html" },
|
||||
});
|
||||
|
||||
try {
|
||||
const res = await request(app)
|
||||
.post("/api/races")
|
||||
.send({
|
||||
id: "2026-06-02-auto-cover",
|
||||
date: "2026-06-02",
|
||||
title: "Auto Cover",
|
||||
distanceKm: 21.1,
|
||||
officialUrl: "https://example.com/race",
|
||||
})
|
||||
.expect(201);
|
||||
|
||||
assert.equal(res.body.coverImageUrl, "https://example.com/auto.jpg");
|
||||
} finally {
|
||||
globalThis.fetch = originalFetch;
|
||||
}
|
||||
});
|
||||
|
||||
test("POST /api/races succeeds when cover extraction fails", async () => {
|
||||
const originalFetch = globalThis.fetch;
|
||||
globalThis.fetch = async () => {
|
||||
throw new Error("network down");
|
||||
};
|
||||
|
||||
try {
|
||||
const res = await request(app)
|
||||
.post("/api/races")
|
||||
.send({
|
||||
id: "2026-06-03-cover-fail",
|
||||
date: "2026-06-03",
|
||||
title: "Cover Fail",
|
||||
distanceKm: 5,
|
||||
officialUrl: "https://example.com/race",
|
||||
})
|
||||
.expect(201);
|
||||
|
||||
assert.equal(res.body.coverImageUrl, null);
|
||||
} finally {
|
||||
globalThis.fetch = originalFetch;
|
||||
}
|
||||
});
|
||||
|
||||
test("PATCH /api/races/:id updates coverImageUrl explicitly", async () => {
|
||||
const id = "2026-06-04-patch-cover";
|
||||
await request(app)
|
||||
.post("/api/races")
|
||||
.send({
|
||||
id,
|
||||
date: "2026-06-04",
|
||||
title: "Patch Cover",
|
||||
distanceKm: 10,
|
||||
})
|
||||
.expect(201);
|
||||
|
||||
const coverImageUrl = "https://example.com/patched.jpg";
|
||||
const res = await request(app)
|
||||
.patch(`/api/races/${id}`)
|
||||
.send({ coverImageUrl })
|
||||
.expect(200);
|
||||
|
||||
assert.equal(res.body.coverImageUrl, coverImageUrl);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user