thirtyfour/
lib.rs

1//! Thirtyfour is a Selenium / WebDriver library for Rust, for automated website UI testing.
2//!
3//! It supports the W3C WebDriver v1 spec.
4//! Tested with Chrome and Firefox, although any W3C-compatible WebDriver
5//! should work.
6//!
7//! ## Getting Started
8//!
9//! Check out [The Book](https://vrtgs.github.io/thirtyfour/) 📚!
10//!
11//! ## Features
12//!
13//! - All W3C WebDriver and WebElement methods supported
14//! - Async / await support (tokio only)
15//! - Create new browser session directly via WebDriver (e.g. chromedriver)
16//! - Create new browser session via Selenium Standalone or Grid
17//! - Find elements (via all common selectors e.g. Id, Class, CSS, Tag, XPath)
18//! - Send keys to elements, including key-combinations
19//! - Execute Javascript
20//! - Action Chains
21//! - Get and set cookies
22//! - Switch to frame/window/element/alert
23//! - Shadow DOM support
24//! - Alert support
25//! - Capture / Save screenshot of browser or individual element as PNG
26//! - Some Chrome DevTools Protocol (CDP) support
27//! - Advanced query interface including explicit waits and various predicates
28//! - Component Wrappers (similar to `Page Object Model`)
29//!
30//! ## Feature Flags
31//!
32//! * `rustls-tls`: (Default) Use rustls to provide TLS support (via reqwest).
33//! * `native-tls`: Use native TLS (via reqwest).
34//! * `component`: (Default) Enable the `Component` derive macro (via thirtyfour-macros).
35//!
36//! ## Example
37//!
38//! The following example assumes you have chromedriver running locally, and
39//! a compatible version of Chrome installed.
40//!
41//! ```no_run
42//! use thirtyfour::prelude::*;
43//!
44//! #[tokio::main]
45//! async fn main() -> WebDriverResult<()> {
46//!     let caps = DesiredCapabilities::chrome();
47//!     let driver = WebDriver::new("http://localhost:9515", caps).await?;
48//!
49//!     // Navigate to https://wikipedia.org.
50//!     driver.goto("https://wikipedia.org").await?;
51//!     let elem_form = driver.find(By::Id("search-form")).await?;
52//!
53//!     // Find element from element.
54//!     let elem_text = elem_form.find(By::Id("searchInput")).await?;
55//!
56//!     // Type in the search terms.
57//!     elem_text.send_keys("selenium").await?;
58//!
59//!     // Click the search button.
60//!     let elem_button = elem_form.find(By::Css("button[type='submit']")).await?;
61//!     elem_button.click().await?;
62//!
63//!     // Look for header to implicitly wait for the page to load.
64//!     driver.find(By::ClassName("firstHeading")).await?;
65//!     assert_eq!(driver.title().await?, "Selenium - Wikipedia");
66//!
67//!     // explicitly close the browser.
68//!     driver.quit().await?;
69//!
70//!     Ok(())
71//! }
72//! ```
73//!
74//! ### The browser will not close automatically
75//!
76//! Rust does not have [async destructors](https://boats.gitlab.io/blog/post/poll-drop/),
77//! and so whenever you forget to use [`WebDriver::quit`] the webdriver will have to block the executor
78//! to drop itself and will also ignore errors while dropping, so if you know when a webdriver is no longer used
79//! it is recommended to more or less "asynchronously drop" via a call to [`WebDriver::quit`] as in the above example.
80//! This also allows you to catch errors during quitting, and possibly panic or report back to the user
81//!
82//! If you do not call [`WebDriver::quit`] **your async executor will be blocked** meaning no futures can run
83//! while quiting. you can use the feature `debug_sync_quit` to get a backtrace printed if your webdriver ever
84//! quits synchronously
85//!
86//! ### Advanced element queries and explicit waits
87//!
88//! You can use [`WebDriver::query`] to perform more advanced queries
89//! including polling and filtering. Custom filter functions are also supported.
90//!
91//! Also, the [`WebElement::wait_until`] method provides additional support for explicit waits
92//! using a variety of built-in predicates. You can also provide your own custom predicate if
93//! desired.
94//!
95//! See the [`query`] documentation for more details and examples.
96//!
97//! [`WebDriver::query`]: extensions::query::ElementQueryable::query
98//! [`WebElement::wait_until`]: extensions::query::ElementWaitable::wait_until
99//! [`query`]: extensions::query
100//!
101//! ### Components
102//!
103//! Components allow you to wrap a web component using smart element resolvers that can
104//! automatically re-query stale elements, and much more.
105//!
106//! ```ignore
107//! #[derive(Debug, Clone, Component)]
108//! pub struct CheckboxComponent {
109//!     base: WebElement,
110//!     #[by(tag = "label", first)]
111//!     label: ElementResolver<WebElement>,
112//!     #[by(css = "input[type='checkbox']")]
113//!     input: ElementResolver<WebElement>,
114//! }
115//!
116//! impl CheckBoxComponent {
117//!     pub async fn label_text(&self) -> WebDriverResult<String> {
118//!         let elem = self.label.resolve().await?;
119//!         elem.text().await
120//!     }
121//!
122//!     pub async fn is_ticked(&self) -> WebDriverResult<bool> {
123//!         let elem = self.input.resolve().await?;
124//!         let prop = elem.prop("checked").await?;
125//!         Ok(prop.unwrap_or_default() == "true")
126//!     }
127//!
128//!     pub async fn tick(&self) -> WebDriverResult<()> {
129//!         if !self.is_ticked().await? {
130//!             let elem = self.input.resolve().await?;
131//!             elem.click().await?;
132//!             assert!(self.is_ticked().await?);
133//!         }
134//!         Ok(())
135//!     }
136//! }
137//! ```
138//!
139//! See the [`components`] documentation for more details.
140//!
141
142#![deny(missing_docs)]
143#![allow(unknown_lints)]
144#![warn(missing_debug_implementations, rustdoc::all)]
145#![forbid(unsafe_code)]
146#![allow(clippy::needless_doctest_main)]
147
148// Re-export StringMatch if needed.
149pub use stringmatch;
150
151// Export types at root level.
152pub use alert::Alert;
153pub use common::cookie;
154pub use common::{
155    capabilities::{
156        chrome::ChromeCapabilities,
157        chromium::{ChromiumCapabilities, ChromiumLikeCapabilities},
158        desiredcapabilities::*,
159        edge::EdgeCapabilities,
160        firefox::FirefoxCapabilities,
161        ie::InternetExplorerCapabilities,
162        opera::OperaCapabilities,
163        safari::SafariCapabilities,
164    },
165    command::By,
166    cookie::*,
167    keys::*,
168    requestdata::*,
169    types::*,
170};
171pub use switch_to::SwitchTo;
172pub use web_driver::WebDriver;
173pub use web_element::WebElement;
174
175/// Allow importing the common types via `use thirtyfour::prelude::*`.
176pub mod prelude {
177    pub use crate::alert::Alert;
178    pub use crate::error::{WebDriverError, WebDriverResult};
179    pub use crate::extensions::query::{ElementPoller, ElementQueryable, ElementWaitable};
180    pub use crate::session::scriptret::ScriptRet;
181    pub use crate::switch_to::SwitchTo;
182    pub use crate::WebDriver;
183    pub use crate::WebElement;
184    pub use crate::{
185        BrowserCapabilitiesHelper, By, Capabilities, CapabilitiesHelper, ChromiumLikeCapabilities,
186        DesiredCapabilities,
187    };
188    pub use crate::{Cookie, Key, SameSite, TimeoutConfiguration, TypingData, WindowHandle};
189}
190
191/// Action chains allow for more complex user interactions with the keyboard and mouse.
192pub mod action_chain;
193/// Alert handling.
194pub mod alert;
195/// Common wrappers used by both async and sync implementations.
196pub mod common;
197/// Components and component wrappers.
198pub mod components;
199/// Error wrappers.
200pub mod error;
201/// Extensions for specific browsers.
202pub mod extensions;
203/// Everything related to driving the underlying WebDriver session.
204pub mod session;
205/// Miscellaneous support functions for `thirtyfour` tests.
206pub mod support;
207
208mod js;
209mod switch_to;
210mod web_driver;
211mod web_element;
212
213const VERSION: &str = env!("CARGO_PKG_VERSION");