/** * Shared seed helpers so specs don't each hand-roll the upload/comment create * flow. Centralising the API contract (routes, field names, expected statuses) * means an API change is a one-file edit, not a 7-file hunt. */ import { readFileSync } from 'node:fs'; import { join } from 'node:path'; import { uploadRaw } from './upload-client'; import { db } from '../fixtures/db'; const BASE = process.env.E2E_FRONTEND_URL ?? 'http://localhost:3101'; // A real, decodable JPEG. Magic-bytes-only fakes now get auto-cleaned by the // backend when compression fails (a failed transcode refunds quota + deletes the // row), which would delete the seeded upload out from under the test. Read lazily // at call time (cwd is the e2e dir at runtime, like the gallery-path spec) so test // collection can't trip on a module-load read. let sampleJpg: Buffer | null = null; function sampleImage(): Buffer { if (!sampleJpg) { sampleJpg = readFileSync(join(process.cwd(), 'fixtures', 'media', 'sample.jpg')); } return sampleJpg; } export type SeedUploadOptions = { caption?: string; /** Mark compression done so the card is fully rendered in the feed. Default true. */ visible?: boolean; }; /** Seed a real, accepted upload owned by `jwt` and return its id. */ export async function seedUpload(jwt: string, opts: SeedUploadOptions = {}): Promise { const res = await uploadRaw(jwt, sampleImage(), { filename: 'a.jpg', contentType: 'image/jpeg', caption: opts.caption, }); if (res.status !== 201) throw new Error(`seedUpload failed: ${res.status} ${await res.text()}`); const { id } = await res.json(); if (opts.visible !== false) await db.setUploadCompressionStatus(id, 'done'); return id; } /** Seed a comment on `uploadId` authored by `jwt`; return its id. */ export async function seedComment(jwt: string, uploadId: string, body: string): Promise { const res = await fetch(`${BASE}/api/v1/upload/${uploadId}/comments`, { method: 'POST', headers: { Authorization: `Bearer ${jwt}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ body }), }); if (res.status !== 201) throw new Error(`seedComment failed: ${res.status} ${await res.text()}`); return (await res.json()).id; } /** Read the comments for an upload as `jwt`. */ export async function listComments(jwt: string, uploadId: string): Promise { const res = await fetch(`${BASE}/api/v1/upload/${uploadId}/comments`, { headers: { Authorization: `Bearer ${jwt}` }, }); return res.json(); } /** Resolve a single upload row from a feed response whose envelope shape isn't pinned. */ export function findFeedRow(feed: any, id: string): any { const list: any[] = feed.uploads ?? feed.items ?? feed; return Array.isArray(list) ? list.find((u: any) => u.id === id) : undefined; }