Repository Public
1import { readFileSync, readdirSync } from "node:fs";2import path from "node:path";3import { sql } from "@/lib/db";4import { submitRequest, type SubmitInput } from "@/lib/services/booking";5import { randomUUID } from "node:crypto";67export const TZ = "America/Toronto";8export const ms = (iso: string) => Temporal.Instant.from(iso).epochMilliseconds;9/** Clock used by the services (env.nowMs). */10export const setNow = (iso: string) => { process.env.SPCAL_FAKE_NOW = iso; };1112export async function resetDb(): Promise<{ userId: string }> {13 // Schema once per database (dropping it would change type OIDs under the pooled connections), then empty tables.14 const [{ exists }] = await sql<{ exists: boolean }[]>`SELECT to_regclass('public.users') IS NOT NULL AS exists`;15 if (!exists) {16 const dir = path.join(process.cwd(), "db/migrations");17 for (const f of readdirSync(dir).filter((x) => x.endsWith(".sql")).sort()) await sql.unsafe(readFileSync(path.join(dir, f), "utf8"));18 }19 const tables = await sql<{ tablename: string }[]>`SELECT tablename FROM pg_tables WHERE schemaname = 'public'`;20 await sql.unsafe(`TRUNCATE ${tables.map((t) => `"${t.tablename}"`).join(", ")} RESTART IDENTITY CASCADE`);21 const [u] = await sql<{ id: string }[]>`INSERT INTO users (email, display_name) VALUES ('owner@example.test', 'Owner Test') RETURNING id`;22 await sql`INSERT INTO settings (user_id, public_name, notify_email) VALUES (${u.id}, 'Owner Test', 'owner@example.test')`;23 return { userId: u.id };24}2526export async function addRules(userId: string, weekdays: number[], startMinute: number, endMinute: number, eventTypeId: string | null = null) {27 for (const weekday of weekdays) await sql`INSERT INTO availability_rules (user_id, event_type_id, weekday, start_minute, end_minute) VALUES (${userId}, ${eventTypeId}, ${weekday}, ${startMinute}, ${endMinute})`;28}2930export async function addType(userId: string, over: Record<string, unknown> = {}): Promise<string> {31 const v = { slug: "meet", title: "Rencontre", duration_min: 30, slot_step_min: 30, min_notice_min: 0, horizon_days: 365, require_reason: false, ...over };32 const [t] = await sql<{ id: string }[]>`INSERT INTO event_types ${sql({ user_id: userId, ...v } as never)} RETURNING id`;33 return t.id;34}3536let n = 0;37export function visitor(over: Partial<SubmitInput> = {}): SubmitInput {38 n++;39 return { slug: "meet", startMs: 0, name: `Visitor ${n}`, email: `visitor${n}@example.test`, visitorTz: TZ, locale: "fr", idempotencyKey: randomUUID(), ...over };40}41export const submit = (over: Partial<SubmitInput>) => submitRequest(visitor(over));4243export const code = async (p: Promise<unknown>): Promise<string> => p.then(() => "ok", (e) => (e as { code?: string }).code ?? String(e));44