Changeset a5a6249 in Klonkt for test/ward-pwa.test.js


Ignore:
Timestamp:
08/12/2026 07:52:13 PM (3 months ago)
Author:
Robin <roboburr@…>
Children:
084b046
Parents:
303bfc4
Message:

De Ward PWA: de feed en de reddingsboei

Plak 2. Nu valt er iets te doen op /ward in plaats van alleen te kijken.

DE FEED. Dezelfde bron als de Krant (getTimeline) en dezelfde partial
voor de body (renderNoteBody), zodat een post er overal hetzelfde uitziet:
opmaak, media, quote-kaart, embed. Alleen kale content doorgeven zou een
lege regel opleveren waar een foto hoort, precies de fout die het
guardian-dashboard ooit had.

DE BOEI, en die is hier BETER dan in de app. Shaer maakt een
schermafdruk van de kaart, met al het gedoe van buiten beeld renderen.
Op de server weten we wélke note het is, dus de hulpvraag draagt de note
zelf mee. Een guardian ziet daardoor de echte post en niet een plaatje
dat er ooit op leek.

Slepen met pointer-events, want dat is het enige dat op een telefoon en
met een muis hetzelfde doet. touch-action: none op de boei houdt de
pagina stil tijdens het slepen; zonder dat vecht het met scrollen en
verlies je hem halverwege. De kaart eronder licht op, want mikken met een
vinger zonder terugkoppeling is gokken. Een tik zonder slepen vraagt hulp
zonder dat er een post bij hoort, en de grote knop bovenaan doet
hetzelfde.

Changed files:
src/routes/ward.js

  • /api/feed met afgemaakte body per kaart
  • /api/help: direct bericht aan ALLE guardians, met de note erbij; 409 als er geen guardians zijn, want dan is er niets te vragen

src/views/pages/ward.ejs

  • feed-sectie, zwevende boei, hulpdialoog

src/assets/js/ward.js

  • kaarten tekenen, slepen, mikken, versturen

src/assets/css/ward.css

  • kaarten, boei, dialoog, sr-only

src/services/i18n.js

  • acht nieuwe sleutels in nl, en, de

test/ward-pwa.test.js

  • de feed levert een gerenderde body; de boei weigert zonder guardians; een vreemde kan hem niet afvuren

remarks: 889 tests groen. Slepen is alleen in code getest, niet met een
echte vinger op een echt scherm; dat is aan Robin op dev.

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • test/ward-pwa.test.js

    r303bfc4 ra5a6249  
    118118  } finally { server.close(); }
    119119});
     120
     121test('de feed levert afgemaakte kaarten, niet kale content', async () => {
     122  // Een post in de tijdlijn van dit kind.
     123  db.prepare(`INSERT INTO ap_timeline (slug, id, author_uri, author_handle, author_name, content, url, published, created_at)
     124              VALUES ('mee', 'p-1', ?, '@vriend@elders.example', 'Vriend', '<p>hallo</p>', 'https://elders.example/n/1', datetime('now'), datetime('now'))`)
     125    .run('https://elders.example/ap/users/vriend');
     126
     127  const { server, port } = await listen(appWith({ user: { id: 'u1' } }));
     128  try {
     129    const r = await fetch(`http://127.0.0.1:${port}/ward/api/feed`);
     130    assert.equal(r.status, 200);
     131    const { items } = await r.json();
     132    assert.equal(items.length, 1);
     133    // De body komt AF van de server: dezelfde partial als de Krant. Alleen
     134    // `content` doorgeven zou media en quote-kaarten laten verdwijnen.
     135    assert.ok(items[0].bodyHtml, 'de kaart kwam zonder gerenderde body');
     136    assert.ok(items[0].whenText, 'geen leesbare tijd');
     137    // De id is waar de boei op mikt.
     138    assert.equal(items[0].id, 'p-1');
     139  } finally { server.close(); }
     140});
     141
     142test('de boei weigert als er niemand is om te vragen', async () => {
     143  // Een kind ZONDER guardians. Dan is er niets om naartoe te sturen, en dat
     144  // moet het zeggen in plaats van te doen alsof er hulp onderweg is.
     145  db.prepare('INSERT INTO users (id, username, email, password_hash, role) VALUES (?,?,?,?,?)')
     146    .run('u2', 'alleen', 'a@t', 'x', 'user');
     147  db.prepare('INSERT INTO sites (id, slug, title, owner_id) VALUES (?,?,?,?)')
     148    .run('s2', 'alleen', 'Alleen', 'u2');
     149
     150  const { server, port } = await listen(appWith({ user: { id: 'u2' } }));
     151  try {
     152    const r = await fetch(`http://127.0.0.1:${port}/ward/api/help`, {
     153      method: 'POST',
     154      headers: { 'Content-Type': 'application/json' },
     155      body: JSON.stringify({ words: 'help' }),
     156    });
     157    assert.equal(r.status, 409);
     158    assert.equal((await r.json()).error, 'no_guardians');
     159  } finally { server.close(); }
     160});
     161
     162test('een vreemde kan de boei niet afvuren', async () => {
     163  // Zonder deze poort zou iedereen namens een kind zijn guardians kunnen
     164  // alarmeren.
     165  const { server, port } = await listen(appWith({}));
     166  try {
     167    const r = await fetch(`http://127.0.0.1:${port}/ward/api/help`, {
     168      method: 'POST', headers: { 'Content-Type': 'application/json' },
     169      body: JSON.stringify({ words: 'x' }), redirect: 'manual',
     170    });
     171    assert.notEqual(r.status, 200);
     172  } finally { server.close(); }
     173});
Note: See TracChangeset for help on using the changeset viewer.