I've got a Java based Selenium setup which uses Cucumber to specify and run tests. Currently this runs using the Chrome driver, but ideally we would repeat the tests using Firefox and IE (and if possible in parallel), as the local users use all three. I am using Gradle as a build tool and would like to stick with that.
To try and work towards this approach I have implemented a JUnit based parallel testing setup which is described here, which works brilliantly and does exactly what I want. HOWEVER, this does not run through Cucumber but directly in JUnit, and I cannot see a simple way to adapt it.
I have found Zucchini, which seems to do exactly what I want it to do. HOWEVER the documentation on this is very sparse indeed and with my limited experience I am unable to set it up - I am new to testing, Selenium and Java and have inherited this framework which I am trying to extend. There is an example here which almost runs for me (fails on Firefox but that's likely my setup), but I am failing to implement it. Basically in my implementation the code runs, opens the driver and appears to immediately close it again. Then it returns a NullPointerException on the first step of the scenario (presumably as it cannot find the driver).
My feature file:
Feature: Visit Google and do an example search
Scenario: Navigate to the Google search homepage, search for "Cat", and check the first result is about cats
Given I visit the Google search page
When I enter the text "cat" into the search box
And I click the search button
Then I should see the top result mentioning cats
My setup code (similar to FirstZucchiniTest.java
in the example repo):
package stepDefinitions;
import java.util.ArrayList;
import java.util.List;
import com.comcast.zucchini.AbstractZucchiniTest;
import com.comcast.zucchini.TestContext;
import net.dimaj.zucchini.utils.Constants;
import cucumber.api.CucumberOptions;
import cucumber.api.Scenario;
import cucumber.api.java.Before;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
@CucumberOptions(
features = {"src/test/resources/features"},
plugin = {"pretty", "json:target/cucumber-report/json/cucumber-report.json", "html:target/cucumber-report"},
glue={"helpers","stepDefinitions"}
)
public class ZucchiniDefinitions extends AbstractZucchiniTest {
@Override
public List<TestContext> getTestContexts() {
List<TestContext> rv = new ArrayList<TestContext>();
TestContext chrome = new TestContext("chrome");
chrome.set(Constants.CONTEXT_BROWSER, new ChromeDriver());
rv.add(chrome);
TestContext ff = new TestContext("firefox");
ff.set(Constants.CONTEXT_BROWSER, new FirefoxDriver());
rv.add(ff);
return rv;
}
@Override
public void cleanup(TestContext out) {
WebDriver driver = out.get(Constants.CONTEXT_BROWSER);
if (null != driver) {
driver.quit();
}
}
}
The definitions for visiting Google:
package stepDefinitions;
import com.comcast.zucchini.TestContext;
import cucumber.api.java.en.And;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import org.openqa.selenium.WebDriver;
import pageFactory.examplePages.GoogleSearchHomepage;
import pageFactory.examplePages.GoogleSearchResultsPage;
import static net.dimaj.zucchini.utils.Constants.CONTEXT_BROWSER;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
public class GoogleDefinitions {
private WebDriver driver;
public GoogleDefinitions (BaseDefinitions baseDefinitions) {
this.driver = TestContext.getCurrent().get(CONTEXT_BROWSER);
System.out.println("got driver");
}
@Given("^I visit the Google search page$")
public void iVisitTheGoogleSearchPage() {
GoogleSearchHomepage googleSearchHomepage = new GoogleSearchHomepage(driver);
googleSearchHomepage.visit();
}
@When("^I enter the text \"([^\"]*)\" into the search box$")
public void iEnterTheTextIntoTheSearchBox(String textToEnter) {
GoogleSearchHomepage googleSearchHomepage = new GoogleSearchHomepage(driver);
googleSearchHomepage.typeInSearchField(textToEnter);
}
@And("^I click the search button$")
public void iClickTheSearchButton() {
GoogleSearchHomepage googleSearchHomepage = new GoogleSearchHomepage(driver);
googleSearchHomepage.clickSearchButton();
}
@Then("^I should see the top result mentioning cats$")
public void iShouldSeeTheTopResultMentioningCats() {
GoogleSearchResultsPage googleSearchResultsPage = new GoogleSearchResultsPage(driver);
assertThat(googleSearchResultsPage.getTextOfResult(1).toLowerCase(), containsString("cat"));
}
}
And finally the page definitions for the Google home page:
package pageFactory.examplePages;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import pageFactory.SuperPage;
public class GoogleSearchHomepage extends SuperPage {
@FindBy(css = ".gsfi[name='q']")
public WebElement searchTextField;
@FindBy(css = "[value='Google Search'][name='btnK']")
public WebElement searchButton;
public GoogleSearchHomepage(WebDriver driver) {
super(driver);
}
public void typeInSearchField(String text) {
searchTextField.sendKeys(text);
}
public GoogleSearchResultsPage clickSearchButton() {
searchTextField.sendKeys(Keys.RETURN);
return new GoogleSearchResultsPage(driver);
}
public GoogleSearchHomepage visit() {
driver.get("https://www.google.co.uk/");
System.out.println("Google acquired");
return new GoogleSearchHomepage(driver);
}
}
and the Google Search Result page:
package pageFactory.examplePages;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import pageFactory.SuperPage;
import java.util.List;
public class GoogleSearchResultsPage extends SuperPage {
@FindBy(className = "r:first-of-type")
public List<WebElement> searchTextField;
public GoogleSearchResultsPage(WebDriver driver) {
super(driver);
}
public String getTextOfResult(Integer resultNumberToGet) {
return searchTextField.get(resultNumberToGet).getText();
}
}
Constants are as provided by the original example repo and look as follows:
package net.dimaj.zucchini.utils;
public class Constants {
public static final String CONTEXT_BROWSER = "browser";
public static final String CONTEXT_SCENARIO = "scenarior";
}
My question is why this setup is failing?