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
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: answerCallbackQuery → true,
everything else → a valid Message.