| 1 | // De chips in het lijf van een Note krijgen een eigen URL (shaer-38y).
|
|---|
| 2 | //
|
|---|
| 3 | // Eerder was dit een vetgedrukte opsomming van titels met een enkele "listen
|
|---|
| 4 | // on"-link naar de post als geheel: vijf namen waar een lezer niets mee kon.
|
|---|
| 5 | // Elke track heeft op de postpagina al een anker (#track-<id>) -- direct
|
|---|
| 6 | // ingesloten, in een album of in een playlist -- dus elke naam kan naar precies
|
|---|
| 7 | // het nummer wijzen waar hij bij hoort.
|
|---|
| 8 | import { test } from 'node:test';
|
|---|
| 9 | import assert from 'node:assert/strict';
|
|---|
| 10 |
|
|---|
| 11 | process.env.DATABASE_PATH = ':memory:';
|
|---|
| 12 | process.env.PUBLIC_BASE_URL = 'https://test.example';
|
|---|
| 13 |
|
|---|
| 14 | const dbMod = await import('../src/config/database.js');
|
|---|
| 15 | const db = dbMod.default;
|
|---|
| 16 | dbMod.initializeDatabase();
|
|---|
| 17 | const AP = (await import('../src/services/ActivityPubService.js')).default;
|
|---|
| 18 |
|
|---|
| 19 | const BASE = 'https://test.example';
|
|---|
| 20 |
|
|---|
| 21 | db.prepare('INSERT INTO users (id, username, email, password_hash, role) VALUES (?,?,?,?,?)')
|
|---|
| 22 | .run('u1', 'robin', 'r@t', 'x', 'god');
|
|---|
| 23 | db.prepare('INSERT INTO sites (id, slug, title, owner_id, is_public) VALUES (?,?,?,?,1)')
|
|---|
| 24 | .run('s1', 'band', 'De Band', 'u1');
|
|---|
| 25 |
|
|---|
| 26 | const insM = db.prepare('INSERT INTO media (id, site_id, filename, storage_path, mime_type, size) VALUES (?,?,?,?,?,1000)');
|
|---|
| 27 | const insT = db.prepare('INSERT INTO audio_tracks (id, site_id, title, album, duration, media_id, fedi_open) VALUES (?,?,?,?,?,?,?)');
|
|---|
| 28 | insM.run('m1', 's1', 'een.mp3', 'audio/een.mp3', 'audio/mpeg');
|
|---|
| 29 | insM.run('m2', 's1', 'twee.mp3', 'audio/twee.mp3', 'audio/mpeg');
|
|---|
| 30 | insM.run('m3', 's1', 'drie.mp3', 'audio/drie.mp3', 'audio/mpeg');
|
|---|
| 31 | insT.run('t1', 's1', 'Eerste', 'De Plaat', 200, 'm1', 1);
|
|---|
| 32 | insT.run('t2', 's1', 'Tweede', 'De Plaat', 180, 'm2', 1);
|
|---|
| 33 | insT.run('t3', 's1', 'Derde', null, 160, 'm3', 1);
|
|---|
| 34 |
|
|---|
| 35 | db.prepare("INSERT INTO playlists (id, site_id, title, kind) VALUES ('lijst','s1','De Lijst','playlist')").run();
|
|---|
| 36 | db.prepare("INSERT INTO playlist_tracks (playlist_id, track_id, position) VALUES ('lijst','t3',0)").run();
|
|---|
| 37 |
|
|---|
| 38 | const site = db.prepare("SELECT * FROM sites WHERE id = 's1'").get();
|
|---|
| 39 | const note = (content, id = 'p1') =>
|
|---|
| 40 | AP.buildNote(BASE, site, { id, slug: id, title: 'T', content, status: 'published' });
|
|---|
| 41 |
|
|---|
| 42 | test('een losse track wordt een link naar zijn eigen anker', () => {
|
|---|
| 43 | const c = note('[[track:t1]]').content;
|
|---|
| 44 | assert.ok(c.includes(`<a href="${BASE}/p1#track-t1">Eerste</a>`), c.slice(-300));
|
|---|
| 45 | });
|
|---|
| 46 |
|
|---|
| 47 | test('meerdere tracks: elk zijn eigen link, in de volgorde van de post', () => {
|
|---|
| 48 | const c = note('[[track:t2]] en [[track:t1]]', 'p2').content;
|
|---|
| 49 | const namen = [...c.matchAll(/#track-(t\d)">([^<]+)</g)].map((m) => [m[1], m[2]]);
|
|---|
| 50 | assert.deepEqual(namen, [['t2', 'Tweede'], ['t1', 'Eerste']]);
|
|---|
| 51 | });
|
|---|
| 52 |
|
|---|
| 53 | test('een album-insluiting levert links per track, niet een albumnaam', () => {
|
|---|
| 54 | const c = note('[[album:De Plaat]]', 'p3').content;
|
|---|
| 55 | assert.ok(c.includes(`#track-t1">Eerste</a>`));
|
|---|
| 56 | assert.ok(c.includes(`#track-t2">Tweede</a>`));
|
|---|
| 57 | });
|
|---|
| 58 |
|
|---|
| 59 | test('een playlist ook -- die gaf eerder helemaal geen namen', () => {
|
|---|
| 60 | const c = note('[[playlist:lijst]]', 'p4').content;
|
|---|
| 61 | assert.ok(c.includes(`#track-t3">Derde</a>`), 'de tracks van de lijst staan er nu bij');
|
|---|
| 62 | });
|
|---|
| 63 |
|
|---|
| 64 | test('een albumnaam zonder tracks blijft gewone tekst', () => {
|
|---|
| 65 | const c = note('[[album:Bestaat Niet]]', 'p5').content;
|
|---|
| 66 | assert.ok(c.includes('Bestaat Niet'));
|
|---|
| 67 | assert.ok(!/#track-[^"]*">Bestaat Niet/.test(c), 'geen link naar een anker dat er niet is');
|
|---|
| 68 | });
|
|---|
| 69 |
|
|---|
| 70 | test('dezelfde track twee keer levert een link, niet twee', () => {
|
|---|
| 71 | const c = note('[[track:t1]] en nog eens [[track:t1]]', 'p6').content;
|
|---|
| 72 | assert.equal([...c.matchAll(/#track-t1"/g)].length, 1);
|
|---|
| 73 | });
|
|---|
| 74 |
|
|---|
| 75 | test('en de listen-link naar de post zelf blijft staan', () => {
|
|---|
| 76 | const c = note('[[track:t1]]', 'p7').content;
|
|---|
| 77 | assert.ok(/listen on/.test(c), 'de uitnodiging naar de pagina als geheel verdwijnt niet');
|
|---|
| 78 | });
|
|---|