trails/apps/journal/app/routes/api.e2e.seed.ts
Ullrich Schäfer 861701e881
Show POI details (phone, website, opening hours) on Journal route detail page
Waypoints snapped to OSM POIs in the Planner now carry their metadata all
the way through to the Journal:

- Extend Waypoint type with osmId and poiTags fields
- Extract osmId/poiTags from Yjs Y.Map in ExportButton and SaveToJournalButton
- Encode POI metadata as <trails:poi> extensions in GPX <wpt> elements
- Parse <trails:poi> extensions back in the GPX parser
- Display phone, website, opening hours, address on Journal route detail
- E2E test for the full roundtrip; seed endpoint now defaults to public visibility

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:32:38 +02:00

77 lines
2.3 KiB
TypeScript

import { randomUUID } from "node:crypto";
import { data } from "react-router";
import { eq } from "drizzle-orm";
import { getDb } from "~/lib/db";
import { users, routes } from "@trails-cool/db/schema/journal";
import { createRouteToken } from "~/lib/jwt.server";
import { TERMS_VERSION } from "~/lib/legal";
// Only available when the server is started with E2E=true.
// Never enabled in production.
function assertE2EEnabled() {
if (process.env.E2E !== "true") {
throw new Response("Not found", { status: 404 });
}
}
const E2E_USER_USERNAME = "e2e-test-user";
const E2E_USER_EMAIL = "e2e@localhost";
/**
* POST /api/e2e/seed
*
* Idempotently creates the e2e test user and a bare route (no GPX, no geom),
* then returns a callback-scoped JWT for that route. Used by e2e tests that
* need to hit the Planner callback endpoint without going through the browser
* auth flow.
*
* Body: none required. Optionally pass { routeName } to label the route.
*/
export async function action({ request }: { request: Request }) {
assertE2EEnabled();
if (request.method !== "POST") {
return data({ error: "Method not allowed" }, { status: 405 });
}
const db = getDb();
// Upsert the e2e test user
await db
.insert(users)
.values({
id: randomUUID(),
username: E2E_USER_USERNAME,
email: E2E_USER_EMAIL,
displayName: "E2E Test User",
domain: "localhost",
termsAcceptedAt: new Date(),
termsVersion: TERMS_VERSION,
})
.onConflictDoNothing({ target: users.username });
const [user] = await db
.select({ id: users.id })
.from(users)
.where(eq(users.username, E2E_USER_USERNAME));
if (!user) throw new Error("e2e seed: failed to upsert test user");
const body = request.headers.get("content-type")?.includes("application/json")
? await request.json().catch(() => ({}))
: {};
const routeName = (body as { routeName?: string }).routeName ?? "E2E callback test route";
const visibility = (body as { visibility?: string }).visibility ?? "public";
const routeId = randomUUID();
await db.insert(routes).values({
id: routeId,
ownerId: user.id,
name: routeName,
description: "",
visibility: visibility as "public" | "unlisted" | "private",
});
const token = await createRouteToken(routeId);
return data({ routeId, token, ownerId: user.id });
}