source: Klonkt/test/guardian-help-state.test.js@ 9ce14b8

main
Last change on this file since 9ce14b8 was 9ce14b8, checked in by roboburr <roboburr@…>, 5 weeks ago

Een hulpvraag van een oud-ward gaat naar de geschiedenis (shaer-lgo, vervolg)

Bart heeft een hulpvraag staan van iemand die hij niet meer bewaakt, en kwam er
niet vanaf. Terecht: de knop stond er wel, maar de markeerroute eist dat het NOG
je ward is en antwoordt anders met 403. Klikken deed dus niets, zonder uitleg.

HET LOSLAAT-SCHERM BELOOFDE DIT AL LETTERLIJK -- "je krijgt geen hulpvragen meer
van ze". Nieuwe komen inderdaad niet meer binnen, maar wat er al lag bleef in de
lijst staan die om aandacht vraagt. Dit is dus geen nieuwe keuze maar een belofte
die de app al doet en niet nakwam.

NIET ALS AFGEHANDELD. Dat lag voor de hand en is fout: afhandelen is een claim
over een kind waar je niets meer over te zeggen hebt, en die claim wordt ook nog
rondgestuurd naar de guardians die er wel nog zijn. Er is een derde uitkomst en
die leest als wat hij is: niet meer van jou. De vraag zakt naar de geschiedenis,
zonder knoppen, met een regel die zegt dat hun andere guardians er nog zijn.

Dat laatste is geen troost maar een feit: een guardianship eindigt nooit bij de
LAATSTE guardian (3.4 -- dan is het emancipatie). Er blijft altijd iemand over
voor wie de vraag wel open staat, dus dit dooft geen reddingsboei.

Wat er al gebeurd is blijft leesbaar: was je erbij toen je nog guardian was, dan
blijft die oppik met naam staan. Er wordt niets herschreven.

Vier toetsen, drie talen. Suite 615/615.

  • Property mode set to 100644
