singularity-forge/src/tests/web-mode-network-flags.test.ts

195 lines
7.1 KiB
TypeScript

import test from 'node:test'
import assert from 'node:assert/strict'
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { join } from 'node:path'
import { tmpdir } from 'node:os'
const cliWeb = await import('../cli-web-branch.ts')
const webMode = await import('../web-mode.ts')
// ─── CLI flag parsing ────────────────────────────────────────────────
test('parseCliArgs captures --host flag', () => {
const flags = cliWeb.parseCliArgs(['node', 'dist/loader.js', '--web', '--host', '0.0.0.0'])
assert.equal(flags.web, true)
assert.equal(flags.webHost, '0.0.0.0')
})
test('parseCliArgs captures --port flag', () => {
const flags = cliWeb.parseCliArgs(['node', 'dist/loader.js', '--web', '--port', '8080'])
assert.equal(flags.web, true)
assert.equal(flags.webPort, 8080)
})
test('parseCliArgs ignores invalid port values', () => {
const flags = cliWeb.parseCliArgs(['node', 'dist/loader.js', '--web', '--port', 'abc'])
assert.equal(flags.webPort, undefined)
})
test('parseCliArgs ignores out-of-range port', () => {
const flags = cliWeb.parseCliArgs(['node', 'dist/loader.js', '--web', '--port', '99999'])
assert.equal(flags.webPort, undefined)
})
test('parseCliArgs captures --allowed-origins flag', () => {
const flags = cliWeb.parseCliArgs(['node', 'dist/loader.js', '--web', '--allowed-origins', 'http://192.168.1.10:3000'])
assert.deepEqual(flags.webAllowedOrigins, ['http://192.168.1.10:3000'])
})
test('parseCliArgs splits comma-separated allowed origins', () => {
const flags = cliWeb.parseCliArgs([
'node', 'dist/loader.js', '--web',
'--allowed-origins', 'http://192.168.1.10:3000,http://tailscale-host:3000',
])
assert.deepEqual(flags.webAllowedOrigins, ['http://192.168.1.10:3000', 'http://tailscale-host:3000'])
})
test('parseCliArgs captures all web network flags together', () => {
const flags = cliWeb.parseCliArgs([
'node', 'dist/loader.js', '--web',
'--host', '0.0.0.0',
'--port', '4000',
'--allowed-origins', 'http://my-tailscale:4000',
])
assert.equal(flags.webHost, '0.0.0.0')
assert.equal(flags.webPort, 4000)
assert.deepEqual(flags.webAllowedOrigins, ['http://my-tailscale:4000'])
})
test('parseCliArgs does not set network flags when not provided', () => {
const flags = cliWeb.parseCliArgs(['node', 'dist/loader.js', '--web'])
assert.equal(flags.webHost, undefined)
assert.equal(flags.webPort, undefined)
assert.equal(flags.webAllowedOrigins, undefined)
})
// ─── launchWebMode env forwarding ────────────────────────────────────
test('launchWebMode forwards custom host, port, and allowed origins to subprocess env', async (t) => {
const tmp = mkdtempSync(join(tmpdir(), 'gsd-web-net-'))
const standaloneRoot = join(tmp, 'dist', 'web', 'standalone')
const serverPath = join(standaloneRoot, 'server.js')
mkdirSync(standaloneRoot, { recursive: true })
writeFileSync(serverPath, 'console.log("stub")\n')
let spawnEnv: Record<string, string> | undefined
t.after(() => { rmSync(tmp, { recursive: true, force: true }) });
const status = await webMode.launchWebMode(
{
cwd: '/tmp/project',
projectSessionsDir: '/tmp/.gsd/sessions',
agentDir: '/tmp/.gsd/agent',
packageRoot: tmp,
host: '0.0.0.0',
port: 8080,
allowedOrigins: ['http://192.168.1.10:8080', 'http://tailscale-host:8080'],
},
{
initResources: () => {},
spawn: (_command, _args, options) => {
spawnEnv = (options as { env: Record<string, string> }).env
return { pid: 99999, once: () => undefined, unref: () => {} } as any
},
waitForBootReady: async () => undefined,
openBrowser: () => {},
stderr: { write: () => true },
},
)
assert.equal(status.ok, true)
if (!status.ok) throw new Error('expected success')
assert.equal(status.host, '0.0.0.0')
assert.equal(status.port, 8080)
assert.equal(status.url, 'http://0.0.0.0:8080')
assert.ok(spawnEnv)
assert.equal(spawnEnv!.HOSTNAME, '0.0.0.0')
assert.equal(spawnEnv!.PORT, '8080')
assert.equal(spawnEnv!.GSD_WEB_HOST, '0.0.0.0')
assert.equal(spawnEnv!.GSD_WEB_PORT, '8080')
assert.equal(spawnEnv!.GSD_WEB_ALLOWED_ORIGINS, 'http://192.168.1.10:8080,http://tailscale-host:8080')
})
test('launchWebMode omits GSD_WEB_ALLOWED_ORIGINS when none provided', async (t) => {
const tmp = mkdtempSync(join(tmpdir(), 'gsd-web-no-origins-'))
const standaloneRoot = join(tmp, 'dist', 'web', 'standalone')
const serverPath = join(standaloneRoot, 'server.js')
mkdirSync(standaloneRoot, { recursive: true })
writeFileSync(serverPath, 'console.log("stub")\n')
let spawnEnv: Record<string, string> | undefined
t.after(() => { rmSync(tmp, { recursive: true, force: true }) });
await webMode.launchWebMode(
{
cwd: '/tmp/project',
projectSessionsDir: '/tmp/.gsd/sessions',
agentDir: '/tmp/.gsd/agent',
packageRoot: tmp,
},
{
initResources: () => {},
resolvePort: async () => 45000,
env: { CLEAN_ENV: '1' },
spawn: (_command, _args, options) => {
spawnEnv = (options as { env: Record<string, string> }).env
return { pid: 99999, once: () => undefined, unref: () => {} } as any
},
waitForBootReady: async () => undefined,
openBrowser: () => {},
stderr: { write: () => true },
},
)
assert.ok(spawnEnv)
assert.equal(spawnEnv!.GSD_WEB_ALLOWED_ORIGINS, undefined)
})
// ─── runWebCliBranch end-to-end forwarding ───────────────────────────
test('runWebCliBranch forwards --host, --port, --allowed-origins to launchWebMode', async (t) => {
const tmp = mkdtempSync(join(tmpdir(), 'gsd-web-branch-flags-'))
const projectDir = join(tmp, 'project')
mkdirSync(projectDir, { recursive: true })
let receivedOptions: Record<string, unknown> | undefined
t.after(() => { rmSync(tmp, { recursive: true, force: true }) });
const flags = cliWeb.parseCliArgs([
'node', 'dist/loader.js', '--web', projectDir,
'--host', '0.0.0.0',
'--port', '9000',
'--allowed-origins', 'http://my-host:9000',
])
const result = await cliWeb.runWebCliBranch(flags, {
runWebMode: async (options) => {
receivedOptions = options as unknown as Record<string, unknown>
return {
mode: 'web' as const,
ok: true as const,
cwd: options.cwd,
projectSessionsDir: options.projectSessionsDir,
host: '0.0.0.0',
port: 9000,
url: 'http://0.0.0.0:9000',
hostKind: 'source-dev' as const,
hostPath: '/tmp/fake-web/package.json',
hostRoot: '/tmp/fake-web',
}
},
stderr: { write: () => true },
})
assert.equal(result.handled, true)
if (!result.handled) throw new Error('expected handled')
assert.equal(result.exitCode, 0)
assert.ok(receivedOptions)
assert.equal(receivedOptions!.host, '0.0.0.0')
assert.equal(receivedOptions!.port, 9000)
assert.deepEqual(receivedOptions!.allowedOrigins, ['http://my-host:9000'])
})