Skip to content

Commit

Permalink
Merge pull request #16 from CloudCannon/feat/typing
Browse files Browse the repository at this point in the history
Initial keypress/typing support
  • Loading branch information
bglw authored Feb 13, 2025
2 parents a7f88ad + f45878b commit c45c82c
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 1 deletion.
2 changes: 2 additions & 0 deletions docs/content/docs/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ Instructions:
- `In my browser, I hover {text}`
- `In my browser, I click the selector {selector}`
- `In my browser, I hover the selector {selector}`
- `In my browser, I press the {keyname} key`
- `In my browser, I type {text}`

Retrievals:
- `In my browser, the result of {js}`
Expand Down
5 changes: 4 additions & 1 deletion toolproof/src/definitions/browser/browser_specific.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use std::path::PathBuf;

use chromiumoxide::cdp::browser_protocol::page::CaptureScreenshotFormat;
use chromiumoxide::cdp::browser_protocol::{
input::{DispatchKeyEventParams, DispatchKeyEventType},
page::CaptureScreenshotFormat,
};

use crate::errors::{ToolproofInputError, ToolproofStepError, ToolproofTestFailure};

Expand Down
89 changes: 89 additions & 0 deletions toolproof/src/definitions/browser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,29 @@ impl BrowserWindow {
)),
}
}

async fn press_key(&self, key: &str, timeout_secs: u64) -> Result<(), ToolproofStepError> {
match self {
BrowserWindow::Chrome(page) => {
let dom =
browser_specific::wait_for_chrome_element_selector(page, "body", timeout_secs)
.await?;

dom.press_key(key).await.map_err(|e| {
ToolproofStepError::Assertion(ToolproofTestFailure::Custom {
msg: format!("Key {key} could not be pressed: {e}"),
})
})?;

Ok(())
}
BrowserWindow::Pagebrowse(_) => Err(ToolproofStepError::Internal(
ToolproofInternalError::Custom {
msg: "Keystrokes not yet implemented for Pagebrowse".to_string(),
},
)),
}
}
}

mod load_page {
Expand Down Expand Up @@ -875,4 +898,70 @@ mod interactions {
.await
}
}

pub struct PressKey;

inventory::submit! {
&PressKey as &dyn ToolproofInstruction
}

#[async_trait]
impl ToolproofInstruction for PressKey {
fn segments(&self) -> &'static str {
"In my browser, I press the {keyname} key"
}

async fn run(
&self,
args: &SegmentArgs<'_>,
civ: &mut Civilization,
) -> Result<(), ToolproofStepError> {
let keyname = args.get_string("keyname")?;

let Some(window) = civ.window.as_ref() else {
return Err(ToolproofStepError::External(
ToolproofInputError::StepRequirementsNotMet {
reason: "no page has been loaded into the browser for this test".into(),
},
));
};

window.press_key(&keyname, auto_selector_timeout(civ)).await
}
}

pub struct TypeText;

inventory::submit! {
&TypeText as &dyn ToolproofInstruction
}

#[async_trait]
impl ToolproofInstruction for TypeText {
fn segments(&self) -> &'static str {
"In my browser, I type {text}"
}

async fn run(
&self,
args: &SegmentArgs<'_>,
civ: &mut Civilization,
) -> Result<(), ToolproofStepError> {
let text = args.get_string("text")?;

let Some(window) = civ.window.as_ref() else {
return Err(ToolproofStepError::External(
ToolproofInputError::StepRequirementsNotMet {
reason: "no page has been loaded into the browser for this test".into(),
},
));
};

for c in text.split("").filter(|s| !s.is_empty()) {
window.press_key(c, auto_selector_timeout(civ)).await?;
}

Ok(())
}
}
}

0 comments on commit c45c82c

Please sign in to comment.