telega/testing/dialog

Drive a compiled dialog in tests, without a bot or a network.

This is the “level 2” harness from docs/dialogs.md: it stands in for the flow registry’s auto-resume, loading the waiting instance from storage and resuming it with the same payloads the registry’s callback/text/photo handlers would build. Pair it with telega/testing/mock and telega/testing/render.calls_transcript to snapshot everything the user would see.

let assert Ok(storage) = flow_storage.create_ets_storage()
let assert Ok(built) = my_dialog(storage)
let flow = dialog_engine.compile(dialog.compiled(built))
let #(client, calls) = testing_dialog.text_client()

let driver =
  testing_dialog.driver(flow:, client:, dialog_id: "settings")
  |> testing_dialog.with_chat(chat_id: 42)

testing_dialog.start(driver, command: "/settings")
testing_dialog.press(driver, data: "dlg:settings:menu:lang:ru")
testing_dialog.send_text(driver, text: "Alice")

mock.get_calls(calls)
|> render.calls_transcript
|> birdie.snap(title: "settings:happy_path")

Types

Everything a dialog needs to be driven: the compiled flow (which carries its own storage), the mock client its renders talk to, and who is talking.

pub opaque type Driver(session, error, dependencies)

Values

pub fn driver(
  flow flow: types.Flow(String, Nil, error, Nil),
  client client: client.TelegramClient,
  dialog_id dialog_id: String,
) -> Driver(Nil, error, Nil)

A driver for a Nil-session, Nil-dependencies dialog — the common case. Chat 1 and user 1 unless with_chat/with_user say otherwise.

pub fn driver_with(
  flow flow: types.Flow(String, session, error, dependencies),
  client client: client.TelegramClient,
  dialog_id dialog_id: String,
  session session: session,
  dependencies dependencies: dependencies,
) -> Driver(session, error, dependencies)

driver for a dialog with its own session and injected dependencies.

pub fn instance(
  driver: Driver(session, error, dependencies),
) -> option.Option(types.FlowInstance)

The persisted instance, or None once the dialog has finished.

pub fn instance_id(
  driver: Driver(session, error, dependencies),
) -> String

The flow instance id this driver reads and writes — useful for asserting on the persisted state directly.

pub fn instance_id_for(
  dialog_id dialog_id: String,
  chat_id chat_id: Int,
  user_id user_id: Int,
) -> String

The flow instance id a dialog persists under, without a driver.

pub fn media_client() -> #(
  client.TelegramClient,
  process.Subject(mock.ApiCall),
)

Mock client for dialogs that recreate the live message (media windows, sub-dialogs): additionally answers deleteMessage with true.

pub fn press(
  driver: Driver(session, error, dependencies),
  data data: String,
) -> Nil

Deliver a button press to the waiting dialog.

pub fn press_on_message(
  driver: Driver(session, error, dependencies),
  data data: String,
  message_id message_id: Int,
) -> Nil

Deliver a press coming from a message other than the live one — a button on an outdated copy of the dialog.

pub fn send_photo(
  driver: Driver(session, error, dependencies),
  file_ids file_ids: List(String),
) -> Nil

Deliver a photo to the waiting dialog, the way the flow registry’s photo auto-resume does.

pub fn send_text(
  driver: Driver(session, error, dependencies),
  text text: String,
) -> Nil

Deliver a text message to the waiting dialog.

pub fn start(
  driver: Driver(session, error, dependencies),
  command command: String,
) -> Nil

Start (or resume) the dialog the way its start command would.

pub fn text_client() -> #(
  client.TelegramClient,
  process.Subject(mock.ApiCall),
)

Mock client for text-only dialogs: answerCallbackQuerytrue, everything else → a valid Message.

pub fn with_chat(
  driver: Driver(session, error, dependencies),
  chat_id chat_id: Int,
) -> Driver(session, error, dependencies)

Drive the dialog in a different chat — one driver per chat keeps concurrent-dialog tests apart.

pub fn with_user(
  driver: Driver(session, error, dependencies),
  user_id user_id: Int,
) -> Driver(session, error, dependencies)

Drive the dialog as a different user.

Search Document