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.
| One kind of access token; presence and status; usernames keep their case; the tour is a miniature of the real app; icons for password managers | 1 | import assert from "node:assert/strict"; |
| 2 | import { test } from "node:test"; | |
| 3 | ||
| 4 | import { decide } from "./prefs.ts"; | |
| 5 | import { | |
| 6 | MAX_STATUS_TEXT, | |
| 7 | NOTHING_KEPT, | |
| 8 | applyChange, | |
| 9 | cleanStatus, | |
| 10 | cleanWorkspaces, | |
| 11 | current, | |
| 12 | dndOn, | |
| 13 | entryOf, | |
| 14 | liveEntry, | |
| 15 | nextExpiry, | |
| 16 | presenceOf, | |
| 17 | readKept, | |
| 18 | sameEntry, | |
| 19 | } from "./presence.ts"; | |
| 20 | ||
| 21 | const NOW = 1_800_000_000_000; | |
| 22 | const iso = (ms: number) => new Date(ms).toISOString(); | |
| 23 | const MIN = 60_000; | |
| 24 | ||
| 25 | test("presence comes from the tabs: none is offline, all idle is away, one in use is active", () => { | |
| 26 | assert.equal(presenceOf([], false), "offline"); | |
| 27 | assert.equal(presenceOf([], true), "offline"); | |
| 28 | assert.equal(presenceOf([{ idle: true }, { idle: true }], false), "away"); | |
| 29 | assert.equal(presenceOf([{ idle: true }, { idle: false }], false), "active"); | |
| 30 | // Away by hand holds while tabs are in use. | |
| 31 | assert.equal(presenceOf([{ idle: false }], true), "away"); | |
| 32 | }); | |
| 33 | ||
| 34 | test("a status is an emoji and a few words, trimmed, and clears at a time in the future", () => { | |
| 35 | const status = cleanStatus({ emoji: " 🗓️ ", text: " In a meeting ", clear_at: iso(NOW + 30 * MIN) }, NOW)!; | |
| 36 | assert.equal(status.emoji, "🗓️"); | |
| 37 | assert.equal(status.text, "In a meeting"); | |
| 38 | assert.equal(status.clear_at, iso(NOW + 30 * MIN)); | |
| 39 | assert.equal(status.source, "manual"); | |
| 40 | assert.equal(status.set_at, iso(NOW)); | |
| 41 | assert.equal(cleanStatus({ text: "x".repeat(300) }, NOW)!.text.length, MAX_STATUS_TEXT); | |
| 42 | // Nothing said, or a time already past, is no status. | |
| 43 | assert.equal(cleanStatus({ emoji: "", text: " " }, NOW), null); | |
| 44 | assert.equal(cleanStatus({ text: "Lunch", clear_at: iso(NOW - MIN) }, NOW), null); | |
| 45 | assert.equal(cleanStatus({ text: "Lunch", clear_at: "soon" }, NOW), null); | |
| 46 | // Without a time it is kept until changed. | |
| 47 | assert.equal(cleanStatus({ text: "On vacation" }, NOW)!.clear_at, null); | |
| 48 | // An emoji alone is enough. | |
| 49 | assert.equal(cleanStatus({ emoji: "🌴", text: "" }, NOW)!.text, ""); | |
| 50 | }); | |
| 51 | ||
| 52 | test("a status and Do Not Disturb are gone once their time passes", () => { | |
| 53 | const kept = applyChange(NOTHING_KEPT, { status: { emoji: "🍔", text: "Lunch", clear_at: iso(NOW + 30 * MIN) }, dnd_until: iso(NOW + 60 * MIN) }, NOW); | |
| 54 | assert.ok(kept.status); | |
| 55 | assert.ok(dndOn(kept.dnd_until, NOW)); | |
| 56 | assert.equal(nextExpiry(kept, NOW), NOW + 30 * MIN); | |
| 57 | const later = current(kept, NOW + 45 * MIN); | |
| 58 | assert.equal(later.status, null); | |
| 59 | assert.equal(later.dnd_until, kept.dnd_until); | |
| 60 | assert.equal(nextExpiry(later, NOW + 45 * MIN), NOW + 60 * MIN); | |
| 61 | const after = current(kept, NOW + 61 * MIN); | |
| 62 | assert.equal(after.dnd_until, null); | |
| 63 | assert.equal(nextExpiry(after, NOW + 61 * MIN), null); | |
| 64 | }); | |
| 65 | ||
| 66 | test("Do Not Disturb resumes with null, and refuses a time in the past", () => { | |
| 67 | const on = applyChange(NOTHING_KEPT, { dnd_until: iso(NOW + MIN) }, NOW); | |
| 68 | assert.ok(dndOn(on.dnd_until, NOW)); | |
| 69 | assert.equal(applyChange(on, { dnd_until: null }, NOW).dnd_until, null); | |
| 70 | assert.equal(applyChange(NOTHING_KEPT, { dnd_until: iso(NOW - MIN) }, NOW).dnd_until, null); | |
| 71 | // A change that does not mention it leaves it. | |
| 72 | assert.equal(applyChange(on, { away: true }, NOW).dnd_until, on.dnd_until); | |
| 73 | }); | |
| 74 | ||
| 75 | test("a calendar never replaces a status set by hand, but replaces its own", () => { | |
| 76 | const byHand = applyChange(NOTHING_KEPT, { status: { emoji: "🤒", text: "Out sick" } }, NOW); | |
| 77 | const meeting = applyChange(byHand, { status: { emoji: "🗓️", text: "In a meeting", source: "calendar", clear_at: iso(NOW + 30 * MIN) } }, NOW); | |
| 78 | assert.equal(meeting.status?.text, "Out sick"); | |
| 79 | // Nor clears it. | |
| 80 | assert.equal(applyChange(byHand, { status: null }, NOW).status, null); | |
| 81 | assert.equal(applyChange(byHand, { status: { text: "", source: "calendar" } }, NOW).status?.text, "Out sick"); | |
| 82 | ||
| 83 | const fromCalendar = applyChange(NOTHING_KEPT, { status: { emoji: "🗓️", text: "In a meeting", source: "calendar", clear_at: iso(NOW + 30 * MIN) } }, NOW); | |
| 84 | assert.equal(fromCalendar.status?.source, "calendar"); | |
| 85 | const next = applyChange(fromCalendar, { status: { text: "Focusing", source: "integration" } }, NOW); | |
| 86 | assert.equal(next.status?.text, "Focusing"); | |
| 87 | // The person always can. | |
| 88 | assert.equal(applyChange(fromCalendar, { status: { text: "Commuting" } }, NOW).status?.source, "manual"); | |
| 89 | }); | |
| 90 | ||
| 91 | test("Do Not Disturb silences toasts and pushes; a test still shows", () => { | |
| 92 | const prefs = { level: "all" as const, workspaces: {} }; | |
| 93 | const notification = { kind: "dm" as const, workspace: "acme" }; | |
| 94 | assert.deepEqual(decide({ prefs, notification, tabs: [], subscriptions: 2, now: NOW, dnd: true }), { toast: false, push: false }); | |
| 95 | assert.deepEqual(decide({ prefs, notification, tabs: [], subscriptions: 2, now: NOW, dnd: true, test: true }), { toast: true, push: true }); | |
| 96 | assert.deepEqual(decide({ prefs, notification, tabs: [], subscriptions: 2, now: NOW }), { toast: true, push: true }); | |
| 97 | }); | |
| 98 | ||
| 99 | test("entries say how a person shows, and compare without their time", () => { | |
| 100 | const kept = applyChange(NOTHING_KEPT, { status: { emoji: "🎯", text: "Focusing", clear_at: iso(NOW + MIN) } }, NOW); | |
| 101 | const a = entryOf({ user_id: "usr_1", username: "ana" }, "active", kept, NOW); | |
| 102 | const b = entryOf({ user_id: "usr_1", username: "ana" }, "active", kept, NOW + 5); | |
| 103 | assert.ok(sameEntry(a, b)); | |
| 104 | assert.ok(!sameEntry(a, { ...b, presence: "away" })); | |
| 105 | assert.ok(!sameEntry(a, null)); | |
| 106 | // Read after its status ran out, a kept entry shows without it. | |
| 107 | assert.equal(liveEntry(a, NOW + 2 * MIN).status, null); | |
| 108 | assert.equal(liveEntry(a, NOW), a); | |
| 109 | }); | |
| 110 | ||
| 111 | test("what is kept reads back, and anything else reads as nothing", () => { | |
| 112 | const kept = applyChange(NOTHING_KEPT, { away: true, status: { text: "Commuting" } }, NOW); | |
| 113 | assert.deepEqual(readKept(JSON.stringify(kept)), kept); | |
| 114 | assert.deepEqual(readKept("not json"), NOTHING_KEPT); | |
| 115 | assert.deepEqual(readKept(null), NOTHING_KEPT); | |
| 116 | }); | |
| 117 | ||
| 118 | test("workspaces are slugs, lowercased and distinct", () => { | |
| 119 | assert.deepEqual(cleanWorkspaces(["Acme", "acme", " web-team ", "-bad", 3, "a".repeat(60)]), ["acme", "web-team"]); | |
| 120 | assert.deepEqual(cleanWorkspaces("acme"), []); | |
| 121 | }); |