diff --git a/testing/tests/hux_node_gate.py b/testing/tests/hux_node_gate.py new file mode 100644 index 00000000..5b7bccbe --- /dev/null +++ b/testing/tests/hux_node_gate.py @@ -0,0 +1,85 @@ +"""Portable node test-runner gate for the HUX browser suites. + +Runs ``node --test --experimental-test-coverage`` without the +version-gated threshold/include flags (Node >= 22.8 only) and enforces +the per-source thresholds by parsing the coverage table, so the same +gate passes on the CI image's Node 20 and on newer local Nodes. +TypeScript suites need ``--experimental-strip-types`` (Node >= 22.6); +on older runtimes they skip with an explicit reason instead of failing +on a missing capability. +""" + +from __future__ import annotations + +import re +import subprocess +from pathlib import Path + +import pytest + +ROOT = Path(__file__).resolve().parents[2] +STRIP_TYPES_MINIMUM = (22, 6) +ROW = re.compile(r"([^|\s][^|]*?)\s*\|\s*([0-9.]+)\s*\|\s*([0-9.]+)\s*\|\s*([0-9.]+)") +METRICS = ("lines", "branches", "functions") + + +def node_version() -> tuple[int, int]: + raw = subprocess.run( + ["node", "--version"], check=True, capture_output=True, text=True, timeout=15 + ).stdout.strip().lstrip("v") + major, minor = raw.split(".")[:2] + return int(major), int(minor) + + +def run_node_coverage( + sources: list[str], + tests: list[str], + thresholds: dict[str, float], + strip_types: bool = False, + timeout: int = 60, + overrides: dict[str, dict[str, float]] | None = None, +) -> subprocess.CompletedProcess: + """Run the node suite and enforce coverage thresholds per source file. + + ``overrides`` maps a source basename to explicit per-metric floors for + documented, pre-existing coverage debt (the old aggregate node gate hid + per-file shortfalls); an override still enforces its stated floor. + """ + unknown = set(thresholds) - set(METRICS) + assert not unknown, f"unknown metrics {unknown}" + overrides = overrides or {} + version = node_version() + if strip_types and version < STRIP_TYPES_MINIMUM: + pytest.skip( + f"node {version[0]}.{version[1]} lacks --experimental-strip-types; " + "the TypeScript suites need Node >= 22.6" + ) + command = ["node", "--test"] + if strip_types: + command.append("--experimental-strip-types") + command += ["--experimental-test-coverage", *tests] + result = subprocess.run( + command, cwd=ROOT, check=False, capture_output=True, text=True, timeout=timeout + ) + assert result.returncode == 0, result.stdout + result.stderr + rows: dict[str, tuple[float, float, float]] = {} + for line in result.stdout.splitlines(): + match = ROW.search(line) + if match: + label = match.group(1).replace("\u2139", " ").strip() + name = label.split("/")[-1] + rows[name] = tuple(float(match.group(i)) for i in (2, 3, 4)) + for source in sources: + name = Path(source).name + assert name in rows, ( + f"no coverage row for {source}\n" + result.stdout + result.stderr + ) + line_pct, branch_pct, funcs_pct = rows[name] + actual = {"lines": line_pct, "branches": branch_pct, "functions": funcs_pct} + floors = {**thresholds, **overrides.get(name, {})} + for metric, minimum in floors.items(): + assert actual[metric] >= minimum, ( + f"{source} {metric} coverage {actual[metric]} < {minimum}\n" + + result.stdout + ) + return result diff --git a/testing/tests/test_hermes_hux_runtime_autonomy_privacy.py b/testing/tests/test_hermes_hux_runtime_autonomy_privacy.py index 4eca12ca..5dd7c26b 100644 --- a/testing/tests/test_hermes_hux_runtime_autonomy_privacy.py +++ b/testing/tests/test_hermes_hux_runtime_autonomy_privacy.py @@ -2,38 +2,28 @@ from __future__ import annotations -import subprocess from pathlib import Path +from hux_node_gate import run_node_coverage + ROOT = Path(__file__).resolve().parents[2] RUNTIME = ROOT / "dockerfiles" / "hermes-webui-hux" / "runtime" + def test_runtime_autonomy_privacy_node_suite_and_coverage(): - result = subprocess.run( + run_node_coverage( + [ + "dockerfiles/hermes-webui-hux/runtime/autonomy-privacy.js", + ], [ - "node", - "--test", - "--experimental-test-coverage", - "--test-coverage-lines=95", - "--test-coverage-functions=95", - "--test-coverage-branches=95", - "--test-coverage-include=dockerfiles/hermes-webui-hux/runtime/autonomy-privacy.js", "testing/tests/test_hermes_hux_runtime_autonomy_privacy_node.js", "testing/tests/test_hermes_hux_runtime_stop_node.js", ], - cwd=ROOT, - check=False, - capture_output=True, - text=True, - timeout=30, + {"branches": 95, "functions": 95, "lines": 95}, + strip_types=False, ) - assert result.returncode == 0, result.stdout + result.stderr - report = next( - line for line in result.stdout.splitlines() if "autonomy-privacy.js" in line - ) - assert min(float(value) for value in report.split("|")[1:4]) >= 95.0 def test_runtime_pair_is_scoped_dependency_free_and_inert(): diff --git a/testing/tests/test_hermes_hux_ui_activity.py b/testing/tests/test_hermes_hux_ui_activity.py index 00b67f25..8efa2fb7 100644 --- a/testing/tests/test_hermes_hux_ui_activity.py +++ b/testing/tests/test_hermes_hux_ui_activity.py @@ -2,34 +2,28 @@ from __future__ import annotations -import subprocess from pathlib import Path +from hux_node_gate import run_node_coverage + ROOT = Path(__file__).resolve().parents[2] ACTIVITY = ROOT / "dockerfiles" / "hermes-webui-hux" / "activity" + def test_hux_activity_model_node_suite_and_coverage(): - result = subprocess.run( + run_node_coverage( + [ + "dockerfiles/hermes-webui-hux/activity/model.ts", + "dockerfiles/hermes-webui-hux/activity/security.ts", + ], [ - "node", - "--test", - "--experimental-strip-types", - "--experimental-test-coverage", - "--test-coverage-lines=95", - "--test-coverage-functions=95", - "--test-coverage-include=dockerfiles/hermes-webui-hux/activity/model.ts", - "--test-coverage-include=dockerfiles/hermes-webui-hux/activity/security.ts", "testing/tests/test_hermes_hux_ui_activity.mjs", ], - cwd=ROOT, - check=False, - capture_output=True, - text=True, - timeout=30, + {"functions": 95, "lines": 95}, + strip_types=True, ) - assert result.returncode == 0, result.stdout + result.stderr def test_hux_activity_component_is_flagged_accessible_and_payload_safe(): diff --git a/testing/tests/test_hermes_hux_ui_artifacts.py b/testing/tests/test_hermes_hux_ui_artifacts.py index 215e927b..33dcfc39 100644 --- a/testing/tests/test_hermes_hux_ui_artifacts.py +++ b/testing/tests/test_hermes_hux_ui_artifacts.py @@ -2,36 +2,29 @@ from __future__ import annotations -import subprocess from pathlib import Path +from hux_node_gate import run_node_coverage + ROOT = Path(__file__).resolve().parents[2] ARTIFACTS = ROOT / "dockerfiles" / "hermes-webui-hux" / "artifacts" + def test_hux_artifact_model_node_suite_and_coverage(): - result = subprocess.run( + run_node_coverage( + [ + "dockerfiles/hermes-webui-hux/artifacts/model.ts", + "dockerfiles/hermes-webui-hux/artifacts/security.ts", + "dockerfiles/hermes-webui-hux/artifacts/endpoints.ts", + ], [ - "node", - "--test", - "--experimental-strip-types", - "--experimental-test-coverage", - "--test-coverage-lines=95", - "--test-coverage-functions=95", - "--test-coverage-branches=95", - "--test-coverage-include=dockerfiles/hermes-webui-hux/artifacts/model.ts", - "--test-coverage-include=dockerfiles/hermes-webui-hux/artifacts/security.ts", - "--test-coverage-include=dockerfiles/hermes-webui-hux/artifacts/endpoints.ts", "testing/tests/test_hermes_hux_ui_artifacts.mjs", ], - cwd=ROOT, - check=False, - capture_output=True, - text=True, - timeout=30, + {"branches": 95, "functions": 95, "lines": 95}, + strip_types=True, ) - assert result.returncode == 0, result.stdout + result.stderr def test_hux_artifact_component_is_flagged_accessible_and_inert(): diff --git a/testing/tests/test_hermes_hux_ui_autonomy.py b/testing/tests/test_hermes_hux_ui_autonomy.py index f4a6910d..85f3571b 100644 --- a/testing/tests/test_hermes_hux_ui_autonomy.py +++ b/testing/tests/test_hermes_hux_ui_autonomy.py @@ -3,37 +3,31 @@ from __future__ import annotations import json -import subprocess from pathlib import Path +from hux_node_gate import run_node_coverage + ROOT = Path(__file__).resolve().parents[2] AUTONOMY = ROOT / "dockerfiles" / "hermes-webui-hux" / "autonomy" + def test_hux_autonomy_model_node_suite_and_coverage(): """Fail-closed policy decisions retain at least 95% executable coverage.""" - result = subprocess.run( + run_node_coverage( + [ + "dockerfiles/hermes-webui-hux/autonomy/model.ts", + "dockerfiles/hermes-webui-hux/autonomy/security.ts", + "dockerfiles/hermes-webui-hux/autonomy/endpoints.ts", + ], [ - "node", - "--test", - "--experimental-strip-types", - "--experimental-test-coverage", - "--test-coverage-lines=95", - "--test-coverage-functions=95", - "--test-coverage-include=dockerfiles/hermes-webui-hux/autonomy/model.ts", - "--test-coverage-include=dockerfiles/hermes-webui-hux/autonomy/security.ts", - "--test-coverage-include=dockerfiles/hermes-webui-hux/autonomy/endpoints.ts", "testing/tests/test_hermes_hux_ui_autonomy.mjs", ], - cwd=ROOT, - check=False, - capture_output=True, - text=True, - timeout=30, + {"functions": 95, "lines": 95}, + strip_types=True, ) - assert result.returncode == 0, result.stdout + result.stderr def test_hux_autonomy_component_is_accessible_flagged_and_inert(): diff --git a/testing/tests/test_hermes_hux_ui_memory.py b/testing/tests/test_hermes_hux_ui_memory.py index f936ce56..7e420a5b 100644 --- a/testing/tests/test_hermes_hux_ui_memory.py +++ b/testing/tests/test_hermes_hux_ui_memory.py @@ -2,36 +2,29 @@ from __future__ import annotations -import subprocess from pathlib import Path +from hux_node_gate import run_node_coverage + ROOT = Path(__file__).resolve().parents[2] MEMORY = ROOT / "dockerfiles" / "hermes-webui-hux" / "memory" + def test_hux_memory_model_node_suite_and_coverage(): - result = subprocess.run( + run_node_coverage( + [ + "dockerfiles/hermes-webui-hux/memory/model.ts", + "dockerfiles/hermes-webui-hux/memory/security.ts", + "dockerfiles/hermes-webui-hux/memory/endpoints.ts", + ], [ - "node", - "--test", - "--experimental-strip-types", - "--experimental-test-coverage", - "--test-coverage-lines=95", - "--test-coverage-functions=95", - "--test-coverage-branches=95", - "--test-coverage-include=dockerfiles/hermes-webui-hux/memory/model.ts", - "--test-coverage-include=dockerfiles/hermes-webui-hux/memory/security.ts", - "--test-coverage-include=dockerfiles/hermes-webui-hux/memory/endpoints.ts", "testing/tests/test_hermes_hux_ui_memory.mjs", ], - cwd=ROOT, - check=False, - capture_output=True, - text=True, - timeout=30, + {"branches": 95, "functions": 95, "lines": 95}, + strip_types=True, ) - assert result.returncode == 0, result.stdout + result.stderr def test_hux_memory_component_is_flagged_accessible_and_privacy_safe(): diff --git a/testing/tests/test_hermes_hux_ui_modes.py b/testing/tests/test_hermes_hux_ui_modes.py index fed65777..c2469ab4 100644 --- a/testing/tests/test_hermes_hux_ui_modes.py +++ b/testing/tests/test_hermes_hux_ui_modes.py @@ -3,35 +3,29 @@ from __future__ import annotations import json -import subprocess from pathlib import Path +from hux_node_gate import run_node_coverage + ROOT = Path(__file__).resolve().parents[2] MODES = ROOT / "dockerfiles" / "hermes-webui-hux" / "modes" + def test_hux_modes_model_node_suite_and_coverage(): """Mode intent validation is covered above the repository threshold.""" - result = subprocess.run( + run_node_coverage( + [ + "dockerfiles/hermes-webui-hux/modes/model.ts", + ], [ - "node", - "--test", - "--experimental-strip-types", - "--experimental-test-coverage", - "--test-coverage-lines=95", - "--test-coverage-functions=95", - "--test-coverage-include=dockerfiles/hermes-webui-hux/modes/model.ts", "testing/tests/test_hermes_hux_ui_modes.mjs", ], - cwd=ROOT, - check=False, - capture_output=True, - text=True, - timeout=30, + {"functions": 95, "lines": 95}, + strip_types=True, ) - assert result.returncode == 0, result.stdout + result.stderr def test_hux_modes_component_is_flagged_accessible_and_provider_neutral(): diff --git a/testing/tests/test_hermes_hux_ui_multimodal.py b/testing/tests/test_hermes_hux_ui_multimodal.py index 359cda4a..cebbe098 100644 --- a/testing/tests/test_hermes_hux_ui_multimodal.py +++ b/testing/tests/test_hermes_hux_ui_multimodal.py @@ -2,36 +2,29 @@ from __future__ import annotations -import subprocess from pathlib import Path +from hux_node_gate import run_node_coverage + ROOT = Path(__file__).resolve().parents[2] MULTIMODAL = ROOT / "dockerfiles" / "hermes-webui-hux" / "multimodal" + def test_hux_multimodal_model_node_suite_and_coverage(): - result = subprocess.run( + run_node_coverage( + [ + "dockerfiles/hermes-webui-hux/multimodal/model.ts", + "dockerfiles/hermes-webui-hux/multimodal/security.ts", + "dockerfiles/hermes-webui-hux/multimodal/endpoints.ts", + ], [ - "node", - "--test", - "--experimental-strip-types", - "--experimental-test-coverage", - "--test-coverage-lines=95", - "--test-coverage-functions=95", - "--test-coverage-branches=95", - "--test-coverage-include=dockerfiles/hermes-webui-hux/multimodal/model.ts", - "--test-coverage-include=dockerfiles/hermes-webui-hux/multimodal/security.ts", - "--test-coverage-include=dockerfiles/hermes-webui-hux/multimodal/endpoints.ts", "testing/tests/test_hermes_hux_ui_multimodal.mjs", ], - cwd=ROOT, - check=False, - capture_output=True, - text=True, - timeout=30, + {"branches": 95, "functions": 95, "lines": 95}, + strip_types=True, ) - assert result.returncode == 0, result.stdout + result.stderr def test_hux_multimodal_component_is_flagged_accessible_safe_and_inert(): diff --git a/testing/tests/test_hermes_hux_ui_onboarding.py b/testing/tests/test_hermes_hux_ui_onboarding.py index 7f6d90cb..1467d686 100644 --- a/testing/tests/test_hermes_hux_ui_onboarding.py +++ b/testing/tests/test_hermes_hux_ui_onboarding.py @@ -3,38 +3,31 @@ from __future__ import annotations import json -import subprocess from pathlib import Path +from hux_node_gate import run_node_coverage + ROOT = Path(__file__).resolve().parents[2] ONBOARDING = ROOT / "dockerfiles" / "hermes-webui-hux" / "onboarding" + def test_hux_onboarding_node_suite_and_coverage(): """Suggestion validation and transport remain above the repository gate.""" - result = subprocess.run( + run_node_coverage( + [ + "dockerfiles/hermes-webui-hux/onboarding/client.ts", + "dockerfiles/hermes-webui-hux/onboarding/model.ts", + "dockerfiles/hermes-webui-hux/onboarding/security.ts", + ], [ - "node", - "--test", - "--experimental-strip-types", - "--experimental-test-coverage", - "--test-coverage-lines=95", - "--test-coverage-functions=95", - "--test-coverage-branches=95", - "--test-coverage-include=dockerfiles/hermes-webui-hux/onboarding/client.ts", - "--test-coverage-include=dockerfiles/hermes-webui-hux/onboarding/model.ts", - "--test-coverage-include=dockerfiles/hermes-webui-hux/onboarding/security.ts", "testing/tests/test_hermes_hux_ui_onboarding.mjs", ], - cwd=ROOT, - check=False, - capture_output=True, - text=True, - timeout=30, + {"branches": 95, "functions": 95, "lines": 95}, + strip_types=True, ) - assert result.returncode == 0, result.stdout + result.stderr def test_hux_onboarding_matches_schema_and_is_inert(): diff --git a/testing/tests/test_hermes_hux_ui_organization.py b/testing/tests/test_hermes_hux_ui_organization.py index 975705cf..b0b815c2 100644 --- a/testing/tests/test_hermes_hux_ui_organization.py +++ b/testing/tests/test_hermes_hux_ui_organization.py @@ -2,36 +2,29 @@ from __future__ import annotations -import subprocess from pathlib import Path +from hux_node_gate import run_node_coverage + ROOT = Path(__file__).resolve().parents[2] ORGANIZATION = ROOT / "dockerfiles" / "hermes-webui-hux" / "organization" + def test_hux_organization_node_suite_and_line_branch_coverage(): - result = subprocess.run( + run_node_coverage( + [ + "dockerfiles/hermes-webui-hux/organization/client.ts", + "dockerfiles/hermes-webui-hux/organization/model.ts", + "dockerfiles/hermes-webui-hux/organization/security.ts", + ], [ - "node", - "--test", - "--experimental-strip-types", - "--experimental-test-coverage", - "--test-coverage-lines=95", - "--test-coverage-branches=95", - "--test-coverage-functions=95", - "--test-coverage-include=dockerfiles/hermes-webui-hux/organization/client.ts", - "--test-coverage-include=dockerfiles/hermes-webui-hux/organization/model.ts", - "--test-coverage-include=dockerfiles/hermes-webui-hux/organization/security.ts", "testing/tests/test_hermes_hux_ui_organization.mjs", ], - cwd=ROOT, - check=False, - capture_output=True, - text=True, - timeout=30, + {"branches": 95, "functions": 95, "lines": 95}, + strip_types=True, ) - assert result.returncode == 0, result.stdout + result.stderr def test_hux_organization_component_is_flagged_accessible_and_scope_safe(): diff --git a/testing/tests/test_hermes_hux_ui_privacy.py b/testing/tests/test_hermes_hux_ui_privacy.py index f13197f5..247cbf09 100644 --- a/testing/tests/test_hermes_hux_ui_privacy.py +++ b/testing/tests/test_hermes_hux_ui_privacy.py @@ -3,42 +3,31 @@ from __future__ import annotations import json -import subprocess from pathlib import Path +from hux_node_gate import run_node_coverage + ROOT = Path(__file__).resolve().parents[2] PRIVACY = ROOT / "dockerfiles" / "hermes-webui-hux" / "privacy" + def test_hux_privacy_node_suite_and_per_source_coverage(): """Privacy adapters and transport remain above the repository gate.""" - result = subprocess.run( + run_node_coverage( + [ + "dockerfiles/hermes-webui-hux/privacy/client.ts", + "dockerfiles/hermes-webui-hux/privacy/model.ts", + "dockerfiles/hermes-webui-hux/privacy/security.ts", + ], [ - "node", - "--test", - "--experimental-strip-types", - "--experimental-test-coverage", - "--test-coverage-lines=95", - "--test-coverage-functions=95", - "--test-coverage-branches=95", - "--test-coverage-include=dockerfiles/hermes-webui-hux/privacy/client.ts", - "--test-coverage-include=dockerfiles/hermes-webui-hux/privacy/model.ts", - "--test-coverage-include=dockerfiles/hermes-webui-hux/privacy/security.ts", "testing/tests/test_hermes_hux_ui_privacy.mjs", ], - cwd=ROOT, - check=False, - capture_output=True, - text=True, - timeout=30, + {"branches": 95, "functions": 95, "lines": 95}, + strip_types=True, ) - assert result.returncode == 0, result.stdout + result.stderr - for row in ("client.ts", "model.ts", "security.ts"): - report = next(line for line in result.stdout.splitlines() if row in line) - percentages = [float(part) for part in report.split("|")[1:4]] - assert min(percentages) >= 95.0, report def test_hux_privacy_matches_contract_and_stays_inert(): diff --git a/testing/tests/test_hermes_hux_ui_research.py b/testing/tests/test_hermes_hux_ui_research.py index 4b3474e5..eef458dd 100644 --- a/testing/tests/test_hermes_hux_ui_research.py +++ b/testing/tests/test_hermes_hux_ui_research.py @@ -3,36 +3,29 @@ from __future__ import annotations import json -import subprocess from pathlib import Path +from hux_node_gate import run_node_coverage + ROOT = Path(__file__).resolve().parents[2] RESEARCH = ROOT / "dockerfiles" / "hermes-webui-hux" / "research" + def test_hux_research_node_suite_and_coverage(): - result = subprocess.run( + run_node_coverage( + [ + "dockerfiles/hermes-webui-hux/research/model.ts", + "dockerfiles/hermes-webui-hux/research/security.ts", + "dockerfiles/hermes-webui-hux/research/endpoints.ts", + ], [ - "node", - "--test", - "--experimental-strip-types", - "--experimental-test-coverage", - "--test-coverage-lines=95", - "--test-coverage-functions=95", - "--test-coverage-branches=95", - "--test-coverage-include=dockerfiles/hermes-webui-hux/research/model.ts", - "--test-coverage-include=dockerfiles/hermes-webui-hux/research/security.ts", - "--test-coverage-include=dockerfiles/hermes-webui-hux/research/endpoints.ts", "testing/tests/test_hermes_hux_ui_research.mjs", ], - cwd=ROOT, - check=False, - capture_output=True, - text=True, - timeout=30, + {"branches": 95, "functions": 95, "lines": 95}, + strip_types=True, ) - assert result.returncode == 0, result.stdout + result.stderr def test_hux_research_matches_shared_contract_and_stays_default_off(): diff --git a/testing/tests/test_hermes_hux_ui_runtime_wave_a.py b/testing/tests/test_hermes_hux_ui_runtime_wave_a.py index 011e2ad6..2bf4b8df 100644 --- a/testing/tests/test_hermes_hux_ui_runtime_wave_a.py +++ b/testing/tests/test_hermes_hux_ui_runtime_wave_a.py @@ -2,34 +2,28 @@ from __future__ import annotations -import subprocess from pathlib import Path +from hux_node_gate import run_node_coverage + ROOT = Path(__file__).resolve().parents[2] RUNTIME = ROOT / "dockerfiles" / "hermes-webui-hux" / "runtime" + def test_hux_wave_a_vanilla_runtime_and_coverage(): - result = subprocess.run( + run_node_coverage( + [ + "dockerfiles/hermes-webui-hux/runtime/wave_a_contract.js", + "dockerfiles/hermes-webui-hux/runtime/wave_a_activity_memory.js", + ], [ - "node", - "--test", - "--experimental-test-coverage", - "--test-coverage-lines=95", - "--test-coverage-functions=95", - "--test-coverage-branches=95", - "--test-coverage-include=dockerfiles/hermes-webui-hux/runtime/wave_a_contract.js", - "--test-coverage-include=dockerfiles/hermes-webui-hux/runtime/wave_a_activity_memory.js", "testing/tests/test_hermes_hux_ui_runtime_wave_a.js", ], - cwd=ROOT, - check=False, - capture_output=True, - text=True, - timeout=30, + {"branches": 95, "functions": 95, "lines": 95}, + strip_types=False, ) - assert result.returncode == 0, result.stdout + result.stderr def test_wave_a_runtime_is_dependency_free_scoped_and_not_live_wired(): diff --git a/testing/tests/test_hermes_hux_ui_runtime_wave_b.py b/testing/tests/test_hermes_hux_ui_runtime_wave_b.py index 7eb5912b..bda2e5b7 100644 --- a/testing/tests/test_hermes_hux_ui_runtime_wave_b.py +++ b/testing/tests/test_hermes_hux_ui_runtime_wave_b.py @@ -2,13 +2,15 @@ from __future__ import annotations -import subprocess from pathlib import Path +from hux_node_gate import run_node_coverage + ROOT = Path(__file__).resolve().parents[2] RUNTIME = ROOT / "dockerfiles" / "hermes-webui-hux" / "runtime" PRODUCTION = ( + RUNTIME / "wave_b_contract.js", RUNTIME / "wave_b_projects_modes.js", RUNTIME / "wave_b_artifacts_research.js", @@ -17,33 +19,22 @@ PRODUCTION = ( def test_hux_wave_b_vanilla_runtime_and_per_source_coverage(): - includes = [ - option - for path in PRODUCTION - for option in ( - "--test-coverage-include", - str(path.relative_to(ROOT)), - ) - ] - result = subprocess.run( + run_node_coverage( + [ + "dockerfiles/hermes-webui-hux/runtime/wave_b_contract.js", + "dockerfiles/hermes-webui-hux/runtime/wave_b_projects_modes.js", + "dockerfiles/hermes-webui-hux/runtime/wave_b_artifacts_research.js", + "dockerfiles/hermes-webui-hux/runtime/wave_b_runtime.js", + ], [ - "node", - "--test", - "--experimental-test-coverage", - "--test-coverage-lines=95", - "--test-coverage-functions=95", - "--test-coverage-branches=95", - *includes, "testing/tests/test_hermes_hux_ui_runtime_wave_b_contract.js", "testing/tests/test_hermes_hux_ui_runtime_wave_b_dom.js", ], - cwd=ROOT, - check=False, - capture_output=True, - text=True, - timeout=30, + {"branches": 95, "functions": 95, "lines": 95}, + strip_types=False, + # Pre-existing debt the old aggregate gate hid; floors still enforced. + overrides={"wave_b_projects_modes.js": {"branches": 90.0, "functions": 94.7}}, ) - assert result.returncode == 0, result.stdout + result.stderr def test_wave_b_uses_only_canonical_scoped_routes_and_concurrency_headers(): diff --git a/testing/tests/test_hermes_webui_hux_integration.py b/testing/tests/test_hermes_webui_hux_integration.py index ee7dc88d..6dc67b19 100644 --- a/testing/tests/test_hermes_webui_hux_integration.py +++ b/testing/tests/test_hermes_webui_hux_integration.py @@ -4,6 +4,8 @@ from __future__ import annotations import importlib.util from pathlib import Path + +from hux_node_gate import run_node_coverage import shutil import subprocess @@ -15,6 +17,7 @@ PATCHER = ROOT / "dockerfiles/hermes-webui-hux-patch.py" BOOTSTRAP = ROOT / "dockerfiles/hermes-webui-hux/bootstrap.js" BOOTSTRAP_STYLE = ROOT / "dockerfiles/hermes-webui-hux/bootstrap.css" NODE_TEST = ROOT / "testing/tests/test_hermes_webui_hux_integration_node.js" + FIXTURE = ROOT / "testing/fixtures/hermes-webui-0.52.181" @@ -49,14 +52,16 @@ def _fixture(tmp_path: Path, module) -> Path: def test_browser_bootstrap_per_source_line_and_branch_coverage() -> None: - result = subprocess.run( - ["node", "--test", "--experimental-test-coverage", - "--test-coverage-lines=95", "--test-coverage-functions=95", - "--test-coverage-branches=95", "--test-coverage-include", - str(BOOTSTRAP.relative_to(ROOT)), str(NODE_TEST.relative_to(ROOT))], - cwd=ROOT, check=False, capture_output=True, text=True, timeout=30, + run_node_coverage( + [ + "dockerfiles/hermes-webui-hux/bootstrap.js", + ], + [ + "testing/tests/test_hermes_webui_hux_integration_node.js", + ], + {"branches": 95, "functions": 95, "lines": 95}, + strip_types=False, ) - assert result.returncode == 0, result.stdout + result.stderr def test_patcher_installs_all_assets_atomically_and_rejects_drift(tmp_path: Path) -> None: