diff options
Diffstat (limited to 'test')
| -rw-r--r-- | test/cdp/endpoint-test.ts | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/test/cdp/endpoint-test.ts b/test/cdp/endpoint-test.ts new file mode 100644 index 0000000..d4b696f --- /dev/null +++ b/test/cdp/endpoint-test.ts @@ -0,0 +1,99 @@ +/** + * Unit tests for CDP target resolution — no browser and no network required. + * + * This is fork-specific logic (see FORK.md): upstream only ever drives a + * browser on localhost. The precedence here is deliberately asymmetric — an + * explicitly configured endpoint must never silently fall back to a different + * browser, while the built-in default must, so a machine off the wire network + * still gets the local browser the extension was originally written for. + * + * Run: npx tsx test/cdp/endpoint-test.ts + */ +import { DEFAULT_REMOTE_CDP, describeCdpTarget, resolveCdpTarget } from "../../src/cdp/endpoint"; + +let passed = 0; +let failed = 0; +const check = (cond: boolean, label: string): void => { + if (cond) { + passed++; + console.log(` ✓ ${label}`); + } else { + failed++; + console.error(` ✗ ${label}`); + } +}; + +const env = (value?: string): NodeJS.ProcessEnv => (value === undefined ? {} : { BU_CDP_HTTP: value }); + +function main(): void { + // E1: the built-in default, used when nothing is configured. + { + const t = resolveCdpTarget(env()); + check(t.kind === "remote", "E1: unset BU_CDP_HTTP resolves to a remote target"); + if (t.kind === "remote") { + check(t.source === "default", "E1: it is marked as the built-in default, not an instruction"); + check(`${t.host}:${t.port}` === DEFAULT_REMOTE_CDP, "E1: it matches DEFAULT_REMOTE_CDP"); + } + } + + // E2: DEFAULT_REMOTE_CDP must itself be parseable, or the default silently + // degrades to local for everyone. + { + const t = resolveCdpTarget(env()); + check(t.kind !== "local", "E2: the built-in default constant is well-formed"); + } + + // E3: an explicit endpoint is an instruction — source must reflect that, so + // discovery fails loudly rather than falling back. + { + const t = resolveCdpTarget(env("10.0.0.9:9333")); + check(t.kind === "remote", "E3: an explicit host:port resolves to a remote target"); + if (t.kind === "remote") { + check(t.host === "10.0.0.9" && t.port === 9333, "E3: host and port are parsed"); + check(t.source === "env", "E3: it is marked as explicitly configured"); + } + } + + // E4: opting back into upstream behaviour. + for (const alias of ["local", "LOCAL", "off", "none", "0", "no"]) { + const t = resolveCdpTarget(env(alias)); + check(t.kind === "local", `E4: "${alias}" selects this machine's own browser`); + } + + // E5: empty or whitespace is treated as unset rather than as an error — a + // shell exporting an empty var should not break the browser. + for (const blank of ["", " "]) { + const t = resolveCdpTarget(env(blank)); + check(t.kind === "remote" && t.source === "default", `E5: ${JSON.stringify(blank)} falls back to the default`); + } + + // E6: malformed values are rejected, not coerced. Silently reinterpreting + // these would drive an unexpected browser. + for (const bad of ["nonsense", "host:", ":9222", "host:0", "host:70000", "host:abc"]) { + const t = resolveCdpTarget(env(bad)); + check(t.kind === "invalid", `E6: "${bad}" is rejected as malformed`); + } + + // E7: IPv6 and hostnames still work — the port is taken from the LAST colon. + { + const t = resolveCdpTarget(env("castle.local:9223")); + check(t.kind === "remote" && t.host === "castle.local", "E7: hostnames are accepted"); + const v6 = resolveCdpTarget(env("[::1]:9223")); + check(v6.kind === "remote" && v6.host === "[::1]" && v6.port === 9223, "E7: bracketed IPv6 keeps its host"); + } + + // E8: descriptions are for humans in /browser-status; they must distinguish + // a default from an instruction, since only one of them falls back. + { + const d = describeCdpTarget(resolveCdpTarget(env())); + const e = describeCdpTarget(resolveCdpTarget(env("10.0.0.9:9333"))); + check(d.includes("default"), "E8: the default is labelled as such"); + check(e.includes("BU_CDP_HTTP"), "E8: an explicit endpoint names the variable that set it"); + check(describeCdpTarget(resolveCdpTarget(env("local"))).includes("own browser"), "E8: local is described plainly"); + } + + console.log(`\n${passed} passed, ${failed} failed`); + if (failed > 0) process.exit(1); +} + +main(); |
