use std::time::Duration; use thirtyfour::error::no_such_element; use thirtyfour::prelude::*; /// Find the first visible element matching a CSS selector. /// The `/add` page has duplicate `name` fields across tabbed forms (roaster, roast, etc.) /// hidden via Datastar `data-show`. This ensures we interact with the active form's fields. async fn find_visible(driver: &WebDriver, css: &str) -> WebDriverResult { let elements = driver.find_all(By::Css(css)).await?; for el in elements { if el.is_displayed().await.unwrap_or(false) { return Ok(el); } } Err(no_such_element(format!( "No visible element found for selector: {css}" ))) } /// Fill a text input identified by its `name` attribute. /// Finds the first *visible* match to avoid hidden duplicate fields on tabbed pages. pub async fn fill_input(driver: &WebDriver, name: &str, value: &str) -> WebDriverResult<()> { let input = find_visible(driver, &format!("input[name='{name}']")).await?; input.clear().await?; input.send_keys(value).await?; Ok(()) } /// Fill a textarea identified by its `name` attribute. /// Finds the first *visible* match to avoid hidden duplicate fields on tabbed pages. pub async fn fill_textarea(driver: &WebDriver, name: &str, value: &str) -> WebDriverResult<()> { let textarea = find_visible(driver, &format!("textarea[name='{name}']")).await?; textarea.clear().await?; textarea.send_keys(value).await?; Ok(()) } /// Select an option from a native `