pr_01m47d15m3e54sn21z27rpy5n9/apps/web/app/lib/invites.test.ts

75 lines3,575 bytesCodeBlame

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import { CONTACT } from "./legal.ts";
5import {
6 HAVE_AN_INVITE,
7 INVITES_CONTACT,
8 cleanCode,
9 inviteFor,
10 inviteLink,
11 inviteState,
12 looksAutomated,
13 moreInvitesMailto,
14 remainingLine,
15 signUpCopy,
16} from "./invites.ts";
17
18const CODE = "g1t-k7m2-q9xd-4hpw-abcd-0123-4567-89ef-ghjk";
19
20test("while invite-only, nobody is offered a plain sign-up", () => {
21 assert.deepEqual(signUpCopy(true), { primary: "Request access", secondary: "Have an invite?" });
22 assert.deepEqual(signUpCopy(false), { primary: "Sign up", secondary: null });
23 assert.equal(HAVE_AN_INVITE, "/register#invite");
24});
25
26test("asking for more invites goes to support with the [g1t Invites] subject", () => {
27 assert.equal(INVITES_CONTACT, CONTACT.support);
28 assert.equal(moreInvitesMailto(), "mailto:hey@flagon.io?subject=%5Bg1t%20Invites%5D%20More%20invites");
29 assert.equal(
30 moreInvitesMailto("acme"),
31 "mailto:hey@flagon.io?subject=%5Bg1t%20Invites%5D%20More%20invites%20for%20acme",
32 );
33});
34
35test("an invite link is on g1t.sh unless told otherwise", () => {
36 assert.equal(inviteLink(CODE), `https://g1t.sh/invite/${CODE}`);
37 assert.equal(inviteLink(CODE, "http://localhost:8787/"), `http://localhost:8787/invite/${CODE}`);
38});
39
40test("a pasted link or code is tidied to the code", () => {
41 assert.equal(cleanCode(CODE), CODE);
42 assert.equal(cleanCode(` ${CODE} `), CODE);
43 assert.equal(cleanCode(`https://g1t.sh/invite/${CODE}`), CODE);
44 assert.equal(cleanCode(`https://g1t.sh/register?invite=${CODE}&next=%2F`), CODE);
45 assert.equal(cleanCode("g1t-k7m2 q9xd"), "g1t-k7m2q9xd");
46 assert.equal(cleanCode(null), "");
47 assert.equal(cleanCode("x".repeat(500)).length, 80);
48});
49
50test("each invite says where it stands and whom it is for", () => {
51 const base = { redeemedBy: null, email: null, workspace: null };
52 assert.deepEqual(inviteState({ ...base, status: "pending" }), { label: "Pending", tone: "pending" });
53 assert.deepEqual(inviteState({ ...base, status: "redeemed", redeemedBy: "ada" }), { label: "Joined as @ada", tone: "done" });
54 assert.deepEqual(inviteState({ ...base, status: "expired" }), { label: "Expired", tone: "dead" });
55 assert.deepEqual(inviteState({ ...base, status: "revoked" }), { label: "Revoked", tone: "dead" });
56 assert.equal(inviteFor({ ...base, status: "pending" }), "Anyone with the link");
57 assert.equal(inviteFor({ ...base, status: "pending", email: "ada@example.com", workspace: "acme" }), "ada@example.com · joins acme");
58});
59
60test("what is left reads plainly", () => {
61 assert.equal(remainingLine({ limit: 5, used: 2, remaining: 3 }), "3 of 5 invites left");
62 assert.equal(remainingLine({ limit: 1, used: 0, remaining: 1 }), "1 of 1 invite left");
63 assert.equal(remainingLine({ limit: 5, used: 5, remaining: 0 }), "You have used all 5 of your invites");
64 assert.equal(remainingLine({ limit: null, used: 40, remaining: null }), "No limit on your invites");
65});
66
67test("bots that fill the hidden field or answer instantly are turned away", () => {
68 const form = (fields: Record<string, string>) => ({ get: (name: string) => fields[name] ?? null });
69 const now = 1_000_000;
70 assert.equal(looksAutomated(form({ website: "http://spam.example" }), now), true);
71 assert.equal(looksAutomated(form({ started: String(now - 200) }), now), true);
72 assert.equal(looksAutomated(form({ started: String(now - 10_000) }), now), false);
73 assert.equal(looksAutomated(form({}), now), false);
74 assert.equal(looksAutomated(form({ website: " " }), now), false);
75});