Files
community-rule/tests/unit/workshopSignup.test.ts
T
adilalloandCursor c0ba3a3798 Add the Workshops page and keep each sign-up on the site.
The form is built once to the settled field set, and a valid send is saved before anyone is emailed.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-03 19:56:49 -07:00

102 lines
3.8 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { buildWorkshopConfirmationMail, buildWorkshopInboxMail } from "../../lib/workshopSignupMail";
import {
EMPTY_WORKSHOP_FORM_VALUES,
suggestWorkshopRoute,
type WorkshopFormValues,
} from "../../lib/workshopSignup";
import { parseWorkshopSignupPayload } from "../../lib/server/validation/workshopSignupSchemas";
const values: WorkshopFormValues = {
...EMPTY_WORKSHOP_FORM_VALUES,
challenges: ["big-change"],
organizationName: "Northside Credit Union",
organizationKind: "credit-union",
memberCount: "1000-10000",
contactName: "Ada Lovelace",
email: "ada@example.com",
sourcePage: "/workshops",
sourceUrl: "https://communityrule.com/workshops",
};
describe("suggestWorkshopRoute", () => {
it("sends volunteer-run groups to the kit", () => {
expect(
suggestWorkshopRoute({ organizationKind: "volunteer", memberCount: "10000-100000" }),
).toEqual({
largeOrganization: false,
note: "Volunteer-run group: send the kit and office hours.",
});
});
it("flags 1,000 or more members as a large organization and names no price", () => {
const route = suggestWorkshopRoute({
organizationKind: "credit-union",
memberCount: "1000-10000",
});
expect(route.largeOrganization).toBe(true);
expect(route.note).toBe("Large organization: call with the facilitator lead.");
expect(route.note.toLowerCase()).not.toMatch(/price|fee|\$|£|€/);
});
it("sends smaller leagues to a partnership call", () => {
expect(
suggestWorkshopRoute({ organizationKind: "league", memberCount: "under-1000" }).note,
).toBe("League, association or co-op developer: partnership call.");
});
it("sends everyone else the one-page brief", () => {
expect(
suggestWorkshopRoute({ organizationKind: "housing-coop", memberCount: "not-sure" }).note,
).toBe("Send the one-page brief, then offer a call.");
});
});
describe("workshop signup mail", () => {
it("keeps a price out of the inbox note and the confirmation", () => {
const inbox = buildWorkshopInboxMail({
values,
routeNote: "Large organization: call with the facilitator lead.",
largeOrganization: true,
requestId: "req-1",
schedulingUrl: "https://calendar.example/workshop",
});
const confirmation = buildWorkshopConfirmationMail({
largeOrganization: true,
schedulingUrl: "https://calendar.example/workshop",
});
const combined = `${inbox.text}\n${confirmation.text}`.toLowerCase();
expect(combined).not.toMatch(/price|fee|\$|£|€/);
expect(confirmation.text).toContain("two working days");
expect(confirmation.text).toContain("Choose a time");
expect(inbox.text).toContain("Northside Credit Union");
expect(inbox.text).toContain("https://communityrule.com/workshops");
});
});
describe("parseWorkshopSignupPayload", () => {
it("keeps answers and reports each missing required field", () => {
const parsed = parseWorkshopSignupPayload({
unspokenQuestion: "How do we grow?",
organizationName: "Northside",
email: "not-an-email",
});
expect(parsed.values.unspokenQuestion).toBe("How do we grow?");
expect(parsed.values.organizationName).toBe("Northside");
expect(parsed.fieldErrors.challenges).toBe("required");
expect(parsed.fieldErrors.organizationKind).toBe("required");
expect(parsed.fieldErrors.memberCount).toBe("required");
expect(parsed.fieldErrors.contactName).toBe("required");
expect(parsed.fieldErrors.email).toBe("invalid");
});
it("accepts the full field set", () => {
const parsed = parseWorkshopSignupPayload({
...values,
startedAt: Date.now() - 10_000,
});
expect(parsed.fieldErrors).toEqual({});
expect(parsed.values.email).toBe("ada@example.com");
});
});