Skip to content

Commit 38789de

Browse files
howethomasclaude
andcommitted
fix: Strip ANSI codes in tests to handle Rich color output on CI
Add strip_ansi helper function to remove ANSI escape codes from CLI output before assertions. Rich/Typer outputs color codes that split option names like --build into separate strings, causing test failures. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 3a26be3 commit 38789de

File tree

5 files changed

+81
-32
lines changed

5 files changed

+81
-32
lines changed

tests/test_cli.py

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,20 @@
22
CLI integration tests for Conserver.
33
"""
44

5+
import re
6+
57
from typer.testing import CliRunner
68

79
from conserver import __version__
810
from conserver.cli import app
911

1012

13+
def strip_ansi(text: str) -> str:
14+
"""Strip ANSI escape codes from text."""
15+
ansi_pattern = re.compile(r"\x1b\[[0-9;]*m")
16+
return ansi_pattern.sub("", text)
17+
18+
1119
def test_version(cli_runner: CliRunner) -> None:
1220
"""Test --version flag."""
1321
result = cli_runner.invoke(app, ["--version"])
@@ -30,68 +38,76 @@ def test_start_help(cli_runner: CliRunner) -> None:
3038
"""Test start command help."""
3139
result = cli_runner.invoke(app, ["start", "--help"])
3240
assert result.exit_code == 0
33-
assert "--build" in result.stdout
34-
assert "--detach" in result.stdout
35-
assert "--services" in result.stdout
41+
output = strip_ansi(result.stdout)
42+
assert "--build" in output
43+
assert "--detach" in output
44+
assert "--services" in output
3645

3746

3847
def test_stop_help(cli_runner: CliRunner) -> None:
3948
"""Test stop command help."""
4049
result = cli_runner.invoke(app, ["stop", "--help"])
4150
assert result.exit_code == 0
42-
assert "--remove" in result.stdout
43-
assert "--volumes" in result.stdout
44-
assert "--timeout" in result.stdout
51+
output = strip_ansi(result.stdout)
52+
assert "--remove" in output
53+
assert "--volumes" in output
54+
assert "--timeout" in output
4555

4656

4757
def test_status_help(cli_runner: CliRunner) -> None:
4858
"""Test status command help."""
4959
result = cli_runner.invoke(app, ["status", "--help"])
5060
assert result.exit_code == 0
51-
assert "--format" in result.stdout
52-
assert "--all" in result.stdout
53-
assert "--watch" in result.stdout
61+
output = strip_ansi(result.stdout)
62+
assert "--format" in output
63+
assert "--all" in output
64+
assert "--watch" in output
5465

5566

5667
def test_config_help(cli_runner: CliRunner) -> None:
5768
"""Test config command help."""
5869
result = cli_runner.invoke(app, ["config", "--help"])
5970
assert result.exit_code == 0
60-
assert "show" in result.stdout
61-
assert "edit" in result.stdout
62-
assert "set" in result.stdout
63-
assert "validate" in result.stdout
64-
assert "init" in result.stdout
71+
output = strip_ansi(result.stdout)
72+
assert "show" in output
73+
assert "edit" in output
74+
assert "set" in output
75+
assert "validate" in output
76+
assert "init" in output
6577

6678

6779
def test_config_show_help(cli_runner: CliRunner) -> None:
6880
"""Test config show command help."""
6981
result = cli_runner.invoke(app, ["config", "show", "--help"])
7082
assert result.exit_code == 0
71-
assert "--file" in result.stdout
72-
assert "--secrets" in result.stdout
83+
output = strip_ansi(result.stdout)
84+
assert "--file" in output
85+
assert "--secrets" in output
7386

7487

7588
def test_logs_help(cli_runner: CliRunner) -> None:
7689
"""Test logs command help."""
7790
result = cli_runner.invoke(app, ["logs", "--help"])
7891
assert result.exit_code == 0
79-
assert "--follow" in result.stdout
80-
assert "--tail" in result.stdout
81-
assert "--since" in result.stdout
92+
output = strip_ansi(result.stdout)
93+
assert "--follow" in output
94+
assert "--tail" in output
95+
assert "--since" in output
8296

8397

8498
def test_health_help(cli_runner: CliRunner) -> None:
8599
"""Test health command help."""
86100
result = cli_runner.invoke(app, ["health", "--help"])
87101
assert result.exit_code == 0
88-
assert "--verbose" in result.stdout
102+
output = strip_ansi(result.stdout)
103+
assert "--verbose" in output
89104

90105

91106
def test_upgrade_help(cli_runner: CliRunner) -> None:
92107
"""Test upgrade command help."""
93108
result = cli_runner.invoke(app, ["upgrade", "--help"])
94109
assert result.exit_code == 0
95-
assert "--pull" in result.stdout
96-
assert "--backup" in result.stdout
97-
assert "--dry-run" in result.stdout
110+
output = strip_ansi(result.stdout)
111+
assert "--pull" in output
112+
assert "--backup" in output
113+
assert "--dry-run" in output

tests/test_commands/test_config.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Tests for config commands.
33
"""
44

