Skip to content

Commit f848ee5

Browse files
authored
Merge pull request #278 from ling0x/ling/add-init-script
feat: add init script
2 parents 3361e00 + 6f6faca commit f848ee5

5 files changed

Lines changed: 166 additions & 2 deletions

File tree

examples/add-init-script.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
use chromiumoxide::browser::{Browser, BrowserConfig};
2+
use futures::StreamExt;
3+
4+
#[tokio::main]
5+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
6+
tracing_subscriber::fmt::init();
7+
8+
let (browser, mut handler) =
9+
Browser::launch(BrowserConfig::builder().with_head().build()?).await?;
10+
11+
let handle = tokio::spawn(async move {
12+
loop {
13+
let _ = handler.next().await.unwrap();
14+
}
15+
});
16+
17+
let page = browser.new_page("about:blank").await?;
18+
19+
// Add the init script BEFORE navigation
20+
page.add_init_script(
21+
r#"
22+
Object.defineProperty(navigator, 'webdriver', {
23+
get: () => undefined
24+
});
25+
"#,
26+
)
27+
.await?;
28+
29+
// Navigate to a page
30+
page.goto("https://www.wikipedia.org")
31+
.await?
32+
.find_element("h1")
33+
.await?;
34+
35+
let _html = page.wait_for_navigation().await?.content().await?;
36+
37+
handle.await?;
38+
Ok(())
39+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
use chromiumoxide::browser::{Browser, BrowserConfig};
2+
use futures::StreamExt;
3+
4+
#[tokio::main]
5+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
6+
tracing_subscriber::fmt::init();
7+
8+
let (browser, mut handler) =
9+
Browser::launch(BrowserConfig::builder().with_head().build()?).await?;
10+
11+
let handle = tokio::spawn(async move {
12+
loop {
13+
let _ = handler.next().await.unwrap();
14+
}
15+
});
16+
17+
let page = browser.new_page("about:blank").await?;
18+
19+
// Add the init script BEFORE navigation
20+
page.evaluate_on_new_document(
21+
r#"
22+
Object.defineProperty(navigator, 'webdriver', {
23+
get: () => undefined
24+
});
25+
"#,
26+
)
27+
.await?;
28+
29+
// Navigate to a page
30+
page.goto("https://www.wikipedia.org")
31+
.await?
32+
.find_element("h1")
33+
.await?;
34+
35+
let _html = page.wait_for_navigation().await?.content().await?;
36+
37+
handle.await?;
38+
Ok(())
39+
}

src/page.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,15 +1146,43 @@ impl Page {
11461146
self.inner.frame_secondary_execution_context(frame_id).await
11471147
}
11481148

1149-
/// Evaluates given script in every frame upon creation (before loading
1150-
/// frame's scripts)
1149+
/// Evaluates given script in every frame upon creation (before loading frame's scripts).
1150+
///
1151+
/// This is equivalent to Playwright's `addInitScript()` or Puppeteer's `evaluateOnNewDocument()`.
1152+
/// Useful for modifying the JavaScript environment before page scripts run, such as:
1153+
/// - Hiding automation detection properties
1154+
/// - Injecting polyfills
1155+
/// - Setting up global variables
1156+
///
1157+
/// # Example
1158+
/// ```
1159+
/// # use chromiumoxide::page::Page;
1160+
/// # async fn example(page: Page) -> Result<(), Box<dyn std::error::Error>> {
1161+
/// // Hide webdriver property for stealth scraping
1162+
/// page.evaluate_on_new_document(r#"
1163+
/// Object.defineProperty(navigator, 'webdriver', {
1164+
/// get: () => undefined
1165+
/// });
1166+
/// "#).await?;
1167+
/// # Ok(())
1168+
/// # }
1169+
/// ```
11511170
pub async fn evaluate_on_new_document(
11521171
&self,
11531172
script: impl Into<AddScriptToEvaluateOnNewDocumentParams>,
11541173
) -> Result<ScriptIdentifier> {
11551174
Ok(self.execute(script.into()).await?.result.identifier)
11561175
}
11571176

1177+
/// Alias for `evaluate_on_new_document` - familiar to Playwright users.
1178+
#[inline]
1179+
pub async fn add_init_script(
1180+
&self,
1181+
script: impl Into<AddScriptToEvaluateOnNewDocumentParams>,
1182+
) -> Result<ScriptIdentifier> {
1183+
self.evaluate_on_new_document(script).await
1184+
}
1185+
11581186
/// Set the content of the frame.
11591187
///
11601188
/// # Example

tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use chromiumoxide::{Browser, BrowserConfig};
44
use futures::{FutureExt, StreamExt};
55

66
mod basic;
7+
mod page;
78

89
pub async fn test<T>(test: T)
910
where

tests/page.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
use crate::test;
2+
3+
#[tokio::test]
4+
async fn test_evaluate_on_new_document() {
5+
test(async |browser| {
6+
let page = browser
7+
.new_page("about:blank")
8+
.await
9+
.expect("should create new page");
10+
11+
page.evaluate_on_new_document("window.testValue = 42;")
12+
.await
13+
.expect("should evaluate script on new document");
14+
15+
page.goto("https://www.google.com")
16+
.await
17+
.expect("should navigate to www.google.com");
18+
19+
let result: i32 = page
20+
.evaluate("window.testValue")
21+
.await
22+
.expect("should evaluate window.testValue")
23+
.into_value()
24+
.expect("should convert to i32");
25+
26+
assert_eq!(result, 42);
27+
})
28+
.await;
29+
}
30+
31+
#[tokio::test]
32+
async fn test_add_init_script() {
33+
test(async |browser| {
34+
let page = browser
35+
.new_page("about:blank")
36+
.await
37+
.expect("should create new page");
38+
39+
page.add_init_script("window.testValue = 42;")
40+
.await
41+
.expect("should add init script");
42+
43+
page.goto("https://www.google.com")
44+
.await
45+
.expect("should navigate to www.google.com");
46+
47+
let result: i32 = page
48+
.evaluate("window.testValue")
49+
.await
50+
.expect("should evaluate window.testValue")
51+
.into_value()
52+
.expect("should convert to i32");
53+
54+
assert_eq!(result, 42);
55+
})
56+
.await;
57+
}

0 commit comments

Comments
 (0)