/** * Composition-root integration test — the "tests pass, prod breaks" cure. * * WHY: all three P7 dogfood bugs (wizard mount missing providers; coord * client never attached; people deduped by id only) shipped to prod with the * full unit suite green, because unit tests inject their own mocks instead * of exercising the real app.js wiring. This suite boots the REAL createApp() * on an ephemeral port and drives HTTP through the real mount table — the * exact wiring that runs in production — for the routes that historically * broke: /network/wizard, /security/shield, /catalog/:id, /deploys. * * Uses DATA_DIR to point the app at a throwaway data dir; no prod files are * touched. */ const { spawn } = require('child_process'); const path = require('path'); const os = require('os'); const fs = require('fs'); const ROOT = path.resolve(__dirname, '..', '..'); // Boot the REAL app via its REAL entry contract (createApp + listen). function boot(port) { return new Promise((resolve, reject) => { const child = spawn(process.execPath, ['-e', ` process.env.DATA_DIR = ${JSON.stringify(DATA_DIR)}; const { createApp } = require(${JSON.stringify(path.join(ROOT, 'src', 'app'))}); // NOTE: the -e script resolves relative requires from CWD semantics; // the absolute path above is required. createApp().then((created) => { const app = created.app || created; const server = app.listen(${port}, '127.0.0.1', () => { console.log('READY'); }); process.on('SIGTERM', () => server.close(() => process.exit(0))); }).catch((e) => { console.error('BOOT-FAIL', e && e.message); process.exit(1); }); `], { cwd: ROOT, stdio: ['ignore', 'pipe', 'pipe'] }); child.stdout.on('data', (d) => { if (String(d).includes('READY')) resolve(child); }); child.stderr.on('data', (d) => process.stderr.write('[boot] ' + d)); child.on('exit', (code) => reject(new Error('boot exited ' + code))); setTimeout(() => reject(new Error('boot timeout')), 30000); }); } const DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), 'dc-comp-root-')); const PORT = 30000 + Math.floor(Math.random() * 20000); let child; async function get(p, expectAuth = true) { const res = await fetch(`http://127.0.0.1:${PORT}${p}`, { redirect: 'manual' }); return { status: res.status, body: await res.text() }; } describe('composition-root e2e (real createApp on ephemeral port)', () => { beforeAll(async () => { child = await boot(PORT); }, 45000); afterAll(async () => { if (child) { child.kill('SIGTERM'); await new Promise((r) => child.on('exit', r)); } fs.rmSync(DATA_DIR, { recursive: true, force: true }); }); it('boots the real app without throwing', () => { expect(child.exitCode).toBeNull(); }); it('/network/wizard/state is mounted and wired (finding #1 regression)', async () => { const r = await get('/api/v1/network/wizard/state'); // 401 = auth-gated but MOUNTED; the bug shipped 404/503-from-broken-mount. expect([200, 401]).toContain(r.status); }); it('/security/shield is mounted (prod-drift regression)', async () => { const r = await get('/api/v1/security/shield'); // 401 = auth-gated but mounted; 200/503 = auth disabled/with snapshot. // 404 would mean the prod-only drift regressed. expect([200, 401, 503]).toContain(r.status); }); it('/catalog/plex returns real image via app.docker.* (DC-160)', async () => { const r = await get('/api/v1/catalog/plex'); // Auth-gated in the real composition root: assert mounted + gate, not 404. expect([200, 401]).toContain(r.status); if (r.status === 200) { expect(r.body).toContain('plexinc/pms-docker'); } else { expect(r.body).toContain('Authentication required'); } }); it('/deploys bridge is mounted (opt-in feature flag)', async () => { const r = await get('/api/v1/deploys/repos'); expect([200, 401, 501]).toContain(r.status); }); });