Search code examples
javaseleniumcucumber

Mixing web and non-web cucumber/selenium tests avoiding web driver creation


I've inherited a Java/Cucumber test application and it mixes web/Selenium based tests and REST based tests.

When any test is ran, Cucumber is instantiating every class, e.g. my step and page factory classes. The problem is when running REST based tests the Chrome driver is started too and Chrome opens.

As below in the (cut-down code), the call to initElements() is the cause but I don't really understand if/when it's needed and how to remove/lazily load or somehow remove or move this call.

public class XXXPages {
    @FindBy(xpath = "//input[@id='user_name']")
    private WebElement usernameField;

    private WebDriverFactory webDriverFactory;

    public XXXPages(WebDriverFactory webDriverFactory) {
        this.webDriverFactory = webDriverFactory;
        //PROBLEM CALL
        PageFactory.initElements(webDriverFactory.getDriver(), this);

    }

    public XXXPages searchName() {
        WebDriverWait wait = new WebDriverWait(webDriverFactory.getDriver(), Duration.ofSeconds(3));
        wait.until(ExpectedConditions.elementToBeClickable(searchNamefield));
        searchNamefield.click();
        return this;
    }

}



public class WebDriverFactory implements Closeable {
    private RemoteWebDriver webDriver;
    final String driverPath = System.getProperty("webdriver.chrome.driver", "src/test/resources/drivers/linux/chromedriver");

    private void createDriver(){
        System.setProperty("webdriver.chrome.driver", driverPath);
        final ChromeOptions chromeOptions = new ChromeOptions();

        this.webDriver = new ChromeDriver(chromeOptions);
    }

    public RemoteWebDriver getDriver() {
        if (this.webDriver == null){
            createDriver();
            return webDriver;
        }
        return webDriver;
    }

    @Override
    public void close() {
        webDriver.quit();
    }

}

Solution

  • You need to design a wrapper for your driver in lazy initialization manner. Implement a class that would implement WebDriver interface and initialize the driver when the first call to the method happens. Like:

    public class LazyWebDriver implements WebDriver, Disposable {
    
        private WebDriver delegate = null;
    
        private WebDriver getDelegate() {
            if (delegate == null) {
                String driverPath = System.getProperty("webdriver.chrome.driver", "src/test/resources/drivers/linux/chromedriver");
                System.setProperty("webdriver.chrome.driver", driverPath);
                ChromeOptions chromeOptions = new ChromeOptions();
                delegate = new new ChromeDriver(chromeOptions);
            }
            return delegate;
        }
    
        @Override
        public void get(String url) {
            getDelegate().get(url);
        }
    
        // Override other methods here..
    }
    

    It might be useful for you to read this post where such approach is described in complete example.

    Using the above approach would make cucumber create object for LazyWebDriver which won't cause real driver creation. The driver will be created only if you will execute the tests that use it.