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");