cloudaxe-opencode/packages/opencode/specs/property-based-tui-testing-working-notes.md
2026-05-17 14:38:29 -04:00

3.5 KiB

Property-Based TUI Testing Working Notes

Mock LLM Provider

  • SessionPrompt gets model metadata through Provider.Service.getModel(...).
  • Actual generation is routed through LLM.Service / streamText(...), so the first mock should return an AI SDK LanguageModelV3 from the provider service.
  • The normal Provider.layer builds providers from config/models.dev/plugin state. For first pass, the simulated graph can replace Provider.Service with a smaller simulation provider service instead of trying to flow through provider config.
  • Control state should own an ordered LLM script queue. The provider/model should consume from that queue when the AI SDK calls the language model.
  • First version can support text-only output. Tool calls and stream chunk fidelity can come next.
  • Missing script should fail loudly with a typed simulation error, not silently return an empty assistant message.
  • Implemented SimulationProvider.layer, replacing Provider.Service in createSimulatedRoutes.
  • The provider exposes provider simulation and model mock.
  • doGenerate and doStream both consume one queued script through Simulation.Service.nextLLM().
  • Current script support: text, thinking (treated as text for now), and error.
  • Snapshot currently records llmQueued and llmConsumed, not per-step details yet.

OpenTUI Fake Renderer

  • OpenTUI Solid exposes testRender(...) from @opentui/solid.
  • The lower-level core API is createTestRenderer(...) from @opentui/core/testing.
  • createTestRenderer(...) returns renderer, mockInput, mockMouse, renderOnce, captureCharFrame, captureSpans, and resize.
  • captureCharFrame() is the simple screen-buffer string API used heavily in OpenTUI snapshots.
  • captureSpans() returns structured lines/spans plus cursor position, which is a better starting point for visible element discovery than parsing raw characters.
  • mockInput supports interactions like typeText, pressEnter, and pressArrow.
  • Implemented TuiSimulation.createSimulationRenderer(...) beside thread.ts. It creates a test renderer and exposes renderOnce, screen, spans, and destroy.
  • thread.ts checks OPENCODE_SIMULATION, creates the fake renderer there, starts the normal worker/backend, and passes the renderer into tui(...).
  • Backend route assembly checks OPENCODE_SIMULATION_BACKEND; OPENCODE_SIMULATION implies this flag.
  • OPENCODE_SIMULATION_BACKEND=1 can run a real frontend against a simulated backend.
  • tui(...) now accepts an injected CliRenderer, test mode, and an onReady callback. Production still creates the real renderer.

OpenTUI Action APIs

  • Interactable discovery can walk renderer.root.getChildren() recursively.
  • Renderable.focusable and Renderable.focused are public and enough to discover focus targets.
  • renderer.currentFocusedEditor identifies active text input/edit-buffer targets for typing/submission.
  • renderer.hitTest(x, y) maps terminal coordinates through the hit grid to a renderable id.
  • Renderables have public geometry: screenX, screenY, width, height, and num.
  • Mouse listener metadata is stored internally on renderables; first pass checks _mouseListener / _mouseListeners at runtime to identify clickable targets. This is pragmatic but not a stable public API.
  • Test execution uses mockInput.typeText, mockInput.pressEnter, mockInput.pressArrow, and mockMouse.click from OpenTUI testing.
  • Implemented SimulationActions with elements(...), actions(...), and execute(...).