diff --git a/dashcaddy-api/__tests__/e2e-node/composition-root.e2e.test.js b/dashcaddy-api/__tests__/e2e-node/composition-root.e2e.test.js index 9e8f759..7a45345 100644 --- a/dashcaddy-api/__tests__/e2e-node/composition-root.e2e.test.js +++ b/dashcaddy-api/__tests__/e2e-node/composition-root.e2e.test.js @@ -19,7 +19,6 @@ * assertion compares against that live 404 baseline on the same instance. */ const { spawn } = require('child_process'); -const net = require('net'); const path = require('path'); const os = require('os'); const fs = require('fs'); @@ -30,21 +29,9 @@ let child; let PORT; let JWT; -// OS-assigned ephemeral port (judge polish: not a random 30000-49999 guess). -function freePort() { - return new Promise((resolve, reject) => { - const s = net.createServer(); - s.listen(0, '127.0.0.1', () => { - const p = s.address().port; - s.close(() => resolve(p)); - }); - s.on('error', reject); - }); -} - // Boot the REAL app via its REAL entry contract (createApp + listen). The // child mints a JWT through the same authManager singleton the app wires. -function boot(port) { +function boot() { return new Promise((resolve, reject) => { const child = spawn(process.execPath, ['-e', ` process.env.DATA_DIR = ${JSON.stringify(DATA_DIR)}; @@ -60,8 +47,9 @@ function boot(port) { } catch (e) { jwt = ''; } - const server = app.listen(${port}, '127.0.0.1', () => { + const server = app.listen(0, '127.0.0.1', () => { console.log('JWT:' + jwt); + console.log('PORT:' + server.address().port); console.log('READY'); }); process.on('SIGTERM', () => server.close(() => process.exit(0))); @@ -80,11 +68,13 @@ function boot(port) { }, 30000); child.stdout.on('data', (d) => { buf += String(d); - const m = buf.match(/JWT:(\S*)/); - if (!settled && m && buf.includes('READY')) { + const mj = buf.match(/JWT:(\S*)/); + const mp = buf.match(/PORT:(\d+)/); + if (!settled && mj && mp && buf.includes('READY')) { settled = true; clearTimeout(to); - child.jwt = m[1]; + child.jwt = mj[1]; + child.port = Number(mp[1]); resolve(child); } }); @@ -117,9 +107,10 @@ async function expectMounted(p, allowed) { describe('composition-root e2e (real createApp on ephemeral port)', () => { beforeAll(async () => { - PORT = await freePort(); - child = await boot(PORT); + child = await boot(); // child calls listen(0); no probe/rebind race + PORT = child.port; JWT = child.jwt || ''; + if (!Number.isInteger(PORT) || PORT <= 0) throw new Error('child did not report a bound port'); const u = await get('/api/v1/__definitely_not_mounted__'); unknownStatus = u.status; }, 45000);