Files
menu/test/support/harness.ts
T
tanshu edea83228c Menu Set store, image pipeline and Site config
The store keeps a Menu Set's state in the directory layout (drafts/ versus
published/) and its metadata in a manifest, with publishing as a single
directory rename. Editing is allowed on Drafts only, so a published menu can
never change under a customer. Stages 2 and 3 of docs/plan.md, with tests.
2026-09-22 21:15:00 +05:30

67 lines
1.8 KiB
TypeScript

import { mkdir, mkdtemp } from 'node:fs/promises';
import path from 'node:path';
import { createHash } from 'node:crypto';
import { SetStore, type ImagePipeline } from '../../src/storage/sets.ts';
export const SECTIONS = ['bar', 'food'] as const;
/** Deterministic stand-in for sharp, so storage tests need no image work. */
export class FakePipeline implements ImagePipeline {
calls = 0;
async process(data: Buffer, _originalName: string) {
this.calls += 1;
const hash = createHash('sha256').update(data).digest('hex').slice(0, 8);
return {
sourceExt: 'jpg' as const,
hash,
width: 3000,
height: 2000,
original: data,
webp: Buffer.from(`webp:${hash}`),
jpeg: Buffer.from(`jpeg:${hash}`),
thumb: Buffer.from(`thumb:${hash}`),
};
}
}
export function testClock(start = '2026-01-01T00:00:00.000Z') {
let time = Date.parse(start);
return {
now: () => new Date(time),
advance: (ms: number) => {
time += ms;
},
set: (iso: string) => {
time = Date.parse(iso);
},
};
}
export async function tempDir(prefix: string): Promise<string> {
const base = path.join(process.cwd(), '.tmp');
await mkdir(base, { recursive: true });
return mkdtemp(path.join(base, `${prefix}-`));
}
export function makeStore(
dataDir: string,
options: { clock?: ReturnType<typeof testClock>; maxPagesPerSet?: number } = {},
) {
const pipeline = new FakePipeline();
const clock = options.clock ?? testClock();
const store = new SetStore({
dataDir,
pipeline,
sections: [...SECTIONS],
maxPagesPerSet: options.maxPagesPerSet ?? 40,
timeZone: 'Asia/Kolkata',
now: clock.now,
});
return { store, pipeline, clock };
}
export function pngBytes(label: string): Buffer {
return Buffer.from(`fake-image:${label}`);
}