Skip to content

fix(rerun): emit partial stdout on TimeoutError in single-FE rerun --wait#219

Open
Awad-de wants to merge 2 commits into
TestSprite:mainfrom
Awad-de:fix/rerun-wait-timeout-stdout-pr
Open

fix(rerun): emit partial stdout on TimeoutError in single-FE rerun --wait#219
Awad-de wants to merge 2 commits into
TestSprite:mainfrom
Awad-de:fix/rerun-wait-timeout-stdout-pr

Conversation

@Awad-de

@Awad-de Awad-de commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes an asymmetry in testsprite test rerun --wait (single FE rerun path):
when the overall --timeout polling deadline is exceeded, the CLI now emits a
partial { runId, status: "running" } object to stdout before throwing
exit 7 — matching the behavior already present for RequestTimeoutError and
the recently fixed test run --wait / test wait paths.

Before: TimeoutError → throw ApiError immediately → stdout empty in
--output json mode → AI agents must scrape stderr to recover the runId.

After: TimeoutErrorout.print({ runId, status: "running" }) → throw
→ caller can programmatically chain into testsprite test wait <runId>.

Related issue

Hackathon CLI Improvement — agent recovery on polling timeout (complements
the test run --wait / test wait TimeoutError fix; this covers the
remaining single-FE test rerun --wait path).

Type of change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that changes existing behavior)
  • Documentation only
  • Build / CI / chore

Checklist

  • PR targets the main branch.
  • Commits follow Conventional Commits (feat(...), fix(...), docs(...), …).
  • npm run lint and npm run format:check pass.
  • npm run typecheck passes.
  • npm test passes and coverage stays at or above the 80% gate.
  • New behavior is covered by unit tests (mock-based; no network or credentials required).
  • No secrets, API keys, internal endpoints, or personal data are included.
  • User-facing changes are reflected in README.md / DOCUMENTATION.md where relevant. (N/A — internal error-handling parity fix, no CLI surface change.)

Notes for reviewers

Root cause

In runTestRerun (single FE rerun, no BE closure), the TimeoutError catch
block at ~line 6132 called ticker.finalize() then threw ApiError without
any out.print(). The adjacent RequestTimeoutError branch already emitted
a partial run to stdout — this was simply a missed mirror.

Scope

  • Changed: single-FE test rerun --wait TimeoutError path only (~12 lines).
  • Not changed: BE closure fan-out paths — those already aggregate runIds
    into the batch result object on timeout; test run --wait / test wait
    were fixed in a prior PR.

Test added

[finding-4] in test.rerun.spec.ts:

  • triggers TimeoutError via timeoutSeconds: 0 (immediate deadline)
  • asserts exit code 7
  • asserts stdout contains parseable JSON { runId, status: "running" }

Verification

npm test → 1571 passed
npm run typecheck → clean
npm run lint:fix → clean

Summary by CodeRabbit

  • Bug Fixes
    • Improved timeout handling for test reruns by emitting a parseable partial progress message (including the run ID and current running status) before exiting.
    • Added a clearer “resume” hint for timed-out reruns so the next step is straightforward.
    • Ensures the CLI exits with the expected timeout code when polling exceeds the deadline.
  • Tests
    • Added coverage for single-test rerun --wait timeout behavior, including partial output validation.

…wait

Apply the fix in src/commands/test.ts. When the overall --timeout polling
deadline is exceeded on a single FE rerun, emit {runId, status:"running"}
to stdout before exit 7.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0c2e18c8-b571-4297-90c8-eb261eeeb44e

📥 Commits

Reviewing files that changed from the base of the PR and between cff19ae and 95e3978.

📒 Files selected for processing (2)
  • src/commands/test.rerun.spec.ts
  • src/commands/test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/commands/test.rerun.spec.ts

Walkthrough

Modified runTestRerun's single-FE --wait timeout handling to print a partial JSON stdout object with runId and status: 'running' before throwing the timeout error. Added a test that exercises the timeout path and checks the parseable stdout output.

Changes

Rerun Timeout Partial Output

