diff --git a/src/commands/test.run.spec.ts b/src/commands/test.run.spec.ts index fef12ac6..7fa5a584 100644 --- a/src/commands/test.run.spec.ts +++ b/src/commands/test.run.spec.ts @@ -16,7 +16,7 @@ import { DRY_RUN_BANNER, resetDryRunBannerForTesting } from '../lib/client-facto import type { FetchImpl } from '../lib/http.js'; import type { RunResponse, TriggerRunResponse, BatchRunFreshResponse } from '../lib/runs.types.js'; import { takeTelemetryExtras } from '../lib/telemetry.js'; -import { runTestRun, runTestRunAll } from './test.js'; +import { renderRunResponseText, runTestRun, runTestRunAll } from './test.js'; // --------------------------------------------------------------------------- // Helpers @@ -7203,6 +7203,32 @@ describe('runTestRun — --target-url reachability preflight wiring', () => { }); }); +describe('run card: failed step (#672)', () => { + it('prints failedStepIndex right after failureKind for a failed run', () => { + const lines = renderRunResponseText({ ...makeFailedRun(), failedStepIndex: 4 }).split('\n'); + const kind = lines.indexOf('failureKind assertion'); + expect(kind).toBeGreaterThanOrEqual(0); + expect(lines[kind + 1]).toBe('failedStepIndex 4'); + }); + + it('prints it for a blocked run too', () => { + const text = renderRunResponseText({ ...makeFailedRun(), status: 'blocked' }); + expect(text.split('\n')).toContain('failedStepIndex 2'); + }); + + it('omits the line when the server reported no failed step', () => { + expect(renderRunResponseText({ ...makeFailedRun(), failedStepIndex: null })).not.toContain( + 'failedStepIndex', + ); + }); + + it('omits the line for a passed run', () => { + expect(renderRunResponseText({ ...makePassedRun(), failedStepIndex: 2 })).not.toContain( + 'failedStepIndex', + ); + }); +}); + describe('gh-output integration on single-test run --wait (Gap A)', () => { function singleRunHarness(run: RunResponse) { const { credentialsPath } = makeCreds(); diff --git a/src/commands/test.ts b/src/commands/test.ts index 8bf5ce5b..f22bb877 100644 --- a/src/commands/test.ts +++ b/src/commands/test.ts @@ -7563,6 +7563,8 @@ export function renderRunResponseText( if (run.startedAt) lines.push(`startedAt ${run.startedAt}`); if (run.finishedAt) lines.push(`finishedAt ${run.finishedAt}`); if (run.failureKind) lines.push(`failureKind ${run.failureKind}`); + if ((run.status === 'failed' || run.status === 'blocked') && run.failedStepIndex !== null) + lines.push(`failedStepIndex ${run.failedStepIndex}`); // D5-UX: show the human error string when status is failed/blocked and // the backend provided it. Truncate long multi-line errors to the first // line (≤200 chars) so the text output stays readable. JSON mode is