Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add custom parameter to FirefoxProfile? #56

Closed
zhiburt opened this issue Jun 3, 2021 · 10 comments
Closed

Add custom parameter to FirefoxProfile? #56

zhiburt opened this issue Jun 3, 2021 · 10 comments

Comments

@zhiburt
Copy link
Contributor

zhiburt commented Jun 3, 2021

Hello @stevepryde I was trying to set a custom User-Agent for geckodriver as I understand to set it we should do the following in python

profile = webdriver.FirefoxProfile()
profile.set_preference("general.useragent.override", "whatever you want")

But as I see there's no such option currently

pub struct FirefoxProfile {
#[serde(rename = "webdriver_accept_untrusted_certs", skip_serializing_if = "Option::is_none")]
pub accept_untrusted_certs: Option<bool>,
#[serde(rename = "webdriver_assume_untrusted_issuer", skip_serializing_if = "Option::is_none")]
pub assume_untrusted_issuer: Option<bool>,
#[serde(rename = "webdriver.log.driver", skip_serializing_if = "Option::is_none")]
pub log_driver: Option<FirefoxProfileLogDriver>,
#[serde(rename = "webdriver.log.file", skip_serializing_if = "Option::is_none")]
pub log_file: Option<String>,
#[serde(rename = "webdriver.load.strategy", skip_serializing_if = "Option::is_none")]
pub load_strategy: Option<String>,
#[serde(rename = "webdriver_firefox_port", skip_serializing_if = "Option::is_none")]
pub webdriver_port: Option<u16>,
}

I could imagine that there's a bigger list of such settings so might a custom parameter not a bad idea?

PS: I didn't test setting of preference

@stevepryde
Copy link
Owner

Yeah I think that is a good idea. As for how to adapt what is there, I'm not sure. Feel free to submit a PR if you have an idea of how you'd like to solve it.

@audioXD
Copy link
Contributor

audioXD commented Jul 3, 2021

@stevepryde
Does FirefoxProfile even work?

Error: An argument passed to the WebDriver server was invalid:     
    Status: 400
    Additional info:
        profile is not a string
        Error: invalid argument
        Stacktrace:

Because this says it only accepts a Base64 encoded string

Fix: #60

@audioXD
Copy link
Contributor

audioXD commented Jul 3, 2021

@zhiburt
And for the above issue I found this

let mut caps = FirefoxCapabilities::new();
let prefs: serde_json::Value = serde_json::json!({
    "general.useragent.override": "Custom"
});
caps.add_firefox_option("prefs", prefs)?;

@audioXD
Copy link
Contributor

audioXD commented Jul 3, 2021

Simple test

use anyhow::Result;
use thirtyfour::{FirefoxCapabilities, WebDriver, WebDriverCommands};

#[tokio::main]
pub async fn main() -> Result<()> {
    // User agent string
    let user_agent = "Custom";

    // Set user agent in capabilities
    let mut caps = FirefoxCapabilities::new();
    caps.add_firefox_option(
        "prefs",
        serde_json::json!({ "general.useragent.override": user_agent }),
    )?;

    // Start webdriver and get user agent string
    let c = WebDriver::new("http://localhost:4445", caps).await?;
    c.get("https://www.google.si").await?;
    let js_user_agent: serde_json::Value = c
        .execute_script(r#"return navigator.userAgent;"#)
        .await?
        .convert()?;

    // Test
    assert_eq!(user_agent, &js_user_agent);

    // Exit
    c.close().await?;
    Ok(())
}

@audioXD
Copy link
Contributor

audioXD commented Jul 3, 2021

Maye an impl like this:

This code goes in Capabilities (This is for adding keys and supporting mutiple nestings)

fn add_key(
    &mut self,
    key: &[&str],
    subkey: &str,
    value: impl Serialize,
) -> WebDriverResult<()> {
    let mut v = self.get_mut();
    let part = &[subkey];
    let mut keys = key.into_iter().chain(part.iter()).peekable();

    // Move to last avaliable key
    while let Some(key) = keys.peek() {
        if v[key].is_null() {
            break;
        }
        v = &mut v[key];
        keys.next();
    }

    // Create missing nested objects
    for key in keys {
        v[key] = json!({});
        v = &mut v[key];
    }

    // Set value
    *v = to_value(value)?;

    Ok(())
}

This code goes in FirefoxCapabilities

fn set_preference(
    &mut self,
    key: &str,
    value: impl Serialize,
) -> WebDriverResult<()> {
    self.add_key(&["moz:firefoxOptions", "prefs"], key, value)
}

@audioXD
Copy link
Contributor

audioXD commented Jul 3, 2021

Or renaming FirefoxProfile into FirefoxPreferences and having it work the same as Capabilities
AKA having helper methods like set_user_agent(agent: &str), ... and a genric methods like set(key: &str, value impl Serialize), unset(key: &str), ...

@stevepryde
Copy link
Owner

Or renaming FirefoxProfile into FirefoxPreferences and having it work the same as Capabilities
AKA having helper methods like set_user_agent(agent: &str), ... and a genric methods like set(key: &str, value impl Serialize), unset(key: &str), ...

I like this option. However I don't have bandwidth for this currently. Would you be interested in making this change?

@audioXD
Copy link
Contributor

audioXD commented Jul 5, 2021

@stevepryde did it. #61

@stevepryde
Copy link
Owner

Thanks so much for this. I've also added your above "test" as examples/firefox_preferences.rs (modified a little to align with other examples).

@zhiburt
Copy link
Contributor Author

zhiburt commented Jul 6, 2021

So I suppose the issue can be closed?

Good job @audioXD

@zhiburt zhiburt closed this as completed Jul 6, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants