test(output): add direct unit tests for app/output.py (#871)#1169
test(output): add direct unit tests for app/output.py (#871)#1169rrajan94 merged 2 commits intoTracer-Cloud:mainfrom
Conversation
Cover get_output_format(), _humanise_message(), _fmt_timing(), and ProgressTracker.start()/complete() in text mode. Tests are deterministic (env vars scrubbed via autouse fixture, time.monotonic patched, output format forced to text) so no real TTY is required.
Greptile SummaryAdds Confidence Score: 5/5Safe to merge — adds deterministic unit tests with no production code changes. All findings are P2 style suggestions. The test logic, clock arithmetic, fixture ordering, and expected values are all correct. No production code is modified. No files require special attention. Important Files Changed
Sequence DiagramsequenceDiagram
participant T as Test
participant F as Fixtures
participant O as app/output.py
participant R as tool registry
Note over F: autouse: _clear_output_env<br/>(deletes env vars)
Note over F: per-test: force_text_mode<br/>(sets TRACER_OUTPUT_FORMAT=text)
T->>O: get_output_format()
O-->>T: "text" / "rich" / env override
T->>O: _humanise_message(msg)
O->>R: resolve_tool_display_name(action)
R-->>O: display name
O-->>T: humanised string
T->>O: _fmt_timing(elapsed_ms)
O-->>T: "Nms" or "N.Ns"
T->>O: ProgressTracker()
Note over O: reads get_output_format()<br/>at __init__ time → _rich=False
T->>O: tracker.start(node)
O-->>T: print(" … Label")
Note over T: monkeypatch time.monotonic → clock iter
T->>O: tracker.complete(node)
O-->>T: print(" ● Label Xms msg")
T->>O: get_tracker(reset=True)
O-->>T: new ProgressTracker singleton
T->>O: reset_tracker()
O-->>T: new ProgressTracker singleton
Reviews (1): Last reviewed commit: "test(output): add direct unit tests for ..." | Re-trigger Greptile |
Address review feedback on PR Tracer-Cloud#1169: - Autouse fixture now also resets ``app.output._tracker`` so a tracker created in one test cannot leak its ``_rich`` flag into later tests in the broader suite. - Reword the ``time.monotonic`` clock comment so it accurately describes ``dict.pop``'s unconditional default-expression evaluation rather than attributing it to "eager" call semantics.
|
@davincios @VaibhavUpreti kindly review |
|
Validated locally: |
|
🌊 Merged. @Davidson3556 is now permanently woven into git history. No take-backs. 😄 👋 Join us on Discord - OpenSRE : hang out, contribute, or hunt for features and issues. Everyone's welcome. |

Fixes #871
Describe the changes you have made in this PR -
Adds a direct unit test module for
app/output.pyattests/test_output.py.The module previously had no dedicated tests despite controlling progress
spinners, output-format selection, and humanised messages.
Coverage added:
get_output_format()— explicit override, NO_COLOR (set and empty),SLACK_WEBHOOK_URL, TTY/non-TTY, override precedence over NO_COLOR.
_humanise_message()— empty input, registered tool display names,fallback for unknown tools, "No new actions" collapse, integrations
list extraction, validity → confidence formatting, datadog: prefix
stripping, unrecognised pass-through.
_fmt_timing()— parametrised across the ms/seconds boundary(0, 1, 250, 999, 1000, 1500, 12345).
ProgressTracker.start()andcomplete()in text mode — node label,ellipsis prefix, fallback label for unknown nodes, dot marker, timing,
humanised message rendering, recorded events, plus the error path
(
✗marker),update_subtextno-op in text mode, singleton/resetbehaviour, and
ProgressEventdataclass defaults.Tests are deterministic: env vars are scrubbed via an autouse fixture,
time.monotonicis monkeypatched where elapsed time matters, and theoutput format is forced to
textviaTRACER_OUTPUT_FORMATso no realTTY is required.
Demo/Screenshot for feature changes and bug fixes -
Code Understanding and AI Usage
Did you use AI assistance (ChatGPT, Claude, Copilot, etc.) to write any part of this code?
If you used AI assistance:
Explain your implementation approach:
The problem:
app/output.pyhad no direct test module, so refactors tothe progress tracker, format detection, or message humanisation could
silently break the CLI's output without a failing test.
Approach: a single
tests/test_output.pythat exercises each public/helper function directly, instead of going through the graph runner.
Helpers like
_humanise_messageand_fmt_timingare pure functions,so they get straightforward input/output assertions (parametrised for
_fmt_timingto keep the boundary cases obvious).For
ProgressTracker, the tracker has two render paths (rich spinnervs plain text). The issue scope is text mode only — testing the rich
spinner would mean asserting on threaded ANSI output, which is exactly
the kind of brittle terminal snapshot the issue tells us to avoid. So
the tests force
TRACER_OUTPUT_FORMAT=textvia a fixture and asserton the captured
print()output (with ANSI codes stripped).Determinism comes from three things: an autouse fixture that scrubs
the env vars
get_output_format()reads (TRACER_OUTPUT_FORMAT,NO_COLOR,SLACK_WEBHOOK_URL,TRACER_VERBOSE); monkeypatchingtime.monotonicfor the timing assertions; and aforce_text_modefixture applied via
@pytest.mark.usefixturesto keep tracker testsoff the rich path.
One subtlety worth calling out:
ProgressTracker._finishcallstime.monotonictwice (the second time is the eager default fordict.pop), so the patched clock has to yield three values, not two.That's commented in the test.
Checklist before requesting a review
Note: Please check Allow edits from maintainers if you would like us to assist in the PR.