Skip to content

Commit 5450204

Browse files
authored
Merge pull request #20 from CloudCannon/feat/scroll
Add `I scroll to the selector`
2 parents 970f1b3 + 2fbd020 commit 5450204

3 files changed

Lines changed: 81 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99

1010
## Unreleased
1111

12+
* Added browser instruction: `In my browser, I scroll to the selector {selector}`
13+
* NB: Click and hover steps already handled this, so this new instruction is primarily useful for screenshots.
14+
1215
## v0.12.0 (March 21, 2025)
1316

1417
* Added a `toolproof_test_port` default placeholder.

docs/content/docs/functions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ Instructions:
4545
- `In my browser, I hover {text}`
4646
- `In my browser, I click the selector {selector}`
4747
- `In my browser, I hover the selector {selector}`
48+
- `In my browser, I scroll to the selector {selector}`
4849
- `In my browser, I press the {keyname} key`
4950
- `In my browser, I type {text}`
5051

toolproof/src/definitions/browser/mod.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,50 @@ impl BrowserWindow {
515515
}
516516
}
517517

518+
async fn scroll_selector(
519+
&self,
520+
selector: &str,
521+
timeout_secs: u64,
522+
) -> Result<(), ToolproofStepError> {
523+
match self {
524+
BrowserWindow::Chrome(page) => {
525+
loop {
526+
let element = browser_specific::wait_for_chrome_element_selector(
527+
page,
528+
selector,
529+
timeout_secs,
530+
)
531+
.await?;
532+
533+
if let Err(e) = element.scroll_into_view().await {
534+
match e {
535+
// If the element was detached from the DOM after the time we selected it,
536+
// we want to restart this section and select a new element.
537+
CdpError::ScrollingFailed(msg) if msg.contains("detached") => continue,
538+
_ => {
539+
return Err(ToolproofStepError::Assertion(
540+
ToolproofTestFailure::Custom {
541+
msg: format!(
542+
"Element {selector} could not be scrolled into view: {e}"
543+
),
544+
},
545+
))
546+
}
547+
}
548+
}
549+
break;
550+
}
551+
552+
Ok(())
553+
}
554+
BrowserWindow::Pagebrowse(_) => Err(ToolproofStepError::Internal(
555+
ToolproofInternalError::Custom {
556+
msg: "Scrolls not yet implemented for Pagebrowse".to_string(),
557+
},
558+
)),
559+
}
560+
}
561+
518562
async fn press_key(&self, key: &str, timeout_secs: u64) -> Result<(), ToolproofStepError> {
519563
match self {
520564
BrowserWindow::Chrome(page) => {
@@ -929,6 +973,39 @@ mod interactions {
929973
}
930974
}
931975

976+
pub struct ScrollSelector;
977+
978+
inventory::submit! {
979+
&ScrollSelector as &dyn ToolproofInstruction
980+
}
981+
982+
#[async_trait]
983+
impl ToolproofInstruction for ScrollSelector {
984+
fn segments(&self) -> &'static str {
985+
"In my browser, I scroll to the selector {selector}"
986+
}
987+
988+
async fn run(
989+
&self,
990+
args: &SegmentArgs<'_>,
991+
civ: &mut Civilization,
992+
) -> Result<(), ToolproofStepError> {
993+
let selector = args.get_string("selector")?;
994+
995+
let Some(window) = civ.window.as_ref() else {
996+
return Err(ToolproofStepError::External(
997+
ToolproofInputError::StepRequirementsNotMet {
998+
reason: "no page has been loaded into the browser for this test".into(),
999+
},
1000+
));
1001+
};
1002+
1003+
window
1004+
.scroll_selector(&selector, auto_selector_timeout(civ))
1005+
.await
1006+
}
1007+
}
1008+
9321009
pub struct PressKey;
9331010

9341011
inventory::submit! {

0 commit comments

Comments
 (0)