Skip to content

feat: Enhanced test runner UI with progress bar, per-suite results, and bundled image assets#380

Open
kanhaiyaXITE wants to merge 5 commits into
rokucommunity:masterfrom
kanhaiyaXITE:feature/enhanced-test-runner-ui
Open

feat: Enhanced test runner UI with progress bar, per-suite results, and bundled image assets#380
kanhaiyaXITE wants to merge 5 commits into
rokucommunity:masterfrom
kanhaiyaXITE:feature/enhanced-test-runner-ui

Conversation

@kanhaiyaXITE
Copy link
Copy Markdown

@kanhaiyaXITE kanhaiyaXITE commented Apr 22, 2026

Summary

Replaces the default minimal test runner UI with an enhanced visual experience featuring real-time progress tracking, per-suite pass/fail results, and customizable branding.

What changed

Test Runner UI (FileFactory.ts)

  • Dark themed background (#1a1a2e) replacing the plain gray
  • Progress bar with animated fill showing suite completion
  • Summary label showing passed/failed counts and elapsed time
  • Result image that updates to show loading → success/failure state
  • Placeholder company logo — users can replace images/rooibos/your-company-logo.png with their own
  • New field aliases: resultImageUri, summaryText, progressWidth

Test Runner Logic (TestRunner.bs)

  • Per-suite progress: Running (3/15): SuiteName with live progress bar
  • Per-suite results: OK SuiteName (5/5) or X SuiteName (3/5) as each suite completes
  • Final summary with elapsed time: Passed: 12 | Failed: 3 | 15 suites in 4.2s
  • Result image swaps to success/failure icon on completion
  • ScrollableText gets focus immediately so users can scroll with D-pad during execution
  • Test nodes created in an offscreen container (testNodeContainer) to prevent scene re-renders

Image Asset Pipeline (FileFactory.ts + plugin.ts)

  • New copyImageAssets() method copies bundled images to staging directory as binary files
  • Called from afterProgramTranspile hook (when staging directory exists)
  • Images are bundled in the package (pkg:/images/rooibos/...) — no network requests at runtime
  • Supports PNG, JPG, JPEG, GIF formats

Bundled Assets

Image Purpose
your-company-logo.png Placeholder logo (replace with your own)
loading.png Shown while tests are running
success.png Shown when all suites pass
failure.png Shown when any suite fails
scrollbar-track.9.png Custom scrollbar track (9-patch)
scrollbar-thumb.9.png Custom scrollbar thumb (9-patch)

Screenshots

image

Testing

  • npm run test:nocover — 121 passing, 1 pending (no regressions)
  • npm run build — clean build
  • npm run build-test-project — transpiles and packages successfully
  • Sideloaded to Roku device — UI renders correctly with progress bar, results, and scrollbar
  • Telnet log confirms all failures are pre-existing (intentional FailedAssertion + SuiteTimeouts tests)

@TwitchBronBron
Copy link
Copy Markdown
Member

Hey, thanks for this! @chrisdp has some feedback he'll hopefully get around to sharing next week. But this is a much needed improvement, looking forward to landing it!

@kanhaiyaXITE
Copy link
Copy Markdown
Author

Hey, thanks for this! @chrisdp has some feedback he'll hopefully get around to sharing next week. But this is a much needed improvement, looking forward to landing it!

i would love to contribute further if needed!

@TwitchBronBron
Copy link
Copy Markdown
Member

Hey, thanks for this! @chrisdp has some feedback he'll hopefully get around to sharing next week. But this is a much needed improvement, looking forward to landing it!

i would love to contribute further if needed!

That would be great! if I remember correctly, I think one of his big concerns was that there are performance implications of regularly replacing the entire .text of the ScrollableText node. As the test suite grows, that'll slow down over time, and can have performance impacts on the test suites themselves.

I think one of his suggestions was to instead create unique labels for each line, and offset them using absolute positioning. This way the impact of adding new statuses is only as costly as creating 1 new label node per message.

Might be worth experimenting with that?

I'll connect with him next week to get more specific details.

@TwitchBronBron
Copy link
Copy Markdown
Member

Got some more clarity on the approach from Chris. here are the main points:

Label recycling for scrolling
Rather than dynamic list items, use a fixed pool of ~10 labels and swap their text content as you scroll up/down — same nodes, just updated text. This keeps the node usage down, reduces all that concatenated string stuff. Makes the test environment more consistent too.

Loading spinner
The current spinning image...doesn't spin. Would be much better to be a proper spinner somehow.

Progress bar granularity
Base it on individual tests rather than suites, so it updates incrementally as each test completes.

Suite progress display
Show the current suite name alongside x/y test progress. (Not sure if some version of this is already in there — worth a double-check before building it.)

@kanhaiyaXITE
Copy link
Copy Markdown
Author

Got some more clarity on the approach from Chris. here are the main points:

Label recycling for scrolling Rather than dynamic list items, use a fixed pool of ~10 labels and swap their text content as you scroll up/down — same nodes, just updated text. This keeps the node usage down, reduces all that concatenated string stuff. Makes the test environment more consistent too.

Loading spinner The current spinning image...doesn't spin. Would be much better to be a proper spinner somehow.

Progress bar granularity Base it on individual tests rather than suites, so it updates incrementally as each test completes.

Suite progress display Show the current suite name alongside x/y test progress. (Not sure if some version of this is already in there — worth a double-check before building it.)

oaky perfect, i was trying to avoid the animation node but it will make it look super cool! I will try to make above possible.

… refactor

Builds on PR rokucommunity#380 with four review follow-ups and an enterprise-grade
refactor of TestRunner.

UI improvements
- Loading spinner now actually rotates (BusySpinner with control="start")
  and resets cleanly to scale=[0,0] before revealing the result Poster, so
  the success/failure image always lands upright at the same canvas size.
- Progress bar advances per test (not per suite) via a new
  TestRunnerUIReporter wired into the framework's reporter chain, with a
  cross-thread bridge for node/async test suites that fire callbacks on
  the child node's reporter list rather than ours.
- Status header shows the current suite name plus a live
  "started/total · ✓ passed · ✗ failed" counter, updated on every
  onTestBegin/onTestComplete.
- Results panel rebuilt as a designer-style row layout: thin colored
  accent bar on the left (green pass / red fail), suite name as the
  dominant content, and a focus-driven failure-count disclosure on the
  right that reveals "1 failed" / "all 212 failed" only when the row is
  focused. Replaces the old O(N) string-realloc ScrollableText.

Architecture
- New TestRunnerUIReporter class extends BaseTestReporter, owns all UI
  state (totals, scene-node refs, progress writes). Replaces a 35-line
  inline anonymous reporter literal embedded in run().
- TestRunner.run() decomposed from a ~225-line monolith into a 38-line
  orchestration plus 14 single-purpose private helpers
  (precomputeTotalTests, executeSuite, buildSuite, resolveUINodes,
  appendSuiteResultLine, finalizeRun, renderSuccessFinalState,
  renderFailureFinalState, swapResultImage, notifyReporters,
  dispatchOnEnd, publishRooibosResult, maybeRunCoverage,
  printFinalStatus).
- Cross-thread bridge in runNodeTest collapsed from a 14-line per-event
  switch to a single uiReporter.applyNodeProgressEvent(field) call.
- New RooibosResultRow + RooibosScrollableResults components: row uses
  absolutely-positioned children (bar / name / count) so alignment is
  mathematically guaranteed regardless of font proportions; colors hoisted
  to a single m.colors table; render rules expressed as pure helpers.
- RooibosScrollableResults switched from LabelList to MarkupList with
  itemComponentName="RooibosResultRow"; appendLine takes structured
  { name, passed, failedCount, totalCount }, dropping all dead
  text/color/string-arg paths.
- Plugin scene template (FileFactory.ts) branches on the suite parameter:
  node-test components get a minimal XML (just rooibosTestResult field +
  Rooibos_CreateTestNode function, no UI children) — fixes a duplicate
  scene-graph ID bug (multiple resultImage nodes) that previously corrupted
  SceneGraph state and crashed the runtime at end of run.

Bug fixed in passing
- Original final-state rendering used the last loop-iteration's testSuite
  variable, silently rendering nothing when the last class lookup failed.
  New code tracks the last successful suite explicitly.

Assets
- loading.png, success.png, failure.png resized to 75×75 — appropriate for
  the spinner slot, no on-device scaling.
@kanhaiyaXITE
Copy link
Copy Markdown
Author

kanhaiyaXITE commented May 2, 2026

@TwitchBronBron al the changes are in place. Please feel free to leave your input when you get some time to review.

  • Loading spinner now actually rotates (BusySpinner with control="start")
    and resets cleanly to scale=[0,0] before revealing the result Poster, so
    the success/failure image always lands upright at the same canvas size.
  • Progress bar advances per test (not per suite) via a new
    TestRunnerUIReporter wired into the framework's reporter chain, with a
    cross-thread bridge for node/async test suites that fire callbacks on
    the child node's reporter list rather than ours.
  • Status header shows the current suite name plus a live
    "started/total · ✓ passed · ✗ failed" counter, updated on every
    onTestBegin/onTestComplete.
  • Results panel rebuilt as a designer-style row layout: thin colored
    accent bar on the left (green pass / red fail), suite name as the
    dominant content, and a focus-driven failure-count disclosure on the
    right that reveals "1 failed" / "all 212 failed" only when the row is
    focused. Replaces the old O(N) string-realloc ScrollableText.

These were placeholders for an earlier custom scrollbar idea that the
final RooibosScrollableResults component (extending MarkupList) doesn't
need. No code references either file.
@kanhaiyaXITE kanhaiyaXITE force-pushed the feature/enhanced-test-runner-ui branch from 0be34be to 04abada Compare May 4, 2026 12:42
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.

2 participants