// tests/kb-update/test-keychain.test.mjs // Unit tests for scripts/kb-update/lib/keychain.mjs (C3.1). // readSecret reads a single Keychain item via the `security` CLI. Tests inject a // stub exec impl so no real Keychain / no real secret ever touches the suite // (spec ยง3: "Tester injiserer falske creds via en stub"). import { test } from 'node:test'; import assert from 'node:assert/strict'; import { readSecret } from '../../scripts/kb-update/lib/keychain.mjs'; test('readSecret โ€” returns the trimmed secret via injected exec', () => { const calls = []; const execImpl = (cmd, args, opts) => { calls.push({ cmd, args, opts }); return 'secret-value\n'; }; const v = readSecret('learn-platform-tenant-id', 'ktg', { execImpl }); assert.equal(v, 'secret-value'); assert.equal(calls.length, 1); assert.equal(calls[0].cmd, 'security'); assert.deepEqual(calls[0].args, [ 'find-generic-password', '-s', 'learn-platform-tenant-id', '-a', 'ktg', '-w', ]); assert.equal(calls[0].opts.encoding, 'utf8'); }); test('readSecret โ€” returns null when the item is missing (exec throws)', () => { const execImpl = () => { throw new Error('SecKeychain item not found'); }; assert.equal(readSecret('does-not-exist', 'ktg', { execImpl }), null); }); test('readSecret โ€” defaults account to ktg', () => { let captured; const execImpl = (_cmd, args) => { captured = args; return 'x'; }; readSecret('svc', undefined, { execImpl }); assert.ok(captured.includes('-a')); assert.equal(captured[captured.indexOf('-a') + 1], 'ktg'); });