Search code examples
javaseleniumcucumber

Run step to open browser in cucumber / selenium test once before running all scenario examples then run step to close browser afterwards


Apologies for poorly worded question. I am new to test automation and selenium / cucumber BDD and am trying to create a demo project that runs some maths expressions using google and validates the results. I want to use a scenario outline so have ..

Scenario Outline: Enter a maths expression
    Given User enters the maths expression <expression>
    When the user clicks the Search button
    Then The result of <expectedResult> is returned  
Examples: 
    | expression | expectedResult |
    | 4+4 | 8 | 
    | 5^3 | 125 |  

I had my steps to open the chrome browser and navigate to google in the @Before method like ..

@Before
public void setup() throws Throwable {
    System.setProperty("webdriver.chrome.driver","C:\xxx\\chromedriver.exe");
    this.driver = new ChromeDriver();
    this.driver.manage().window().maximize();
    this.driver.manage().timeouts().pageLoadTimeout(60, TimeUnit.SECONDS);
    this.driver.manage().timeouts().setScriptTimeout(60, TimeUnit.SECONDS);
    driver.get("https://google.com");
    Thread.sleep(2000);
    //agrees to the terms and conditions
    driver.findElement(By.xpath("//*[@id=\"L2AGLb\"]/div")).click();
}

When I run my feature it works but for every example in the Scenario Outline it runs the before steps (as appears to be expected behaviour from reading online) i.e. browser opens and closes for each example.

Ideally I would want the browser to open once at start, run through all examples and then close at end. Is there an appropriate method annotation that I can use to achieve this. I have tried to find the answer online but not had any luck. One post mentioned using @BeforeSuite but I just for errors when I tried to use this. Also I tried to use the @Background annotation but this did the same thing as it seems this runs for every scenario example.

Any help would be much appreciated.


Solution

  • You are correct in your assertion. The Cucumber Hook @Before will execute methods tagged with this annotation before the first step of each scenario [See: Cucumber Reference]. Obviously, if you do not want to open and close the browser before and after each scenario, then you can't add that code there. Unfortunately, Cucumber does not have a hook to run "Before Suite" like JUnit or TestNG have. So, you cannot run something before all or after all like you can on those unit test platforms.

    A trick I have used is to initialize the driver and then store it as a global variable in a utility class. This way, I can reuse the same instance for an entire test session. Also, you can create an init scenario and run that will your scenarios.

    @StartBrowser
    Scenario: Start browser session
      When I initialize driver
      Then open browser
    

    In the code...

    public class BrowserInitStepDefinitions {
        @When("I initialize driver")
        public void initializeDriver() {
            System.setProperty("webdriver.chrome.driver","C:\xxx\\chromedriver.exe");
            WebDriverUtils.setDriver(new ChromeDriver());
        }
    
        @Then ("open browser")
        public void openBrowser() {
            WebDriver driver = WebDriverUtils.getDriver();
            driver.get("https://www.yourwebsite.com");
        }
    
        @Then ("close browser")
        public void closeBrowser() {
            WebDriver driver = WebDriverUtils.getDriver();
            driver.quit();
        }
    }
    
    public class WebDriverUtils {
        private static WebDriver driver;
        public static void setDriver(WebDriver webDdriver) {
            if (driver == null) {
                driver = webDdriver;
            }
        }
        public static WebDriver getDriver() {
            if (driver == null) {
                throw new AssertionError("Driver is null. Initialize driver before calling this method.");
            }
            return driver;
        }
    }
    

    Lastly, when you call your scenarios, just remember to include these scenarios first.

    @RunWith(Cucumber.class)
    @CucumberOptions(plugin = {"pretty", "html:target/cucumber-report.html"},
            features= "features",
            glue= {"whatever"},
            tags= "@StartBrowser or @MyTest1 or @MyTest2"
            )
    public class TestRunner {
        // code omitted
    }
    

    You could (and most likely should) create a scenario to close your browser and reclaim any resources that you might've used during the execution of your tests.