5+
import re
56
from pathlib import Path
67
from unittest.mock import MagicMock, patch
78

@@ -10,15 +11,22 @@
1011
from conserver.cli import app
1112

1213

14+
def strip_ansi(text: str) -> str:
15+
"""Strip ANSI escape codes from text."""
16+
ansi_pattern = re.compile(r"\x1b\[[0-9;]*m")
17+
return ansi_pattern.sub("", text)
18+
19+
1320
class TestConfigShowCommand:
1421
"""Tests for the config show command."""
1522

1623
def test_config_show_help(self, cli_runner: CliRunner) -> None:
1724
"""Test config show command shows help."""
1825
result = cli_runner.invoke(app, ["config", "show", "--help"])
1926
assert result.exit_code == 0
20-
assert "--file" in result.stdout
21-
assert "--secrets" in result.stdout
27+
output = strip_ansi(result.stdout)
28+
assert "--file" in output
29+
assert "--secrets" in output
2230

2331
@patch("conserver.commands.config.DockerOps")
2432
def test_config_show_env(
@@ -210,7 +218,8 @@ def test_config_init_help(self, cli_runner: CliRunner) -> None:
210218
"""Test config init command shows help."""
211219
result = cli_runner.invoke(app, ["config", "init", "--help"])
212220
assert result.exit_code == 0
213-
assert "--overwrite" in result.stdout
221+
output = strip_ansi(result.stdout)
222+
assert "--overwrite" in output
214223

215224
@patch("conserver.commands.config.DockerOps")
216225
def test_config_init_creates_files(

tests/test_commands/test_start.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Tests for start command.
33
"""
44

5+
import re
56
from pathlib import Path
67
from unittest.mock import MagicMock, patch
78

@@ -10,15 +11,22 @@
1011
from conserver.cli import app
1112

1213

14+
def strip_ansi(text: str) -> str:
15+
"""Strip ANSI escape codes from text."""
16+
ansi_pattern = re.compile(r"\x1b\[[0-9;]*m")
17+
return ansi_pattern.sub("", text)
18+
19+
1320
class TestStartCommand:
1421
"""Tests for the start command."""
1522

1623
def test_start_help(self, cli_runner: CliRunner) -> None:
1724
"""Test start command shows help."""
1825
result = cli_runner.invoke(app, ["start", "--help"])
1926
assert result.exit_code == 0
20-
assert "--build" in result.stdout
21-
assert "--services" in result.stdout
27+
output = strip_ansi(result.stdout)
28+
assert "--build" in output
29+
assert "--services" in output
2230

2331
@patch("conserver.commands.start.DockerOps")
2432
@patch("conserver.commands.start.HealthChecker")

tests/test_commands/test_status.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Tests for status command.
33
"""
44

5+
import re
56
from pathlib import Path
67
from unittest.mock import MagicMock, patch
78

@@ -11,15 +12,22 @@
1112
from conserver.docker_ops import ContainerInfo
1213

1314

15+
def strip_ansi(text: str) -> str:
16+
"""Strip ANSI escape codes from text."""
17+
ansi_pattern = re.compile(r"\x1b\[[0-9;]*m")
18+
return ansi_pattern.sub("", text)
19+
20+
1421
class TestStatusCommand:
1522
"""Tests for the status command."""
1623

1724
def test_status_help(self, cli_runner: CliRunner) -> None:
1825
"""Test status command shows help."""
1926
result = cli_runner.invoke(app, ["status", "--help"])
2027
assert result.exit_code == 0
21-
assert "--format" in result.stdout
22-
assert "--all" in result.stdout
28+
output = strip_ansi(result.stdout)
29+
assert "--format" in output
30+
assert "--all" in output
2331

2432
@patch("conserver.commands.status.DockerOps")
2533
def test_status_no_containers(

tests/test_commands/test_stop.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Tests for stop command.
33
"""
44

5+
import re
56
from pathlib import Path
67
from unittest.mock import MagicMock, patch
78

@@ -10,15 +11,22 @@
1011
from conserver.cli import app
1112

1213

14+
def strip_ansi(text: str) -> str:
15+
"""Strip ANSI escape codes from text."""
16+
ansi_pattern = re.compile(r"\x1b\[[0-9;]*m")
17+
return ansi_pattern.sub("", text)
18+
19+
1320
class TestStopCommand:
1421
"""Tests for the stop command."""
1522

1623
def test_stop_help(self, cli_runner: CliRunner) -> None:
1724
"""Test stop command shows help."""
1825
result = cli_runner.invoke(app, ["stop", "--help"])
1926
assert result.exit_code == 0
20-
assert "--remove" in result.stdout
21-
assert "--volumes" in result.stdout
27+
output = strip_ansi(result.stdout)
28+
assert "--remove" in output
29+
assert "--volumes" in output
2230

2331
@patch("conserver.commands.stop.DockerOps")
2432
def test_stop_no_containers(

0 commit comments

Comments
 (0)