This post shows how to set a webdriver instance produced by thirtyfour as a member of the World struct defined by Cucumber-rs. We hope to follow up with one more simple post on How to use thirtyfour crate with Cucumber-rs showing ways to write browser driven BDD test automation in Rust using thirtyfour and Cucumber-rs.
Why bother writing browser automation in Rust?
Qxf2 has begun to enjoy writing Rust. All engineers at our company have done the hard work of getting familiar with Rust and trying small projects. We are now in the phase of preparing to write tests in Rust ecosystems. We are looking to work with companies that use Rust. UI automation is (thankfully) not needed as much in the Rust ecosystem. However, we do foresee it being a tiny portion of our testing strategy. In the Rust world, thirtyfour is a popular crate that works with Selenium webdriver. Cucumber-rs is a framework that lets us write BDD tests.
Setup
The setup for running Cucumber Rust tests with thirtyfour crate requires you to add the following crate to the Cargo.toml file
cucumber = "0.19" thirtyfour = { version = "0.31.0", features = ["component"] } |
Remember to add the features along with the version in thirtyfour crate. We faced an issue here while not using it. The component feature flag enables the component to derive macro via thirtyfour macros.
Problem statement
Things were going well while writing the Cucumber test with Rust when we encountered an issue where we wanted the Webdriver to be global so that it can be used across all the functions in the code.
I had the following struct in the code.
#[derive(cucumber::World, Default)] struct World { pub driver: Option<WebDriver>, } |
I have tried to use the driver in the World struct, so that it can be used across the code. Straight way right but Wait!, the problem comes here. If you only have the following struct and use World::run in your main function to run the tests, it will complain of the following error.
`World` doesn’t implement `std::fmt::Debug` and the trait `std::fmt::Debug` is not implemented for `World`
So, the obvious thing is to add #[derive(Debug)] in the World Struct and make it work but adding that in derive throws the following:
`thirtyfour::WebDriver` doesn’t implement `std::fmt::Debug`
So, it’s obvious from the message now that thirty-four::WebDriver doesn’t implement Debug trait, and as we are working with web automation, we would need WebDriver. So, what’s next?
Implementing Debug trait
So, the solution for the above problem was manually implementing the debug trait for WebDriver. To implement the trait, we use a function fmt which has a self-reference to the struct World and a mutable instance of Formatter. Since Rust is not able to automatically derive the debug trait for the struct element “driver”, we assist it as follows.
impl fmt::Debug for World { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("World") .field("driver", &self.driver.as_ref().map(|_| "<WebDriver>")) .finish() } } |
What is happening in the above snippet? We explicitly tell Rust that we are providing the Debug implementation for the “driver” field of the World struct. Since we do not really need the details of the Webdriver element in the debug statement, we just map the field to a string literal. “WebDriver” in our case. You can use any other string literal here or even implement a function to get the driver’s version and browser’s name. The rest of the magic in this trait implementation is the standard way to implement the Debug trait for an element.
Initializing the driver to be used across the functions
In the beginning, I mentioned that we wanted to use the driver across all the functions and hence we implemented it in World struct.
To use the driver across, we first need to initialize it.
fn example_initialize(world: &mut World) -> WebDriverResult<()> { //code world.driver=Some(driver); //Initialize the driver } |
Once, you have initialized the driver, next we can use it as a reference in other functions.
fn example_use_driver(world: &mut World) -> WebDriverResult<()> { let driver = world.driver.as_ref().expect("The driver is needed before you proceed"); //code } |
Running the tests
Here is an example of a BDD test with a scenario outline running on my machine. I hope to be able to share the entire code for it in a future tutorial.
Hire Qxf2 for all your testing needs
Qxf2 is the home of the technical tester. We have experience with implementing a wide variety of testing stacks. Our engineers work well with small engineering teams and love the challenge of testing early stage products. If you are looking for good software testers who can work on Rust or other projects, drop us a note here.
My journey in software testing began with Calabash and Cucumber, where I delved into Mobile Automation using Ruby. As my career progressed, I gained experience working with a diverse range of technical tools. These include e-Discovery, Selenium, Python, Docker, 4G/5G testing, M-CORD, CI/CD implementation, Page Object Model framework, API testing, Testim, WATIR, MockLab, Postman, and Great Expectation. Recently, I’ve also ventured into learning Rust, expanding my skillset further. Additionally, I am a certified Scrum Master, bringing valuable agile expertise to projects.
On the personal front, I am a very curious person on any topic. According to Myers-Briggs Type Indicator, I am described as INFP-T. I like playing soccer, running and reading books.