Layer / File(s) Summary
Timeout stdout emission
src/commands/test.ts
On TimeoutError in single rerun --wait, prints a partial { runId, status: 'running' } object and a resume hint before re-throwing the timeout ApiError.
Timeout stdout test
src/commands/test.rerun.spec.ts
Adds [finding-4] coverage for the single-FE rerun timeout path, mocking rerun trigger and polling responses and asserting exit code 7 with parseable partial stdout JSON.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers: ruili-testsprite, zeshi-du

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main fix: emitting partial stdout on TimeoutError during single-FE rerun --wait.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
src/commands/test.ts (1)

6102-6113: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate partial-timeout-print logic between TimeoutError and RequestTimeoutError branches.

The new TimeoutError block (Lines 6102-6113) and the existing RequestTimeoutError block (Lines 6126-6142) build near-identical { runId, status: 'running' } objects and near-identical text formatters, differing only in the wording of the timeout reason and hint line. Consider extracting a small shared helper (e.g. printTimeoutPartial(out, runId, reasonText)) to keep both branches — and any future timeout branches — in sync.

♻️ Proposed refactor sketch
+function printRerunTimeoutPartial(
+  out: ReturnType<typeof makeOutput>,
+  runId: string,
+  reasonText: string,
+): void {
+  const partial = { runId, status: 'running' as const };
+  out.print(partial, data => {
+    const p = data as typeof partial;
+    return [
+      `runId       ${p.runId}`,
+      `status      ${p.status} (${reasonText})`,
+      `hint        Re-attach with: testsprite test wait ${p.runId}`,
+    ].join('\n');
+  });
+}

Then call it from both catch branches with the appropriate reasonText.

Also applies to: 6126-6142

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/commands/test.ts` around lines 6102 - 6113, The TimeoutError and
RequestTimeoutError branches in test.ts duplicate the same partial-run printing
logic. Extract the shared `{ runId, status: 'running' }` construction and
`out.print` formatter into a small helper (for example, a timeout-partial
printer) and call it from both catch paths, passing only the branch-specific
timeout reason/hint text so the two cases stay consistent.
src/commands/test.rerun.spec.ts (1)

4699-4703: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider also asserting nextAction on the thrown error.

Per DOCUMENTATION.md, --wait --timeout exceedance is expected to include a nextAction pointing callers to test wait <run-id>. Asserting err.details?.nextAction (or equivalent) here would guard that documented contract, not just the exit code and stdout partial.

As per path instructions: "Exit-code mapping: error paths must map to the documented exit code (see DOCUMENTATION.md / the exit-code table)".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/commands/test.rerun.spec.ts` around lines 4699 - 4703, The rerun timeout
assertion currently checks only the exit code and stdout, but it should also
verify the documented `nextAction` on the thrown error. Update the
`test.rerun.spec.ts` timeout case to assert `err.details?.nextAction` (or the
equivalent error field) in the same block where `err` is matched, using the
rerun/wait flow around the `rerunResp.runId` scenario, so the contract that
callers are directed to `test wait <run-id>` is covered.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/commands/test.rerun.spec.ts`:
- Around line 4699-4703: The rerun timeout assertion currently checks only the
exit code and stdout, but it should also verify the documented `nextAction` on
the thrown error. Update the `test.rerun.spec.ts` timeout case to assert
`err.details?.nextAction` (or the equivalent error field) in the same block
where `err` is matched, using the rerun/wait flow around the `rerunResp.runId`
scenario, so the contract that callers are directed to `test wait <run-id>` is
covered.

In `@src/commands/test.ts`:
- Around line 6102-6113: The TimeoutError and RequestTimeoutError branches in
test.ts duplicate the same partial-run printing logic. Extract the shared `{
runId, status: 'running' }` construction and `out.print` formatter into a small
helper (for example, a timeout-partial printer) and call it from both catch
paths, passing only the branch-specific timeout reason/hint text so the two
cases stay consistent.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a45e95fc-68a8-4092-b342-b64f27518f03

📥 Commits

Reviewing files that changed from the base of the PR and between 3305dfa and cff19ae.

📒 Files selected for processing (2)
  • src/commands/test.rerun.spec.ts
  • src/commands/test.ts

@Awad-de

Awad-de commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

Discord Username / User ID
muathawad_37013 — Muath Awad

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant