125 lines
4.5 KiB
TypeScript
125 lines
4.5 KiB
TypeScript
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",
|
||
);
|
||
});
|
||
});
|