import { test } from 'node:test'; import { strict as assert } from 'node:assert'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { randomUUID } from 'node:crypto'; import { createApp } from '../src/server.js'; const TOKEN = 'test-token-' + randomUUID(); test('links CRUD workflow', async () => { const dbPath = join(tmpdir(), `links-test-${randomUUID()}.sqlite`); const app = createApp({ dbPath, adminToken: TOKEN }); const port = 3000 + Math.floor(Math.random() * 1000); const server = app.server.listen(port); const base = `http://127.0.0.1:${port}`; try { // Create link let res = await fetch(`${base}/v1/admin/links`, { method: 'POST', headers: { 'Authorization': `Bearer ${TOKEN}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ title: 'Test Link', url: 'https://example.com', category: 'external', description: 'A test link', visible: true, sort_order: 5 }) }); assert.equal(res.status, 201, 'create should return 201'); const created = await res.json(); assert.ok(created.data.id, 'created link should have id'); assert.equal(created.data.title, 'Test Link'); const linkId = created.data.id; // List all links (admin) res = await fetch(`${base}/v1/admin/links`, { headers: { 'Authorization': `Bearer ${TOKEN}` } }); assert.equal(res.status, 200); let list = await res.json(); assert.equal(list.data.length, 1, 'should have 1 link'); // Get single link res = await fetch(`${base}/v1/admin/links/${linkId}`, { headers: { 'Authorization': `Bearer ${TOKEN}` } }); assert.equal(res.status, 200); const single = await res.json(); assert.equal(single.data.title, 'Test Link'); // Update link res = await fetch(`${base}/v1/admin/links/${linkId}`, { method: 'PATCH', headers: { 'Authorization': `Bearer ${TOKEN}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ title: 'Updated Link', visible: false }) }); assert.equal(res.status, 200); const updated = await res.json(); assert.equal(updated.data.title, 'Updated Link'); assert.equal(updated.data.visible, 0); // Public endpoint should not show invisible links res = await fetch(`${base}/v1/links`); assert.equal(res.status, 200); const publicLinks = await res.json(); assert.equal(publicLinks.data.length, 0, 'invisible links should not appear in public endpoint'); // Make visible again res = await fetch(`${base}/v1/admin/links/${linkId}`, { method: 'PATCH', headers: { 'Authorization': `Bearer ${TOKEN}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ visible: true }) }); assert.equal(res.status, 200); // Public endpoint should now show link res = await fetch(`${base}/v1/links`); const publicVisible = await res.json(); assert.equal(publicVisible.data.length, 1, 'visible links should appear in public endpoint'); // Delete link res = await fetch(`${base}/v1/admin/links/${linkId}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${TOKEN}` } }); assert.equal(res.status, 200); // Verify deletion res = await fetch(`${base}/v1/admin/links`, { headers: { 'Authorization': `Bearer ${TOKEN}` } }); list = await res.json(); assert.equal(list.data.length, 0, 'link should be deleted'); } finally { server.close(); app.close(); } }); test('links validation', async () => { const dbPath = join(tmpdir(), `links-validation-${randomUUID()}.sqlite`); const app = createApp({ dbPath, adminToken: TOKEN }); const port = 3001 + Math.floor(Math.random() * 1000); const server = app.server.listen(port); const base = `http://127.0.0.1:${port}`; try { // Missing title let res = await fetch(`${base}/v1/admin/links`, { method: 'POST', headers: { 'Authorization': `Bearer ${TOKEN}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ url: 'https://example.com' }) }); assert.equal(res.status, 400, 'should reject missing title'); // Missing URL res = await fetch(`${base}/v1/admin/links`, { method: 'POST', headers: { 'Authorization': `Bearer ${TOKEN}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ title: 'Test' }) }); assert.equal(res.status, 400, 'should reject missing url'); // Invalid category res = await fetch(`${base}/v1/admin/links`, { method: 'POST', headers: { 'Authorization': `Bearer ${TOKEN}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ title: 'Test', url: 'https://example.com', category: 'invalid' }) }); assert.equal(res.status, 400, 'should reject invalid category'); } finally { server.close(); app.close(); } });