| 1 | import { test } from "node:test"; |
| 2 | import assert from "node:assert/strict"; |
| 3 | |
| 4 | import { dmTitle, isUnread, sidebarOrder, tally } from "./unread.ts"; |
| 5 | |
| 6 | test("unread is what others wrote after your last read", () => { |
| 7 | assert.equal(isUnread({ id: "msg_2", author: "user:b" }, "user:a", "msg_1"), true); |
| 8 | assert.equal(isUnread({ id: "msg_1", author: "user:b" }, "user:a", "msg_1"), false); |
| 9 | assert.equal(isUnread({ id: "msg_2", author: "user:a" }, "user:a", "msg_1"), false); |
| 10 | assert.equal(isUnread({ id: "msg_0", author: "agent:x" }, "user:a", null), true); |
| 11 | }); |
| 12 | |
| 13 | test("counts per channel, replies included, with mentions of the viewer", () => { |
| 14 | const rows = [ |
| 15 | { channel_id: "c1", id: "m1", author: "user:b", mentions: "" }, |
| 16 | { channel_id: "c1", id: "m2", author: "agent:x", mentions: " syntaqx " }, |
| 17 | { channel_id: "c1", id: "m3", author: "user:a", mentions: " syntaqx " }, |
| 18 | { channel_id: "c2", id: "m4", author: "user:b", mentions: " syntaqxx " }, |
| 19 | { channel_id: "c2", id: "m0", author: "user:b", mentions: " syntaqx " }, |
| 20 | ]; |
| 21 | const counts = tally( |
| 22 | rows, |
| 23 | "user:a", |
| 24 | "syntaqx", |
| 25 | new Map([ |
| 26 | ["c1", null], |
| 27 | ["c2", "m1"], |
| 28 | ]), |
| 29 | ); |
| 30 | assert.deepEqual(counts.get("c1"), { unread: 2, mentions: 1 }); |
| 31 | // m0 was read already, and @syntaqxx is someone else. |
| 32 | assert.deepEqual(counts.get("c2"), { unread: 1, mentions: 0 }); |
| 33 | assert.equal(counts.get("c3"), undefined); |
| 34 | }); |
| 35 | |
| 36 | test("the sidebar puts starred first, then the most recently active", () => { |
| 37 | const entry = (title: string, starred: boolean, at: string | null) => ({ |
| 38 | title, |
| 39 | starred, |
| 40 | channel: { last_message_at: at, created_at: "2026-10-01T00:00:00.000Z" }, |
| 41 | }); |
| 42 | const ordered = sidebarOrder([ |
| 43 | entry("quiet", false, null), |
| 44 | entry("busy", false, "2026-10-08T10:00:00.000Z"), |
| 45 | entry("pinned", true, "2026-10-02T00:00:00.000Z"), |
| 46 | entry("older", false, "2026-10-05T00:00:00.000Z"), |
| 47 | ]); |
| 48 | assert.deepEqual( |
| 49 | ordered.map((e) => e.title), |
| 50 | ["pinned", "busy", "older", "quiet"], |
| 51 | ); |
| 52 | }); |
| 53 | |
| 54 | test("a direct message is titled by the others, or by you for notes", () => { |
| 55 | const p = (display_name: string) => ({ display_name }); |
| 56 | assert.equal(dmTitle([p("Ada")], p("Me")), "Ada"); |
| 57 | assert.equal(dmTitle([p("Ada"), p("Ship")], p("Me")), "Ada, Ship"); |
| 58 | assert.equal(dmTitle([p("A"), p("B"), p("C"), p("D"), p("E")], p("Me")), "A, B, C and 2 more"); |
| 59 | assert.equal(dmTitle([], p("Chase")), "Chase (you)"); |
| 60 | }); |