Search code examples
rust

Rust chromiumoxide library - how to click on the browser back button?


Suppose I have used the chromiumoxide library in rust to visit a couple of webpages:

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    
    // create a `Browser` that spawns a `chromium` process running with UI (`with_head()`, headless is default) 
    // and the handler that drives the websocket etc.
    let (mut browser, mut handler) =
        Browser::launch(BrowserConfig::builder().with_head().build()?).await?;
    
    // spawn a new task that continuously polls the handler
    let handle = tokio::task::spawn(async move {
        while let Some(h) = handler.next().await {
            if h.is_err() {
                break;
            }
        }
    });
    
    // create a new browser page and navigate to the url
    let page = browser.new_page("https://en.wikipedia.org").await?;
    page.wait_for_navigation().await?;

    // go to another url
    page.goto("https://www.example.com/").await?;
    page.wait_for_navigation().await?;

    // how do I now click the back button on the browser to go to the previous url?
    

    browser.close().await?;
    handle.await; 

    Ok(())

}

How do I now click the back button on the browser to visit the previous page?

(I'm aware that I could use page.goto() as an alternative, but this isn't what I want.)


Solution

  • It is currently an open issue to add Page::go_back and Page::go_forward, but you can implement them yourself using raw Commands with Page::execute:

    trait PageExt {
        fn go_back(&self) -> impl std::future::Future<Output = Result<()>> + Send;
    }
    
    impl PageExt for Page {
        async fn go_back(&self) -> Result<()> {
            let CommandResponse {
                result:
                    GetNavigationHistoryReturns {
                        current_index,
                        entries,
                    },
                ..
            } = self.execute(GetNavigationHistoryParams {}).await?;
            self.execute(NavigateToHistoryEntryParams {
                entry_id: entries
                    .get(current_index as usize - 1)
                    .ok_or(CdpError::NotFound)?
                    .id,
            })
            .await
            .map(|_| ())
        }
    }
    
    use chromiumoxide::cdp::browser_protocol::page::{
        GetNavigationHistoryParams, GetNavigationHistoryReturns, NavigateToHistoryEntryParams,
        NavigateToHistoryEntryReturns,
    };
    use chromiumoxide::error::{CdpError, Result};
    use chromiumoxide::Page;
    use chromiumoxide_types::CommandResponse;