use std::path::{Path, PathBuf};
use std::time::Duration;
use crate::session::{PtySession, PtySessionBuilder, PtySessionError};
use crate::step::Step;
use crate::vhs::VhsTape;
#[must_use]
pub struct Scenario {
pub name: String,
pub steps: Vec<Step>,
}
impl Scenario {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
steps: Vec::new(),
}
}
pub fn step(mut self, step: Step) -> Self {
self.steps.push(step);
self
}
pub fn write_text(self, text: impl Into<String>) -> Self {
self.step(Step::write_text(text))
}
pub fn press_key(self, key: impl Into<String>) -> Self {
self.step(Step::press_key(key))
}
pub fn sleep(self, duration: Duration) -> Self {
self.step(Step::sleep(duration))
}
pub fn sleep_ms(self, ms: u64) -> Self {
self.step(Step::sleep_ms(ms))
}
pub fn wait_for_text(self, needle: impl Into<String>, timeout_ms: u32) -> Self {
self.step(Step::wait_for_text(needle, timeout_ms))
}
pub fn wait_for_stable_frame(self, stable_ms: u32, timeout_ms: u32) -> Self {
self.step(Step::wait_for_stable_frame(stable_ms, timeout_ms))
}
pub fn capture(self) -> Self {
self.step(Step::capture())
}
pub fn execute_in_pty(
&self,
session: &mut PtySession,
) -> Result<crate::frame::TerminalFrame, PtySessionError> {
session.execute_steps(&self.steps)
}
pub fn run(
&self,
builder: PtySessionBuilder,
) -> Result<crate::frame::TerminalFrame, PtySessionError> {
let mut session = builder.spawn()?;
self.execute_in_pty(&mut session)
}
pub fn to_vhs_tape(
&self,
binary_path: &Path,
screenshot_path: &Path,
env_vars: &[(&str, &str)],
) -> VhsTape {
VhsTape::from_scenario(self, binary_path, screenshot_path, env_vars)
}
pub fn write_vhs_tape(
&self,
binary_path: &Path,
screenshot_path: &Path,
env_vars: &[(&str, &str)],
tape_path: &Path,
) -> Result<PathBuf, std::io::Error> {
let tape = self.to_vhs_tape(binary_path, screenshot_path, env_vars);
tape.write_to(tape_path)?;
Ok(tape_path.to_path_buf())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn scenario_builder_chains_steps() {
let scenario = Scenario::new("test")
.write_text("hello")
.press_key("Enter")
.sleep_ms(100)
.capture();
assert_eq!(scenario.name, "test");
assert_eq!(scenario.steps.len(), 4);
}
#[test]
fn scenario_compiles_to_vhs_tape() {
let scenario = Scenario::new("startup").sleep_ms(500).capture();
let tape = scenario.to_vhs_tape(
Path::new("/usr/bin/echo"),
Path::new("/tmp/screenshot.png"),
&[],
);
let content = tape.render();
assert!(content.contains("Screenshot"));
assert!(content.contains("Sleep"));
}
}