source: Klonkt/test/unread.test.js@ 383e897

main
Last change on this file since 383e897 was 383e897, checked in by Robin <roboburr@…>, 4 weeks ago

De badge telt niet wat de poort verbergt

Gevonden bij het bijwerken van de bead, niet bij het bouwen: unreadPerConversation
telde alle inkomende berichten, ook die de app achter een dichte messages-poort
nooit toont. Dan vertelt het getal precies wat de poort verbergt.

Nu dezelfde regel als bij de serialisatie: dicht telt niet mee, behalve wat er
altijd door mag -- het guardian-kanaal en de boei.

Co-Authored-By: Claude Opus 5 <noreply@…>

  • Property mode set to 100644
File size: 4.1 KB
Line 
1// De badge: ongelezen per gesprek (shaer-frontend-3tx).
2//
3// Twee dingen liggen hier vast. Een COUNT en geen bijgehouden getal -- bij een
4// verwijdering klopt het dan vanzelf weer, waar een teller zou blijven staan.
5// En Read als GEBEURTENIS: markeren is optellend, dus een toestel dat een week
6// uit stond kan je gelezen berichten niet terugzetten op ongelezen.
7//
8// In-memory SQLite. Run: npm test
9import { test } from 'node:test';
10import assert from 'node:assert/strict';
11
12process.env.DATABASE_PATH = ':memory:';
13process.env.PUBLIC_BASE_URL = 'https://klonkt.test';
14
15const dbMod = await import('../src/config/database.js');
16const db = dbMod.default;
17dbMod.initializeDatabase();
18const AP = await import('../src/services/ActivityPubService.js');
19
20db.prepare('INSERT INTO users (id, username, email, password_hash, role) VALUES (?,?,?,?,?)')
21 .run('u1', 'u1', 'u1@t', 'x', 'god');
22db.prepare('INSERT INTO sites (id, slug, title, owner_id) VALUES (?,?,?,?)').run('s1', 'kind', 'Kind', 'u1');
23
24const OMA = 'https://elders/u/oma';
25const OOM = 'https://elders/u/oom';
26const arrived = (uri, from, stamp, wave = 0) => db.prepare(
27 `INSERT INTO ap_mentions (slug, object_uri, actor_uri, actor_name, content, published, wave)
28 VALUES ('kind', ?, ?, 'iemand', '<p>hoi</p>', ?, ?)`).run(uri, from, stamp, wave);
29
30arrived('https://elders/n/1', OMA, '2026-08-01T10:00:00Z');
31arrived('https://elders/n/2', OMA, '2026-08-01T11:00:00Z');
32arrived('https://elders/n/3', OMA, '2026-08-01T12:00:00Z');
33arrived('https://elders/n/w', OOM, '2026-08-01T09:00:00Z', 1);
34
35test('alles is ongelezen tot je iets gelezen hebt', () => {
36 const u = AP.unreadPerConversation('kind');
37 assert.equal(u.get(OMA).n, 3);
38 assert.equal(u.get(OOM).n, 1);
39 // Een zwaai telt apart: dat is een zetje van een guardian, geen gesprek.
40 assert.equal(u.get(OOM).wave, true);
41 assert.equal(u.get(OMA).wave, false);
42});
43
44test('lezen tot het tweede bericht laat er een over', () => {
45 AP.markRead('kind', 'https://elders/n/2');
46 assert.equal(AP.unreadPerConversation('kind').get(OMA).n, 1);
47 assert.equal(AP.unreadPerConversation('kind').get(OOM).n, 1, 'een ander gesprek raakt het niet');
48});
49
50test('een oud toestel kan gelezen berichten niet terugzetten', () => {
51 // Precies het geval waar Read-als-gebeurtenis voor is: markeren is
52 // optellend, dus dit doet niets.
53 AP.markRead('kind', 'https://elders/n/1');
54 assert.equal(AP.unreadPerConversation('kind').get(OMA).n, 1, 'nog steeds een');
55});
56
57test('alles gelezen is geen rij, niet een nul', () => {
58 AP.markRead('kind', 'https://elders/n/3');
59 assert.equal(AP.unreadPerConversation('kind').get(OMA), undefined);
60});
61
62test('een verwijdering laat het getal vanzelf kloppen', () => {
63 // Waar een bijgehouden teller zou blijven staan: badge zegt 1, er is niets.
64 arrived('https://elders/n/4', OMA, '2026-08-01T13:00:00Z');
65 assert.equal(AP.unreadPerConversation('kind').get(OMA).n, 1);
66 db.prepare("DELETE FROM ap_mentions WHERE object_uri = ?").run('https://elders/n/4');
67 assert.equal(AP.unreadPerConversation('kind').get(OMA), undefined);
68});
69
70test('een onbekende note markeert niets, en dat is geen fout', () => {
71 assert.equal(AP.markRead('kind', 'https://elders/n/bestaat-niet'), null);
72});
73
74test('een dichte messages-poort telt niet mee wat hij verbergt', () => {
75 // Anders vertelt het getal precies wat de poort verbergt: 'er zijn 3
76 // berichten' terwijl de app er geen laat zien.
77 const OPA = 'https://elders/u/opa';
78 arrived('https://elders/n/opa1', OPA, '2026-08-02T10:00:00Z');
79 arrived('https://elders/n/oom2', OOM, '2026-08-02T11:00:00Z');
80 db.prepare(`INSERT INTO ap_mentions (slug, object_uri, actor_uri, actor_name, content, published, help_request)
81 VALUES ('kind', 'https://elders/n/boei', ?, 'iemand', '<p>help</p>', '2026-08-02T12:00:00Z', 1)`).run(OPA);
82
83 const dicht = AP.unreadPerConversation('kind', { messagesAllowed: false, guardians: new Set([OOM]) });
84 assert.equal(dicht.get(OPA).n, 1, 'alleen de boei van opa telt');
85 assert.ok(dicht.get(OOM), 'het guardian-kanaal gaat altijd door');
86
87 const open = AP.unreadPerConversation('kind', { messagesAllowed: true });
88 assert.equal(open.get(OPA).n, 2, 'met de poort open tellen ze allebei');
89});
Note: See TracBrowser for help on using the repository browser.