"""Run the sidecar's node test suites (claude-box/*.test.mjs) inside exec-fn's pytest. exec-fn owns the test harness; the sidecar repo (submodule claude-box/) owns only its suites (ARCHITECTURE.md §1e). One test per suite, discovered, so a new `foo.test.mjs` is covered the day it lands (uploads.test.mjs had no wrapper and never ran in the suite until this replaced exec-fn's two per-file wrappers, 2026-10-14). Each suite is passed EXPLICITLY: `node --test ` would treat every .mjs in the dir as a test file and execute server.mjs, which listens on a port. The two suites below must never vanish quietly -- the sandbox path gate and the panel sign-in are the sidecar's security edge (ARCHITECTURE.md). """ import shutil import subprocess from pathlib import Path import pytest BOX = Path(__file__).resolve().parents[1] / "claude-box" SUITES = sorted(BOX.glob("*.test.mjs")) MUST_HAVE = {"sandbox-paths.test.mjs", "login.test.mjs"} def test_security_suites_present(): missing = MUST_HAVE - {p.name for p in SUITES} assert not missing, f"{sorted(missing)} missing from {BOX} — the gate lost its tests (uninitialised submodule? `git submodule update --init`)" @pytest.mark.skipif(shutil.which("node") is None, reason="node not installed") @pytest.mark.parametrize("suite", SUITES, ids=lambda p: p.name) def test_node_suite(suite): r = subprocess.run(["node", "--test", str(suite)], cwd=BOX, capture_output=True, text=True, timeout=120) assert r.returncode == 0, r.stdout[-3000:] + r.stderr[-2000:]