// Test: Rechteprüfung beim Speichern (fehlendesBearbeitungsrecht() in // server.js). Startet einen echten Server mit leerer Datenbank in einem // Wegwerf-Ordner (SESSIONS_DIR/DB_PATH), legt eine Rolle nur mit „Kommentar // und Fortschritt“ an und prüft über POST /save-projects, was ein Konto mit // dieser Rolle ändern darf. Aufruf: npm test const test = require('node:test'); const assert = require('node:assert'); const fs = require('fs'); const os = require('os'); const path = require('path'); const { spawn } = require('child_process'); const ordner = fs.mkdtempSync(path.join(os.tmpdir(), 'projektuebersicht-test-')); const PORT = 3990 + Math.floor(Math.random() * 9); const url = p => 'http://127.0.0.1:' + PORT + p; let server; async function anfrage(methode, pfad, cookie, body){ const r = await fetch(url(pfad), { method: methode, headers: Object.assign({ 'Content-Type': 'application/json' }, cookie ? { Cookie: cookie } : {}), body: body === undefined ? undefined : JSON.stringify(body) }); return { status: r.status, daten: await r.json().catch(() => null), cookie: (r.headers.get('set-cookie') || '').split(';')[0] }; } async function anmelden(username, password){ const r = await anfrage('POST', '/login', null, { username, password }); assert.strictEqual(r.status, 200, 'Anmeldung ' + username + ': ' + JSON.stringify(r.daten)); return r.cookie; } test.before(async () => { server = spawn(process.execPath, [path.join(__dirname, '../server.js')], { env: Object.assign({}, process.env, { PORT: String(PORT), SESSIONS_DIR: ordner, DB_PATH: path.join(ordner, 'test.db'), SPEICHER_MAX_MB: '', HAENGER_MAX_S: '' }), stdio: 'ignore' }); for(let i = 0; i < 50; i++){ try { if((await fetch(url('/health'))).ok) return; } catch(e){ /* startet noch */ } await new Promise(r => setTimeout(r, 200)); } throw new Error('Testserver startet nicht'); }); test.after(() => { if(server) server.kill(); fs.rmSync(ordner, { recursive: true, force: true }); }); test('Konto nur mit Kommentar-Recht: Kommentar ja, Terminplan nein', async () => { const pw = /Passwort:\s+(\S+)/.exec(fs.readFileSync(path.join(ordner, 'INITIAL_ADMIN_PASSWORD.txt'), 'utf8'))[1]; const admin = await anmelden('admin', pw); // Rolle mit „Anwendung nutzen“ und „Kommentar und Fortschritt“, sonst nichts. const rolle = await anfrage('POST', '/rollen', admin, { name: 'Nur Kommentar' }); assert.strictEqual(rolle.status, 200, JSON.stringify(rolle.daten)); const key = rolle.daten.neu; assert.strictEqual((await anfrage('PUT', '/rollen/' + key + '/rechte', admin, { rechte: ['app', 'wb.kommentar'], an: true })).status, 200); const konto = await anfrage('POST', '/admin/users', admin, { username: 'leser', firstName: 'Lea', lastName: 'Leser', role: key, department: 'ELT', password: 'geheim-1234' }); assert.strictEqual(konto.status, 200, JSON.stringify(konto.daten)); // Ein Projekt in der aktuellen Sitzung anlegen (als Administrator). const geladen = (await anfrage('GET', '/load-all', admin)).daten; const woche = geladen.weeks[geladen.weeks.length - 1]; woche.projects.push({ id: 'p1', projectUid: 'u1', nr: '99-0001', name: 'Testprojekt', group: 'Aktive Projekte', gewerke: ['ELT'], plan: { todos: [] } }); const angelegt = await anfrage('POST', '/save-week', admin, { week: woche, baseUpdatedAt: woche.updatedAt }); assert.strictEqual(angelegt.status, 200, JSON.stringify(angelegt.daten)); const leser = await anmelden('leser', 'geheim-1234'); const projekt = () => anfrage('GET', '/load-all', leser).then(r => { const w = r.daten.weeks[r.daten.weeks.length - 1]; return { label: w.label, p: w.projects.find(x => x.id === 'p1') }; }); // Aufgabe im Terminplan anlegen: braucht „Terminplan bearbeiten“. let { label, p } = await projekt(); const base = p.updatedAt; p.plan.todos.push({ id: 't1', title: 'Darf nicht gespeichert werden', start: '', end: '', assignees: [], dependsOn: [] }); const verboten = await anfrage('POST', '/save-projects', leser, { label, projects: [{ project: p, baseUpdatedAt: base }] }); assert.strictEqual(verboten.status, 403); assert.strictEqual(verboten.daten.recht, 'proj.plan'); // Kommentar des Gewerks schreiben: erlaubt. ({ label, p } = await projekt()); assert.strictEqual(p.plan.todos.length, 0, 'die verbotene Aufgabe darf nicht gespeichert sein'); p.kommentare = { ELT: { status: 'Abstimmung mit TGA steht aus', statusAuthor: 'Lea Leser', statusAt: new Date().toISOString(), besprochen: false } }; const erlaubt = await anfrage('POST', '/save-projects', leser, { label, projects: [{ project: p, baseUpdatedAt: p.updatedAt }] }); assert.strictEqual(erlaubt.status, 200, JSON.stringify(erlaubt.daten)); });