| 1 | import assert from "node:assert/strict"; |
| 2 | import { test } from "node:test"; |
| 3 | |
| 4 | import { |
| 5 | accountWentSummary, |
| 6 | confirmsUsername, |
| 7 | deletedWithAccount, |
| 8 | soleOwnerNote, |
| 9 | soleWorkspacesRefusal, |
| 10 | staffDeleteProblem, |
| 11 | staffDeletionRefusal, |
| 12 | } from "./deleted-accounts.ts"; |
| 13 | |
| 14 | const deletion = { |
| 15 | username: "ada", |
| 16 | workspaces: 2, |
| 17 | tokens: 1, |
| 18 | ssh_keys: 0, |
| 19 | applications: 0, |
| 20 | repositories: 0, |
| 21 | sole_owner_of: [], |
| 22 | protected: false, |
| 23 | }; |
| 24 | |
| 25 | const sole = (slug: string) => ({ slug, name: slug, members: 1, billing: null, protected: false }); |
| 26 | |
| 27 | const went = { workspaces: 2, teams: 1, repositories: 3, tokens: 1, sshKeys: 2, staff: null, reason: null, deletedWorkspaces: [] }; |
| 28 | |
| 29 | test("what went reads as one line", () => { |
| 30 | assert.equal(accountWentSummary(went), "2 workspaces, 1 team, 3 repositories, 1 token, 2 SSH keys"); |
| 31 | }); |
| 32 | |
| 33 | test("only a protected account is refused outright", () => { |
| 34 | assert.equal(staffDeletionRefusal(deletion), null); |
| 35 | const owner = { ...deletion, sole_owner_of: [sole("acme")] }; |
| 36 | assert.equal(staffDeletionRefusal(owner), null); |
| 37 | assert.equal( |
| 38 | staffDeletionRefusal({ ...owner, username: "g1t", protected: true }), |
| 39 | "g1t is protected and can never be deleted.", |
| 40 | ); |
| 41 | }); |
| 42 | |
| 43 | test("workspaces it owns alone go with it, said up front", () => { |
| 44 | assert.equal(soleOwnerNote(deletion), null); |
| 45 | assert.match(soleOwnerNote({ ...deletion, sole_owner_of: [sole("ada")] })!, /^ada is the only owner of 1 workspace\. Deleting the account deletes it first/); |
| 46 | assert.match(soleOwnerNote({ ...deletion, sole_owner_of: [sole("a"), sole("b")] })!, /of 2 workspaces\. Deleting the account deletes them first/); |
| 47 | assert.equal(soleWorkspacesRefusal({ ...deletion, sole_owner_of: [sole("ada")] }), null); |
| 48 | }); |
| 49 | |
| 50 | test("a protected workspace or billing that cannot settle stops it, naming which", () => { |
| 51 | const owner = { |
| 52 | ...deletion, |
| 53 | sole_owner_of: [ |
| 54 | sole("ada"), |
| 55 | { ...sole("flagon-io"), protected: true }, |
| 56 | { ...sole("ada-labs"), billing: "ada-labs has an unpaid invoice. Pay it from the workspace's Billing page first." }, |
| 57 | ], |
| 58 | }; |
| 59 | assert.equal( |
| 60 | soleWorkspacesRefusal(owner), |
| 61 | "ada cannot be deleted with its workspaces yet. flagon-io is protected and can never be deleted. ada-labs has an unpaid invoice. Pay it from the workspace's Billing page first.", |
| 62 | ); |
| 63 | }); |
| 64 | |
| 65 | test("staff confirm with the username", () => { |
| 66 | assert.ok(confirmsUsername("ada", " ADA ")); |
| 67 | assert.ok(!confirmsUsername("ada", "")); |
| 68 | assert.ok(!confirmsUsername("ada", "grace")); |
| 69 | }); |
| 70 | |
| 71 | test("the form needs a reason, the username, and the box ticked when workspaces go too", () => { |
| 72 | const form = { username: "ada", reason: "Retired test account", confirm: "ada", withWorkspaces: false, acknowledged: false }; |
| 73 | assert.equal(staffDeleteProblem(form), null); |
| 74 | assert.equal(staffDeleteProblem({ ...form, reason: "" }), "Say why the account is being deleted."); |
| 75 | assert.equal(staffDeleteProblem({ ...form, confirm: "grace" }), "Type ada to confirm."); |
| 76 | assert.equal( |
| 77 | staffDeleteProblem({ ...form, withWorkspaces: true }), |
| 78 | "Tick the box to say the workspaces it alone owns are deleted too.", |
| 79 | ); |
| 80 | assert.equal(staffDeleteProblem({ ...form, withWorkspaces: true, acknowledged: true }), null); |
| 81 | }); |
| 82 | |
| 83 | test("workspaces deleted with the account are matched to their deletions", () => { |
| 84 | const waiting = { |
| 85 | workspaceId: "wsp_1", |
| 86 | slug: "ada", |
| 87 | name: "Ada", |
| 88 | deletedAt: "2026-10-08T00:00:00.000Z", |
| 89 | deletedBy: "staff@g1t.sh", |
| 90 | purgeAfter: "2026-11-07T00:00:00.000Z", |
| 91 | went: { repositories: 1, projects: 0, members: 1, billing: null, protected: false }, |
| 92 | restorable: true, |
| 93 | }; |
| 94 | const gone = deletedWithAccount( |
| 95 | { ...went, deletedWorkspaces: [{ workspaceId: "wsp_1", slug: "ada" }, { workspaceId: "wsp_2", slug: "ada-labs" }] }, |
| 96 | [waiting], |
| 97 | ); |
| 98 | assert.deepEqual(gone, [ |
| 99 | { workspaceId: "wsp_1", slug: "ada", deleted: waiting }, |
| 100 | { workspaceId: "wsp_2", slug: "ada-labs", deleted: null }, |
| 101 | ]); |
| 102 | assert.deepEqual(deletedWithAccount(went, [waiting]), []); |
| 103 | }); |