From c87bee50c99366a0b0f32784f735fda6eb67bfef Mon Sep 17 00:00:00 2001 From: Athul Date: Tue, 20 Oct 2026 10:34:48 +0530 Subject: [PATCH] UN-4469 [FIX] Skip optional Node groups whose node_modules is missing The `ui` Playwright group has reported 1 error and 0 tests on every CI run since it was added in #2212: CI has npx but never installs tests/e2e/ui, so `npx --no-install playwright test` aborts. groups.yaml documents that a missing install must skip this optional group, but the rig only skipped when npx itself was absent. Optional vitest/playwright groups now skip (exit 5) when their workdir has no node_modules. Required groups such as `frontend` still run and fail, so a dropped install step stays red. Co-Authored-By: Claude Opus 5.5 --- tests/rig/cli.py | 11 ++++++++ tests/rig/tests/test_cli.py | 51 +++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/tests/rig/cli.py b/tests/rig/cli.py index 6c4f2e1605..89ebca7139 100644 --- a/tests/rig/cli.py +++ b/tests/rig/cli.py @@ -1238,6 +1238,17 @@ def _node_command( ) return ["sh", "-c", "exit 5"] + if group.optional and not (group.absolute_workdir() / "node_modules").is_dir(): + # An optional suite nobody installed (CI never installs `ui`) would + # otherwise make `npx --no-install` abort and read as an error on every + # run. Required groups fall through, so a missing install stays red. + print( + f"[rig] {group.workdir}/node_modules not found; skipping optional " + f"{group.name} (runner={group.runner})", + file=sys.stderr, + ) + return ["sh", "-c", "exit 5"] + if group.runner == "vitest": cmd = [ "npx", diff --git a/tests/rig/tests/test_cli.py b/tests/rig/tests/test_cli.py index 9f755f93b7..1aca63748e 100644 --- a/tests/rig/tests/test_cli.py +++ b/tests/rig/tests/test_cli.py @@ -916,6 +916,57 @@ def test_node_command_without_npx_collects_nothing( ] +def _node_group(workdir: Path, *, optional: bool): + from tests.rig.groups import GroupDefinition + + return GroupDefinition( + name="ui", tier="e2e", paths=(".",), runner="playwright", + workdir=str(workdir), optional=optional, + ) + + +def test_node_command_optional_group_without_node_modules_collects_nothing( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + """CI has npx but never installs an optional suite's packages, so + `npx --no-install` aborts and the group reads as an error on every run. + An optional group must skip instead, as `groups.yaml` documents. + """ + import tests.rig.cli as cli_mod + + monkeypatch.setattr(cli_mod.shutil, "which", lambda _: "/usr/bin/npx") + group = _node_group(tmp_path, optional=True) + assert cli_mod._node_command(group, junit=tmp_path / "junit.xml") == [ + "sh", "-c", "exit 5", + ] + + +def test_node_command_required_group_without_node_modules_still_runs( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + """A required group (e.g. `frontend`) whose install step went missing must + stay red, not skip quietly. + """ + import tests.rig.cli as cli_mod + + monkeypatch.setattr(cli_mod.shutil, "which", lambda _: "/usr/bin/npx") + group = _node_group(tmp_path, optional=False) + cmd = cli_mod._node_command(group, junit=tmp_path / "junit.xml") + assert cmd[:4] == ["npx", "--no-install", "playwright", "test"] + + +def test_node_command_optional_group_with_node_modules_runs( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + import tests.rig.cli as cli_mod + + monkeypatch.setattr(cli_mod.shutil, "which", lambda _: "/usr/bin/npx") + (tmp_path / "node_modules").mkdir() + group = _node_group(tmp_path, optional=True) + cmd = cli_mod._node_command(group, junit=tmp_path / "junit.xml") + assert cmd[:4] == ["npx", "--no-install", "playwright", "test"] + + def _make_group(name: str, workdir: str): from tests.rig.groups import GroupDefinition