evOo-local/apps/www/src/waitlist.test.ts
cynarAI 6c7eed7580 Initial clean evOo-local from f00577b
Fresh history cut from cynarAI/evoo antigravity-handoff/project-timeline
(Voice First + project timeline). Brand docs/titles as evOo; keep @rakazo/*
packages as tech debt. Excludes node_modules, caches, secrets, voice blobs.
2026-09-20 17:15:16 +02:00

111 lines
3.8 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import waitlistFunction from "../api/waitlist";
import {
captureWaitlistSignup,
normalizeWaitlistEmail,
parseWaitlistBody,
} from "./waitlist";
describe("waitlist", () => {
it("parses JSON and normalizes email addresses", () => {
expect(parseWaitlistBody('{"email":" Person@Example.COM "}')).toEqual({
email: " Person@Example.COM ",
});
expect(normalizeWaitlistEmail(" Person@Example.COM ")).toBe("person@example.com");
});
it("rejects malformed and oversized email addresses", () => {
expect(normalizeWaitlistEmail("person@example")).toBeNull();
expect(normalizeWaitlistEmail(`${"a".repeat(250)}@example.com`)).toBeNull();
expect(parseWaitlistBody({ email: "person@example.com", contactNote: 42 })).toBeNull();
});
it("captures a deduplicated person in the marketing analytics project", async () => {
const fetchImpl = vi.fn(async (..._args: Parameters<typeof fetch>) =>
new Response(null, { status: 200 }),
);
await expect(
captureWaitlistSignup(
"person@example.com",
{ PUBLIC_POSTHOG_KEY: "public-project-token" },
fetchImpl,
),
).resolves.toBe(true);
expect(fetchImpl).toHaveBeenCalledOnce();
const call = fetchImpl.mock.calls[0];
expect(call).toBeDefined();
const [url, init] = call!;
expect(String(url)).toBe("https://us.i.posthog.com/i/v0/e/");
expect(init?.signal).toBeInstanceOf(AbortSignal);
const payload = JSON.parse(String(init?.body));
expect(payload).toMatchObject({
api_key: "public-project-token",
event: "waitlist_joined",
properties: {
$process_person_profile: true,
$set: { email: "person@example.com", waitlist_status: "joined" },
$set_once: { waitlist_source: "evoo.com" },
},
});
expect(payload.distinct_id).toMatch(/^waitlist:[a-f0-9]{64}$/);
});
it("fails closed when the marketing project is not configured", async () => {
const fetchImpl = vi.fn();
await expect(captureWaitlistSignup("person@example.com", {}, fetchImpl)).resolves.toBe(false);
expect(fetchImpl).not.toHaveBeenCalled();
});
it("rejects an oversized body when content-length is missing", async () => {
const request = new Request("https://evoo.com/api/waitlist", {
method: "POST",
body: JSON.stringify({ email: `${"a".repeat(2_048)}@example.com` }),
headers: { "content-type": "application/json" },
});
const response = await waitlistFunction.fetch(request);
expect(response.status).toBe(400);
});
it.each(["declared", "streamed"] as const)(
"does not wait on a hanging body cancel for %s oversize",
async (kind) => {
let cancelStarted = false;
const body = new ReadableStream<Uint8Array>({
start(controller) {
controller.enqueue(new Uint8Array(2_049));
},
cancel() {
cancelStarted = true;
return new Promise(() => undefined);
},
});
const request = new Request("https://evoo.com/api/waitlist", {
method: "POST",
headers: kind === "declared" ? { "content-length": "2049" } : undefined,
body,
duplex: "half",
} as RequestInit & { duplex: "half" });
const response = await waitlistFunction.fetch(request);
expect(response.status).toBe(400);
expect(cancelStarted).toBe(true);
},
);
it("silently accepts submissions that fill the bot trap", async () => {
const request = new Request("https://evoo.com/api/waitlist", {
method: "POST",
body: JSON.stringify({ email: "person@example.com", contactNote: "filled by a bot" }),
headers: { "content-type": "application/json" },
});
const response = await waitlistFunction.fetch(request);
expect(response.status).toBe(200);
await expect(response.json()).resolves.toEqual({ ok: true });
});
});