import { describe, expect, it } from "vitest"; import { RULE_STAKEHOLDER_INVITE_LOGO_PATH, RULE_STAKEHOLDER_INVITER_FALLBACK, buildRuleStakeholderInviteMail, ruleStakeholderInviteCopyUrl, stakeholderInviteInviterLabel, stakeholderInviteReplyTo, } from "../../lib/server/ruleStakeholderInviteMail"; const VERIFY_URL = "https://communityrule.info/api/invites/rule-stakeholder/verify?token=abc"; describe("stakeholder invite reply address", () => { it("uses a mailbox as Reply-To and keeps a missing address out of the header", () => { expect(stakeholderInviteReplyTo(" Maya@Example.org ")).toBe( "maya@example.org", ); expect(stakeholderInviteReplyTo(RULE_STAKEHOLDER_INVITER_FALLBACK)).toBe( undefined, ); expect(stakeholderInviteReplyTo("CommunityRule")).toBe(undefined); }); it("names a missing inviter without turning the label into an address", () => { expect(stakeholderInviteInviterLabel("")).toBe( RULE_STAKEHOLDER_INVITER_FALLBACK, ); expect(stakeholderInviteInviterLabel("Maya@Example.org")).toBe( "maya@example.org", ); const mail = buildRuleStakeholderInviteMail({ to: "rosa@example.org", verifyUrl: VERIFY_URL, origin: "https://communityrule.info", communityName: "Juniper Street Food Share", inviterEmail: RULE_STAKEHOLDER_INVITER_FALLBACK, }); expect(mail.text).toContain( `${RULE_STAKEHOLDER_INVITER_FALLBACK} sent the invitation.`, ); }); }); describe("ruleStakeholderInviteCopyUrl", () => { it("adds copy=1 to the invitation link", () => { expect(ruleStakeholderInviteCopyUrl(VERIFY_URL)).toBe( `${VERIFY_URL}©=1`, ); }); }); describe("buildRuleStakeholderInviteMail", () => { const mail = buildRuleStakeholderInviteMail({ to: "rosa@example.org", verifyUrl: VERIFY_URL, origin: "https://communityrule.info", communityName: "Juniper Street Food Share", inviterEmail: "maya@example.org", summary: "A food share that runs every Sunday on Juniper Street. Volunteers collect surplus from two grocers and a farm stand and share it with neighbors.", document: { sections: [ { categoryName: "Values", entries: [ { title: "Care", body: "We care." }, { title: "Share", body: "We share." }, { title: "Listen", body: "We listen." }, ], }, { categoryName: "Communication", entries: Array.from({ length: 6 }, (_, i) => ({ title: `Card ${i + 1}`, body: "Body", })), }, ], }, }); it("uses the launch subject, preview, and privacy line", () => { expect(mail.subject).toBe( "Juniper Street Food Share invited you to read their Rule", ); expect(mail.previewText).toBe( "It covers how they talk, who belongs, how they decide and what happens when they disagree.", ); expect(mail.text).toContain( "Every Rule starts private. Only the people Juniper Street Food Share invites can read it until the person who holds the pen turns on a link. A Rule is public and featured only when a community asks us in writing.", ); expect(mail.html).toContain("Every Rule starts private."); }); it("names the inviter by email and points replies at that address in copy", () => { expect(mail.text).toContain("maya@example.org sent the invitation."); expect(mail.text).toContain( "how they talk, who belongs, how they decide and what happens when they disagree.", ); expect(mail.html).not.toContain("Maya Ortiz"); }); it("includes read and copy links, footer, and the 2x mark", () => { expect(mail.text).toContain(VERIFY_URL); expect(mail.text).toContain(`${VERIFY_URL}©=1`); expect(mail.html).toContain(`href="${VERIFY_URL}"`); expect(mail.html).toContain(`href="${VERIFY_URL}&copy=1"`); expect(mail.html).toContain("Read the Rule"); expect(mail.html).toContain("Make a copy"); expect(mail.html).toContain("3 VALUES AND 6 CARDS"); expect(mail.html).toContain("JS"); expect(mail.html).toContain("#e4e4e4"); expect(mail.html).toContain("font-size:14px;line-height:20px;color:#464646"); expect(mail.html).toContain( `https://communityrule.info${RULE_STAKEHOLDER_INVITE_LOGO_PATH}`, ); expect(mail.html).toContain("https://communityrule.info/privacy"); expect(mail.html).toContain("https://communityrule.info/about"); expect(mail.text).toContain( "Juniper Street Food Share’s Rule on CommunityRule", ); }); });