Skip to content

feat(cli): extract JUnit formatter + step-cmd hints + message= fallback#900

Merged
bokelley merged 2 commits into
mainfrom
bokelley/junit-extract-step-hints
Apr 24, 2026
Merged

feat(cli): extract JUnit formatter + step-cmd hints + message= fallback#900
bokelley merged 2 commits into
mainfrom
bokelley/junit-extract-step-hints

Conversation

@bokelley

Copy link
Copy Markdown
Contributor

Closes the salvageable deltas from #894 (closed as obsolete). Follow-up to #870 / #875 / #879 / #883 / #891.

Summary

Three cherry-picked bits from the abandoned #894:

  1. Extract formatStoryboardResultsAsJUnit from `bin/adcp.js` into `src/lib/testing/storyboard/junit.ts` (@internal). Was 70 lines of inline JS that required spawning the CLI to test. Now a pure function with unit coverage at `test/lib/storyboard-junit-formatter.test.js` — XML structure, hint integration, escaping.

  2. Wire hints into `adcp storyboard step` — a printer site I missed in feat(cli): render StoryboardStepResult.hints in console + JUnit (#879) #891. The phase-nested storyboard printer uses a 3-space indent; the single-step command prints at column zero. Parameterized `printStepHints(hints, indent)` so both callers share the helper.

  3. `` attribute fallback to `hints?.[0]?.message` when `step.error` is absent. Closes an edge opened by the Runner hints: extend gate beyond !passed to cover schema-rejected-200 responses #883 gate widening — validation-only failures under a 200-OK envelope have no task-level error, so CI dashboards that only read the attribute used to see `validation failed` instead of the diagnosis.

Cleanup

Drops the unused `formatHintsForFailureBody` export from `adcp-step-hints.js` now that the JUnit module owns its own hint rendering. The CLI `adcp-step-hints.js` is now single-purpose (human console only).

Test plan

  • 10 new tests in `test/lib/storyboard-junit-formatter.test.js` covering shape, hint integration, message= fallback, and XML escaping.
  • `cli-step-hints.test.js` replaced the dropped `formatHintsForFailureBody` tests with two new `printStepHints`-with-indent cases.
  • Full storyboard/CLI test suite: 2387 pass, 0 fail.
  • `node bin/adcp.js --help` smoke check.
  • `prettier --check` + `tsc --noEmit` clean.

🤖 Generated with Claude Code

bokelley and others added 2 commits April 24, 2026 12:48
Cherry-picks the three salvageable deltas from closed PR #894 (which
overlapped heavily with merged #891 after a long rebase drift):

1. Extracts `formatStoryboardResultsAsJUnit` from `bin/adcp.js` into
   `src/lib/testing/storyboard/junit.ts` (@internal). Now unit-testable
   as a pure function — 10 tests pinning XML structure, hint integration,
   and escaping added in `test/lib/storyboard-junit-formatter.test.js`.

2. Wires `printStepHints` into `adcp storyboard step` — a printer site
   that #891 missed. Parameterizes the indent so both the phase-nested
   (`   `) and column-zero step printers share the helper.

3. Adds `<failure message=…>` attribute fallback to `hints?.[0]?.message`
   when `step.error` is absent. Closes an edge opened by the #883 gate
   widening (validation-only failures with no task-level error): CI
   dashboards that only read the attribute now surface the hint.

Drops the now-unused `formatHintsForFailureBody` export from
`adcp-step-hints.js` and its tests — the JUnit module owns its own hint
rendering.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Code-reviewer flagged: the file-level `@internal` JSDoc was binding to
the next declaration (the import of `StoryboardResult`), so
stripInternal removed the import but left the function signature
referencing an undeclared name. Emitted `.d.ts` was:

    export declare function formatStoryboardResultsAsJUnit(
      results: StoryboardResult[]
    ): string;

— any downstream TS consumer hit TS2304. Fixed by moving the @internal
annotation onto the function itself; d.ts now correctly emits
`export {};`.

Also drops the re-export from `storyboard/index.ts` — stripInternal
already strips it from the public type surface and the CLI reaches into
`dist/lib/testing/storyboard/junit.js` directly, so the re-export was
dead for every consumer.

Testing-reviewer nits addressed:
- New test: empty results produces valid empty testsuites element
- New test: multi-storyboard + multi-phase aggregation (catches off-by-
  ones in totalTests / suiteTests reducers)
- New test: `step.error === ''` (empty string, not undefined) → first
  hint message fallback kicks in
- Replaced brittle escape-pipeline-reconstruction regex with explicit
  entity assertions; scoped `&apos;` check to the `message=` attribute
  where it's actually load-bearing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bokelley bokelley merged commit fd25ba1 into main Apr 24, 2026
9 checks passed
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