flagon-io/g1t

public

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

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

108 lines5,227 bytesCodeBlame
1import 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 landingFor,
13 looksAutomated,
14 moreInvitesMailto,
15 remainingLine,
16 signUpCopy,
17 suggestUsername,
18 welcomeCookie,
19 clearWelcome,
20 welcomes,
21} from "./invites.ts";
22
23const CODE = "g1t-k7m2-q9xd-4hpw-abcd-0123-4567-89ef-ghjk";
24
25test("while invite-only, nobody is offered a plain sign-up", () => {
26 assert.deepEqual(signUpCopy(true), { primary: "Request access", secondary: "Have an invite?" });
27 assert.deepEqual(signUpCopy(false), { primary: "Sign up", secondary: null });
28 assert.equal(HAVE_AN_INVITE, "/register#invite");
29});
30
31test("asking for more invites goes to support with the [g1t Invites] subject", () => {
32 assert.equal(INVITES_CONTACT, CONTACT.support);
33 assert.equal(moreInvitesMailto(), "mailto:hey@flagon.io?subject=%5Bg1t%20Invites%5D%20More%20invites");
34 assert.equal(
35 moreInvitesMailto("acme"),
36 "mailto:hey@flagon.io?subject=%5Bg1t%20Invites%5D%20More%20invites%20for%20acme",
37 );
38});
39
40test("an invite link is on g1t.sh unless told otherwise", () => {
41 assert.equal(inviteLink(CODE), `https://g1t.sh/invite/${CODE}`);
42 assert.equal(inviteLink(CODE, "http://localhost:8787/"), `http://localhost:8787/invite/${CODE}`);
43});
44
45test("a pasted link or code is tidied to the code", () => {
46 assert.equal(cleanCode(CODE), CODE);
47 assert.equal(cleanCode(` ${CODE} `), CODE);
48 assert.equal(cleanCode(`https://g1t.sh/invite/${CODE}`), CODE);
49 assert.equal(cleanCode(`https://g1t.sh/register?invite=${CODE}&next=%2F`), CODE);
50 assert.equal(cleanCode("g1t-k7m2 q9xd"), "g1t-k7m2q9xd");
51 assert.equal(cleanCode(null), "");
52 assert.equal(cleanCode("x".repeat(500)).length, 80);
53});
54
55test("each invite says where it stands and whom it is for", () => {
56 const base = { redeemedBy: null, email: null, workspace: null };
57 assert.deepEqual(inviteState({ ...base, status: "pending" }), { label: "Pending", tone: "pending" });
58 assert.deepEqual(inviteState({ ...base, status: "redeemed", redeemedBy: "ada" }), { label: "Joined as @ada", tone: "done" });
59 assert.deepEqual(inviteState({ ...base, status: "expired" }), { label: "Expired", tone: "dead" });
60 assert.deepEqual(inviteState({ ...base, status: "revoked" }), { label: "Revoked", tone: "dead" });
61 assert.equal(inviteFor({ ...base, status: "pending" }), "Anyone with the link");
62 assert.equal(inviteFor({ ...base, status: "pending", email: "ada@example.com", workspace: "acme" }), "ada@example.com · joins acme");
63});
64
65test("what is left reads plainly", () => {
66 assert.equal(remainingLine({ limit: 5, used: 2, remaining: 3 }), "3 of 5 invites left");
67 assert.equal(remainingLine({ limit: 1, used: 0, remaining: 1 }), "1 of 1 invite left");
68 assert.equal(remainingLine({ limit: 5, used: 5, remaining: 0 }), "You have used all 5 of your invites");
69 assert.equal(remainingLine({ limit: null, used: 40, remaining: null }), "No limit on your invites");
70});
71
72test("bots that fill the hidden field or answer instantly are turned away", () => {
73 const form = (fields: Record<string, string>) => ({ get: (name: string) => fields[name] ?? null });
74 const now = 1_000_000;
75 assert.equal(looksAutomated(form({ website: "http://spam.example" }), now), true);
76 assert.equal(looksAutomated(form({ started: String(now - 200) }), now), true);
77 assert.equal(looksAutomated(form({ started: String(now - 10_000) }), now), false);
78 assert.equal(looksAutomated(form({}), now), false);
79 assert.equal(looksAutomated(form({ website: " " }), now), false);
80});
81
82test("a username is suggested from the invited address", () => {
83 assert.equal(suggestUsername("ada.lovelace@example.com"), "ada-lovelace");
84 assert.equal(suggestUsername("Margaret_Hamilton+g1t@example.com"), "margaret-hamilton");
85 assert.equal(suggestUsername("--x--@example.com"), "x");
86 assert.equal(suggestUsername(`${"a".repeat(38)}.b@example.com`), "a".repeat(38));
87 assert.equal(suggestUsername("...@example.com"), "");
88 assert.equal(suggestUsername(null), "");
89});
90
91test("an invite lands in its workspace, else its repository", () => {
92 assert.equal(landingFor({ workspace: { slug: "Flagon-IO" }, repository: null }), "flagon-io");
93 assert.equal(landingFor({ workspace: null, repository: { name: "flagon-io/g1t" } }), "flagon-io/g1t");
94 assert.equal(landingFor({ workspace: null, repository: null }), null);
95});
96
97test("the welcome is for one place, and ends", () => {
98 const set = welcomeCookie("flagon-io/g1t", true);
99 assert.match(set, /^g1t_welcome=flagon-io%2Fg1t; Path=\/; Max-Age=300; HttpOnly; SameSite=Lax; Secure$/);
100 const header = `a=1; ${set.split(";")[0]}; b=2`;
101 assert.equal(welcomes(header, "flagon-io/g1t"), true);
102 assert.equal(welcomes(header, "flagon-io"), false);
103 assert.equal(welcomes("g1t_welcome=flagon-io", "Flagon-IO"), true);
104 assert.equal(welcomes("g1t_welcome=%E0%A4%A", "flagon-io"), false);
105 assert.equal(welcomes("g1t_welcome=..%2F..%2Fx", "../../x"), false);
106 assert.equal(welcomes(null, "flagon-io"), false);
107 assert.match(clearWelcome(false), /^g1t_welcome=; Path=\/; Max-Age=0; HttpOnly; SameSite=Lax$/);
108});