Running identical Cucumber test scenarios with both Selenium WebDriver and headless browser execution

I’m working on automated testing for web apps using Cucumber framework. Right now I have my test steps configured to work with a headless browser setup, which runs pretty smoothly. But sometimes I need to execute the same test scenarios using Selenium WebDriver for visual debugging or other purposes.

I’m thinking about a couple of ways to handle this:

  1. Modify each step definition to check some configuration setting and execute the appropriate browser interaction based on that
  2. Create separate step files for each browser type and load the right ones based on my test configuration

What’s the best practice for handling this kind of dual browser setup? Has anyone dealt with something similar before?

I’ve been running this setup for three years and learned some hard lessons. The factory pattern works well, but take it further - use a driver manager singleton that handles both setup and cleanup. Skip hardcoding browser types. I use a simple YAML config for browser mode, timeouts, and other settings. The driver manager reads it at startup and creates the right WebDriver instance. Keep your page object model completely browser-agnostic. Your step definitions shouldn’t know if they’re running headless or not. Our team can switch between modes without touching test code. One gotcha: make sure implicit waits and element strategies work the same in both modes. Headless browsers sometimes handle timing differently, so you might need different wait conditions.

Both approaches work, but you’ll hate maintaining them later. Every new test means duplicating effort or making your step definitions more complex.

I hit this exact issue last year. Our QA team needed headless runs for CI and visual debugging locally. Instead of changing all our Cucumber steps, I built an automation workflow that handles browser switching at execution level.

The solution monitors your test config and spins up the right browser environment before Cucumber even starts. Need headless? It configures that. Need visual debugging? It switches to full Selenium WebDriver without touching any step definitions.

This keeps your test code clean and kills the need for duplicate step files or config checks scattered everywhere. Just run your tests normally - the automation handles everything behind the scenes.

The workflow also logs which browser mode ran for each test, so tracking down issues later is way easier.

You can set this up pretty easily with Latenode’s browser automation features. It handles both headless and visual browser modes seamlessly: https://latenode.com

The Problem:

You’re using the Cucumber framework for automated web app testing and want to seamlessly switch between headless browser testing and Selenium WebDriver for visual debugging, without modifying your existing step definitions or creating numerous separate step files. You’re exploring strategies to manage this dual-browser setup efficiently.

:thinking: Understanding the “Why” (The Root Cause):

Directly modifying step definitions to handle different browser types (headless vs. Selenium WebDriver) leads to tightly coupled code, making maintenance a nightmare as your test suite grows. Similarly, creating separate step files for each browser type results in significant code duplication and increases complexity. The ideal solution keeps your Cucumber step definitions clean and browser-agnostic, abstracting away the browser-specific logic. This allows for easy maintainability and scalability as new tests are added or browser types change.

:gear: Step-by-Step Guide:

  1. Create a WebDriver Abstraction Layer: Implement an abstraction layer (e.g., a WebDriverFactory class) that handles the creation and management of WebDriver instances. This layer will be responsible for determining the appropriate browser type (headless or Selenium WebDriver) based on configuration settings (e.g., an environment variable, a configuration file, or command-line arguments).

    public class WebDriverFactory {
    
        public static WebDriver getWebDriver() {
            String browserType = System.getProperty("browser", "headless"); // Default to headless
    
            switch (browserType.toLowerCase()) {
                case "headless":
                    // Configure headless Chrome or Firefox WebDriver
                    ChromeOptions chromeOptions = new ChromeOptions();
                    chromeOptions.addArguments("--headless", "--disable-gpu");
                    return new ChromeDriver(chromeOptions);
                case "selenium":
                    // Configure Selenium WebDriver
                    return new ChromeDriver(); // Or FirefoxDriver, etc.
                default:
                    throw new IllegalArgumentException("Unsupported browser type: " + browserType);
            }
        }
    }
    
  2. Modify Your Step Definitions: In your Cucumber step definitions, instead of directly instantiating the WebDriver, use the WebDriverFactory to retrieve an instance:

    @Given("^I navigate to the homepage$")
    public void iNavigateToTheHomepage() {
        WebDriver driver = WebDriverFactory.getWebDriver();
        driver.get("https://www.example.com");
    }
    
  3. Configure Browser Type: Set the browser system property (or your chosen configuration mechanism) to control the browser type used. For example, to run tests with Selenium WebDriver, you could use:

    -Dbrowser=selenium mvn test
    

    or update your configuration file accordingly.

:mag: Common Pitfalls & What to Check Next:

  • Implicit Waits and Explicit Waits: Ensure that your implicit waits and explicit waits are correctly configured to handle potential timing differences between headless and full browser modes. Headless browsers often interact differently with web elements concerning load times.
  • Capabilities Management: Implement robust capabilities management within your WebDriverFactory. Ensure all desired capabilities (e.g., browser size, screen resolution, logging preferences) are correctly set for both headless and non-headless modes.
  • Error Handling: Include comprehensive error handling within your WebDriverFactory to gracefully handle situations like WebDriver initialization failures or unsupported browser types.

:speech_balloon: Still running into issues? Share your (sanitized) config files, the exact command you ran, and any other relevant details. The community is here to help!

i think option 1’s really good but make it better. build a browser factory class that gives you the headless or regular WebDriver depending on an env setting or config file. this way, your step defs call the factory method instead of sticking with browser setups. less code dup and easier to keep track of.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.