File size: 6.6 KB
Line 
1// Oppikken en afhandelen van een hulpvraag (shaer-lgo).
2//
3// Een hulpvraag gaat naar ALLE guardians van een kind, op verschillende servers.
4// Zonder gedeelde staat denken er twee dat de ander het oppakt -- en dat is
5// precies het scenario waar de reddingsboei voor bestaat.
6//
7// DE FAALSTAND IS HIER NIET VEILIG. Bij een gate is 'dicht' het veilige
8// antwoord; hier is de faalstand 'iedereen denkt dat het geregeld is', en dat is
9// gevaarlijker dan geen markering. Vandaar dat de meeste tests hieronder gaan
10// over wat er gebeurt als er IETS niet klopt: dan hoort de hulpvraag OPEN te
11// staan.
12//
13// Run: npm test
14
15import { test } from 'node:test';
16import assert from 'node:assert/strict';
17
18process.env.DATABASE_PATH = ':memory:';
19process.env.PUBLIC_BASE_URL = 'https://klonkt.test';
20
21const dbMod = await import('../src/config/database.js');
22const db = dbMod.default;
23dbMod.initializeDatabase();
24const help = await import('../src/services/guardianship/help.js');
25
26const NOTE = 'https://kind.test/ap/notes/hulp-1';
27const OMA = 'https://oma.test/ap/users/oma';
28const OPA = 'https://opa.test/ap/users/opa';
29
30test('een verse hulpvraag staat open', () => {
31 const s = help.statusOf(NOTE);
32 assert.equal(s.open, true);
33 assert.deepEqual(s.pickedUpBy, []);
34 assert.equal(s.handled, null);
35});
36
37test('oppikken mag STAPELEN', () => {
38 // Twee mensen die tegelijk reageren op een kind dat om hulp vraagt is geen
39 // probleem. Twee die allebei niets doen omdat de ander het geclaimd had, wel.
40 help.record(NOTE, OMA, 'pickup', '@oma@oma.test');
41 help.record(NOTE, OPA, 'pickup', '@opa@opa.test');
42 const s = help.statusOf(NOTE);
43 assert.equal(s.pickedUpBy.length, 2);
44 assert.equal(s.open, true, 'opgepikt is nog niet afgehandeld');
45});
46
47test('en het staat erbij DOOR WIE, want dat was de hele vraag', () => {
48 const s = help.statusOf(NOTE);
49 assert.ok(s.pickedUpBy.some((p) => p.handle === '@oma@oma.test'));
50 assert.ok(s.pickedUpBy.every((p) => p.at), 'met een tijdstip, anders kun je niet zien dat het oud wordt');
51});
52
53test('twee keer hetzelfde oppikken telt een keer', () => {
54 help.record(NOTE, OMA, 'pickup', '@oma@oma.test');
55 assert.equal(help.statusOf(NOTE).pickedUpBy.length, 2);
56});
57
58test('een oppik VERVALT NIET maar veroudert wel zichtbaar', () => {
59 // Barts keuze: niets verdwijnt, want een signaal dat wegvalt laat een
60 // hulpvraag er onaangeroerd uitzien terwijl er iemand mee bezig is. Het scherm
61 // toont in plaats daarvan hoe oud het is.
62 const rijen = [{ kind: 'pickup', guardian_uri: OMA, created_at: '2026-08-05T10:00:00.000Z' }];
63 const s = help.helpStatus(rijen, Date.parse('2026-08-07T10:00:00.000Z'));
64 assert.equal(s.open, true);
65 assert.equal(s.ageMs, 2 * 24 * 3600 * 1000, 'twee dagen oud, en dat hoort te zien te zijn');
66});
67
68test('afhandelen sluit hem, met naam', () => {
69 help.record(NOTE, OPA, 'handled', '@opa@opa.test');
70 const s = help.statusOf(NOTE);
71 assert.equal(s.open, false);
72 assert.equal(s.handled.handle, '@opa@opa.test');
73 assert.equal(s.ageMs, null, 'de leeftijd van een oppik zegt niets meer als het klaar is');
74});
75
76test('er is GEEN terugdraai', () => {
77 // Besluit van Bart: sluiten gebeurt met een stevige bevestiging, en leeft de
78 // vraag daarna nog, dan wordt hij OPNIEUW GESTELD -- een nieuwe hulpvraag. Er
79 // wordt niets herschreven.
80 assert.equal(typeof help.default.undo, 'undefined');
81 assert.equal(typeof help.default.reopen, 'undefined');
82});
83
84test('bij twijfel staat een hulpvraag OPEN', () => {
85 // Alles wat geen expliciete afsluiting is telt als open. Een lege lijst, rommel,
86 // een onbekende soort: allemaal 'er wacht nog iemand'. De omgekeerde fout --
87 // iets als afgehandeld tonen dat het niet is -- is de gevaarlijke.
88 for (const rijen of [[], null, [{ kind: 'iets', guardian_uri: OMA }], [{ kind: 'pickup', guardian_uri: OMA }]]) {
89 assert.equal(help.helpStatus(rijen).open, true);
90 }
91});
92
93test('een markering wordt herkend, en iets anders niet', () => {
94 assert.deepEqual(help.parseMarker({ 'shaer:helpPickup': NOTE }), { kind: 'pickup', noteUri: NOTE });
95 assert.deepEqual(help.parseMarker({ 'shaer:helpHandled': NOTE }), { kind: 'handled', noteUri: NOTE });
96 assert.equal(help.parseMarker({ content: '<p>hoi</p>' }), null);
97 assert.equal(help.parseMarker(null), null);
98 assert.equal(help.parseMarker({ 'shaer:helpPickup': '' }), null, 'leeg is geen markering');
99});
100
101test('afhandelen wint van oppikken in hetzelfde bericht', () => {
102 // Kan niet ontstaan uit onze eigen verzending, maar wel uit een andere
103 // implementatie. Het zwaarste signaal telt.
104 assert.equal(help.parseMarker({ 'shaer:helpPickup': NOTE, 'shaer:helpHandled': NOTE }).kind, 'handled');
105});
106
107test('een lijst hulpvragen kost EEN query', () => {
108 const N2 = 'https://kind.test/ap/notes/hulp-2';
109 help.record(N2, OMA, 'pickup', '@oma@oma.test');
110 const m = help.statusFor([NOTE, N2, 'https://kind.test/ap/notes/leeg']);
111 assert.equal(m.size, 3);
112 assert.equal(m.get(NOTE).open, false);
113 assert.equal(m.get(N2).pickedUpBy.length, 1);
114 assert.equal(m.get('https://kind.test/ap/notes/leeg').open, true, 'onbekend is open');
115});
116
117test('een hulpvraag van een OUD-ward staat niet meer open', () => {
118 // Het loslaat-scherm belooft dit al: "je krijgt geen hulpvragen meer van ze".
119 // Nieuwe komen niet meer binnen, maar wat er al lag bleef staan -- en was niet
120 // af te sluiten, want de markeerroute eist dat het nog je ward is.
121 const st = help.withWardship(help.helpStatus([]), false);
122 assert.equal(st.open, false);
123 assert.equal(st.formerWard, true);
124});
125
126test('maar hij is NIET afgehandeld', () => {
127 // Dat zou een claim zijn over een kind waar je niets meer over te zeggen hebt,
128 // en die claim wordt ook nog rondgestuurd naar de andere guardians. Er is een
129 // derde uitkomst: niet meer van jou.
130 const st = help.withWardship(help.helpStatus([]), false);
131 assert.equal(st.handled, null);
132});
133
134test('een lopende oppik blijft leesbaar als je losgelaten hebt', () => {
135 // Je was erbij. Dat je nu geen guardian meer bent maakt niet dat het nooit
136 // gebeurd is -- de geschiedenis hoort te kloppen.
137 const rijen = [{ kind: 'pickup', guardian_uri: OMA, guardian_handle: '@oma', created_at: '2026-08-05T10:00:00.000Z' }];
138 const st = help.withWardship(help.helpStatus(rijen, Date.parse('2026-08-05T11:00:00.000Z')), false);
139 assert.equal(st.pickedUpBy.length, 1);
140 assert.equal(st.pickedUpBy[0].handle, '@oma');
141});
142
143test('zolang het WEL je ward is verandert er niets', () => {
144 const rijen = [{ kind: 'pickup', guardian_uri: OMA, guardian_handle: '@oma', created_at: '2026-08-05T10:00:00.000Z' }];
145 const basis = help.helpStatus(rijen, Date.parse('2026-08-05T11:00:00.000Z'));
146 assert.deepEqual(help.withWardship(basis, true), basis);
147});
Note: See TracBrowser for help on using the repository browser.