plushie/testing/renderer

Test renderer: OTP actor wrapping a Port to the Rust binary.

Provides bidirectional wire communication for renderer-backed test backends (headless and windowed). Handles the Elm loop: dispatches decoded events through update, processes commands, re-renders the view, and sends snapshots back to the renderer.

Request/response lifecycle

External callers send Call* messages (find, interact, tree_hash, screenshot, reset) which include a reply Subject. The actor assigns a unique request ID, sends a wire message to the Rust binary, and stores a PendingEntry keyed by that ID. When the Rust binary responds, the actor matches the response ID to the pending map, replies to the caller, and removes the entry.

Pending map invariant: every entry in the pending map corresponds to exactly one outstanding wire request. If the port exits, all pending callers receive a ReplyError and the actor stops. No request ID is ever reused.

Backends

Use headless mode (--headless args) for CI and screenshot tests with software rendering. Use windowed mode for manual visual verification. The mock backend does not use this actor at all – it runs the Elm loop in pure Gleam without a port.

Types

Configuration for starting a renderer actor.

pub type RendererConfig {
  RendererConfig(
    args: List(String),
    format: protocol.Format,
    renderer_path: option.Option(String),
    send_settings: Bool,
    screenshot_size: option.Option(#(Int, Int)),
  )
}

Constructors

  • RendererConfig(
      args: List(String),
      format: protocol.Format,
      renderer_path: option.Option(String),
      send_settings: Bool,
      screenshot_size: option.Option(#(Int, Int)),
    )

    Arguments

    args

    Port arguments (e.g. [“–headless”] or [“–headless”, “–json”]).

    format

    Wire format.

    renderer_path

    Path to the plushie binary. None = auto-resolve.

    send_settings

    Whether to send settings before the initial snapshot.

    screenshot_size

    Screenshot dimensions for headless mode (None for windowed).

Messages the renderer actor handles.

pub opaque type RendererMessage

Reply values from the renderer actor.

pub type RendererReply {
  ReplyElement(option.Option(element.Element))
  ReplyTree(option.Option(dynamic.Dynamic))
  ReplyOk
  ReplyModel(dynamic.Dynamic)
  ReplyTreeHash(tree_hash.TreeHash)
  ReplyScreenshot(screenshot.Screenshot)
  ReplyError(String)
}

Constructors

Convenience alias for the renderer actor’s Subject.

pub type RendererSubject =
  process.Subject(RendererMessage)

Values

pub fn click(
  subject: process.Subject(RendererMessage),
  selector: String,
) -> Nil

Click on an element identified by selector.

pub fn find(
  subject: process.Subject(RendererMessage),
  selector: String,
) -> option.Option(element.Element)

Find an element by selector string.

pub fn get_screenshot(
  subject: process.Subject(RendererMessage),
  name: String,
) -> screenshot.Screenshot

Capture a screenshot from the renderer.

pub fn get_tree(
  subject: process.Subject(RendererMessage),
) -> option.Option(dynamic.Dynamic)

Get the raw tree from the renderer.

pub fn get_tree_hash(
  subject: process.Subject(RendererMessage),
  name: String,
) -> tree_hash.TreeHash

Get a tree hash from the renderer.

pub fn model(
  subject: process.Subject(RendererMessage),
) -> dynamic.Dynamic

Get the current model (returned as Dynamic – caller casts).

pub fn move_to(
  subject: process.Subject(RendererMessage),
  x: Float,
  y: Float,
) -> Nil

Move the mouse pointer to absolute coordinates.

pub fn press(
  subject: process.Subject(RendererMessage),
  key: String,
) -> Nil

Press a key (no selector).

pub fn release(
  subject: process.Subject(RendererMessage),
  key: String,
) -> Nil

Release a key (no selector).

pub fn reset(subject: process.Subject(RendererMessage)) -> Nil

Reset the session to initial state.

pub fn select(
  subject: process.Subject(RendererMessage),
  selector: String,
  value: String,
) -> Nil

Select a value on a picker/dropdown identified by selector.

pub fn slide(
  subject: process.Subject(RendererMessage),
  selector: String,
  value: Float,
) -> Nil

Slide a slider to a value, identified by selector.

pub fn start(
  app: app.App(model, event.Event),
  config: RendererConfig,
) -> Result(process.Subject(RendererMessage), actor.StartError)

Start a renderer actor with the given app and config.

pub fn stop(subject: process.Subject(RendererMessage)) -> Nil

Stop a renderer actor by sending a normal exit to its process.

pub fn submit(
  subject: process.Subject(RendererMessage),
  selector: String,
) -> Nil

Submit a form element identified by selector.

pub fn toggle(
  subject: process.Subject(RendererMessage),
  selector: String,
) -> Nil

Toggle a checkbox/toggler identified by selector.

pub fn type_key(
  subject: process.Subject(RendererMessage),
  key: String,
) -> Nil

Press and release a key (no selector).

pub fn type_text(
  subject: process.Subject(RendererMessage),
  selector: String,
  text: String,
) -> Nil

Type text into an element identified by selector.

Search Document