From 44abc1cbdc05fad059dc0c6c9540c40d6d534768 Mon Sep 17 00:00:00 2001 From: Sue the Coder Date: Wed, 9 Sep 2026 10:16:15 -0700 Subject: [PATCH] test(cli): normalise rich-panel output before asserting on BadParameter text test_harness_and_legacy_agent_are_mutually_exclusive has failed on CI since f72f815 while passing locally. The message is raised as typer.BadParameter, which typer renders through a rich panel; typer's rich_utils sets force_terminal=True whenever GITHUB_ACTIONS (or FORCE_COLOR / PY_COLORS) is set, so on Actions the panel is coloured and wrapped at the default 80 columns with no terminal attached, and the asserted substring is split across two bordered lines. Locally none of those variables is set, the panel is not forced, and the assertion passes. Reproduced with poetry.lock's typer 0.26.2 / rich 14.2.0: GITHUB_ACTIONS=true alone flips the test from pass to fail. Add a _plain_output() helper that strips ANSI escapes and box-drawing characters and collapses whitespace, and assert against that. The sibling test at line 227 goes through typer.echo, not a panel, and is unaffected. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01StcQgXQDE4F6eJer1sEXRb --- tests/test_cli.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index 49b8082..72b3d2a 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -2,6 +2,7 @@ import json import os +import re import subprocess from pathlib import Path from types import SimpleNamespace @@ -16,6 +17,24 @@ from sucoder import cli from sucoder.config import BranchPrefixes, Config, MirrorSettings + +_ANSI_ESCAPE = re.compile(r"\x1b\[[0-9;?]*[ -/]*[@-~]") +_BOX_DRAWING = re.compile(r"[\u2500-\u257f]") + + +def _plain_output(result) -> str: + """CLI output with styling, panel borders, and line wraps removed. + + typer renders ``BadParameter`` through a rich panel and forces terminal + mode when ``GITHUB_ACTIONS`` (or ``FORCE_COLOR``) is set, so under CI the + message is coloured and wrapped at 80 columns even though no terminal is + attached. A substring assertion on the raw output therefore depends on + the console width; assert against this normalised text instead. + """ + text = _ANSI_ESCAPE.sub("", result.output) + text = _BOX_DRAWING.sub(" ", text) + return " ".join(text.split()) + try: from click.shell_completion import CompletionItem as ClickCompletionItem except (ImportError, AttributeError): # pragma: no cover - defensive @@ -414,7 +433,7 @@ def test_harness_and_legacy_agent_are_mutually_exclusive(tmp_path, monkeypatch): ) assert result.exit_code != 0 - assert "either --harness or the legacy --agent" in result.output + assert "either --harness or the legacy --agent" in _plain_output(result) def test_skills_list_reports_accessible_paths(tmp_path, monkeypatch):