Hot questions for Using Cucumber in automation

Question:

My goal is running Cucumber scenarios while using Spring for objects creation and wiring. As far as I understood (from some Cucumber books), the Cucumber runner should be responsible for loading the application context as long as the path configured properly.

For example, if I have a runner Java class that looks like this:

@RunWith(Cucumber.class)
@CucumberOptions(features = {"classpath:xxx_features"}, 
                 glue = {"com.package.name"})

public class FunctionalDevIT {
}

then Cucumber runner will automatically scan and initialize all the beans that it will find so I won't have to load the application context manually as well as get beans one by one from the context.

Currently, just to get my head around the concept, I have a created the most basic configuration that consists of three Java classes:

  1. Runner class (as described above)
  2. Beans Class - the class that contains the beans

    @Component
    public class BeansClass {
    
        @Bean
        public void test1() {
            System.out.println("test1!");
        }
    }
    
  3. Main class - the class that uses the beans defined in the Beans Class

    @ContextConfiguration("classpath:/cucumber.xml")
    public class MainClass {
    
        @Autowired
        private BeansClass testclass;
    
        @Before
        public void navigate() {
            testclass.test1();
        }
    }
    

At the moment that approach doesn't work for me and I get the NullPointerException when I try to call the testclass.test1() method in the Main Class which means that the context wasn't loaded after all.

Am I missing some configuration or perhaps my whole understanding of how that is supposed to be working is wrong?

P.S. All my files are currently in the same package.


Answer:

I resolved this issue by adding and additional configuration class that has been annotated with @ComponentScan and @Configuration, so something like this:

@ComponentScan
@Configuration
public class ConfigurationClass {
    . . . 
}

Then I used this class in ConfigurationClass in the main class:

@ContextConfiguration(classes = WebDriverConfiguration.class)
public class MainClass {
    . . .
}

Question:

I am using Cucumber-Selenium and Excel as my Data file, my question is how can I run my feature file multiple time based on the data I have on the Excel. For Example I have 10 rows of data in Excel and wanted to run it one by one, after the first row of data it will move to the next row and execute it.

Feature File: Scenario: Login

Given I open the browser and access this URL
When I enter the "<Username>" and "<Password>"
Then I am able to login

Step Definition: public class Login {

 WebDriver driver = null;
 String url;        


@Given("^I open the browser and access this URL$")
public void navigateToUrl() throws Throwable{

    System.setProperty("webdriver.chrome.driver", "");
    driver = new ChromeDriver();
    url = DataTable.getDataTableValue(0, 2, 2);
    driver.get(url);
    driver.manage().window().maximize();
}

@When("^I enter the \"([^\"]*)\" and \"([^\"]*)\"$")
public void enterCredentials(String userName, String password ) throws Throwable {

    userName = DataTable.getDataTableValue(0, 1, 1);
    password = DataTable.getDataTableValue(0, 1, 2);

    driver.findElement(By.id("username")).sendKeys(userName);
    driver.findElement(By.id("password")).sendKeys(password);   
}

@Then("^I am able to login$")
public void clickLoginButton() throws Throwable {
    driver.findElement(By.id("Login")).click();
}

}

Here is my Data Table(Excel File)

|ID | UserName | Password

|ID1 |username1 |password1

|ID2 | username2 | password2

|ID3 | username3 | password3

|ID4 | username4 | password4


Answer:

If you want to iterate of the content in an Excel sheet you need to implement that in code in the step definition. There is no support for doing it in Gherkin.

Apache POI may be an option when implementing the iteration.

It is important to understand that the purpose of Behaviour-Driven Development, BDD, is communication. Gherkin is one way of communicating. The Gherkin scenarios can be read and understood by almost anyone understanding the problem.

If you have some of the truth in Gherkin and some in Excel you will end up in a situation where you don't use Cucumber and Gherkin for communication but rather as a test tool. This may be ok. But if you use Cucumber as a test tool, there are other tools that may be easier to use. JUnit is one of them.

Question:


Answer:

below code will wait until specified text is not present..

    int i=0;

    while(i==0)
    {
        try{
            Select select = new Select(driver.findElement(By.xpath("ELEMENT_XPATH")));
            select.getOptions().indexOf(0);
            int ed = select.getOptions().indexOf(0);
            if(ed==0); //check whether it's got your index or not(if not then it will throw error and go to Catch section)
            {
                System.out.println("Pass got.. Index Value");
            }
            i=1; //if it got your index value in drop down then .. exit from loop..
        }catch(org.openqa.selenium.NoSuchElementException NSEE)
        {
            i=0; // iteration will continue until .. you'll not get your index in Drop down.. 
        }
    }

Question:

I want to sendKeys in the calendar box but there is a default value in that box

I tried to clear it before sendKeys but it is not working

My code:

Actions actions = new Actions(driver);
                            actions.moveToElement(driver.findElement(By.xpath("//*[@id='dateOfBirth']")));
                            actions.click();
                            actions. clear();
                            Thread.sleep(3000);     
                            actions.sendKeys("07-12-2018");
                            actions.sendKeys(Keys.TAB);
                        actions.build().perform();

Please help me how to clear the box

HTML Code:

<input type="text" value="07-14-1993" id="dateOfBirth" class="react-datepicker-ignore-onclickoutside">

Answer:

Instead of Actions you can try:

WebElement input = driver.findElement(By.xpath("//*[@id='dateOfBirth']"));
input.click();
input.clear();
input.sendKeys("07-12-2018");
input.sendKeys(Keys.TAB); // I don't know why you need TAB, but since you have it in your code

or

Actions actions = new Actions(driver);
actions.moveToElement(driver.findElement(By.xpath("//*[@id='dateOfBirth']")));
actions.click();
actions.build().perform();
WebElement input = driver.findElement(By.xpath("//*[@id='dateOfBirth']"));
input.clear();
input.sendKeys("07-12-2018");
input.sendKeys(Keys.TAB);

or

Actions actions = new Actions(driver);                        
actions.moveToElement(driver.findElement(By.xpath("//*[@id='dateOfBirth']")));
actions.click();
actions.sendKeys(Keys.BACK_SPACE).sendKeys(Keys.BACK_SPACE).sendKeys(Keys.BACK_SPACE).sendKeys(Keys.BACK_SPACE).sendKeys(Keys.BACK_SPACE).sendKeys(Keys.BACK_SPACE).sendKeys(Keys.BACK_SPACE).sendKeys(Keys.BACK_SPACE).sendKeys(Keys.BACK_SPACE).sendKeys(Keys.BACK_SPACE);
Thread.sleep(3000);     
actions.sendKeys("07-12-2018");
actions.sendKeys(Keys.TAB);
actions.build().perform();

or use JavaScript:

WebElement input = driver.findElement(By.xpath("//*[@id='dateOfBirth']"));
JavascriptExecutor js=(JavascriptExecutor) driver;
js.executeScript("arguments[0].setAttribute(value, '07-12-2018')", input);

Question:

Given: Open the app

When: Enter username and password

Then: user is able to login

And verify the Actual Price

And Compare to the Expected price

Examples:

|Actual Price                           | Expected Price|

|"//div[@class='actual_price']//span[2]"|    USD 100.00| 

|"//div[@class='actual_price']//span[2]"|    USD 200.00|

Step def to get the Actual price is:

@And("^verify the \"([^\"]*)\"$")
public void gettxt(String expectedPrice) throws Throwable {
    String actualprice= driver.findElement(By.xpath(actualprice)).getText();

    try{
    if(expectedPrice.equals(actualPrice)){
        System.out.println("Price is correct");
        System.out.println("Expected Price: " + expectedPrice);
        System.out.println("Actual Price: " + actualPrice);
    }else{
        System.out.println("Price is not correct");
        System.out.println("Expected Price: " + expectedPrice);
        System.out.println("Actual Price: " + actualPrice);
    }
}catch (Exception e){
    return;
    }

Question is how can I compare the actual and expected price. thanks for all your help.. the Actual price column in the example is the xpath to get the text on the UI for the actual value displayed, then the expected price column is the expected value. Any help will be appreciated...


Answer:

The code you have put in here seems to be incorrect.

The regular expression to match Gherkin in the step definition will take the xpath from the Examples. This xpath string will get stored in variable expectedprice as per the function you have defined.

By Your statement String actualprice= driver.findElement(By.xpath(actualprice)).getText();, i assume that, you are trying to get the value of actual price from the xpath and then trying to compare it with expectedPrice you have passed in the Examples section. if this is correct then you need to rewrite you code

Your feature file

Given: Open the app
When: Enter username and password
Then: user is able to login
And verify the Actual Price
And compare to the Expected Price

Examples:
|Actual Price                           | Expected Price|
|"//div[@class='actual_price']//span[2]"|    USD 100.00 | 
|"//div[@class='actual_price']//span[2]"|    USD 200.00 |

Your Step definition

String actualPrice = null;
@And("^verify the \"([^\"]*)\"$")
public void gettxt(String actualPricePath) throws Throwable {
            actualPrice= driver.findElement(By.xpath(actualpricePath)).getText();
}

@And("^Compare to the \"([^\"]*)\"$")
public void comparePrices(String expectedPrice){
    Assert.assertEquals(expectedPrice, actualPrice, "The actual price is not equal to expected price");
}

Question:


Answer:

The ExampleTest you're looking for lives under src/test/java/com/deque/axe folder of the repository you're referenced. Just in case you fail to find it one more time:

private static final URL scriptUrl = ExampleTest.class.getResource("/axe.min.js");

JSONObject responseJSON = new AXE.Builder(driver, scriptUrl).analyze();

There is a couple of alternative approaches you might find useful / easier to use:

Question:

I want to run my Cucumber Features using an executable batch file but am not sure how to do it.

My batch file must allow me to run test cases selectively also i.e bases on Tags or any particular feature file in general.


Answer:

Well, here is a starting point for you: In your terminal:

gedit myscript.sh

Write following in your script:

echo "starting script"
cd /yourproject/homefolder
mvn test -Dcucumber.options="–tags @$1"
echo "ending script"

Save the script, then in terminal make it executable by typing

chmod +x myscript.sh

Then call it like this

./myscript.sh Smoke

Command above runs all scenarios using tag Smoke.

This is all from my head, didn't test it, but it should work! Same procedure for myscript.bat create myscript.bat and write in it following:

echo "starting script"
cd C://yourproject/homefolder
mvn test -Dcucumber.options="–tags @$1"
echo "ending script"

Then call it like this

myscript.bat Smoke

Question:

My code is not working. it gives error for this line "int temp = Integer.parseInt(currentTemp.substring(0, currentTemp.indexOf("˚ ")));" I tried several ways but I could not. Maybe a different factor affects it. Is there any idea to fix it? Error is here:

Background: # darksky.feature:5 Given I am on Darksky Home Page # DarkskySD.iAmOnDarkskyHomePage() Current Temp: 43° Current Temp:43˚ Rain.

java.lang.StringIndexOutOfBoundsException: String index out of range: -1

at java.lang.String.substring(String.java:1967)
at framework.DarkskyTS.etr(DarkskyTS.java:138)
at stepdefinition.DarkskySD.currentTempGreaterOrless(DarkskySD.java:39)
at ✽.Then I verify current temp is not greater or less then temps from daily timeline(darksky.feature:25)

@currenttempgreaterorless Scenario: Verify Current Temperature should not be greater or less than the Temperature from Daily Timeline # darksky.feature:24 Then I verify current temp is not greater or less then temps from daily timeline # DarkskySD.currentTempGreaterOrless() java.lang.StringIndexOutOfBoundsException: String index out of range: -1 at java.lang.String.substring(String.java:1967) at framework.DarkskyTS.etr(DarkskyTS.java:138) at stepdefinition.DarkskySD.currentTempGreaterOrless(DarkskySD.java:39) at ✽.Then I verify current temp is not greater or less then temps from daily timeline(darksky.feature:25)

Failed scenarios: darksky.feature:24 # Scenario: Verify Current Temperature should not be greater or less than the Temperature from Daily Timeline

1 Scenarios (1 failed) 2 Steps (1 failed, 1 passed) 0m5.234s public void tempValue(){

    String currentTemp = SharedSD.getDriver().findElement(By.cssSelector(".summary.swap")).getText();
    System. out.println("Current Temp:" + currentTemp);
    List<WebElement> tempsInTimeLine = SharedSD.getDriver().findElements(By.cssSelector(".temps span:last-child"));
    int temp = Integer.parseInt(currentTemp.substring(0, currentTemp.indexOf("˚ ")));
    int highestInTimeLine = temp;
    int lowestInTimeLine = temp;
    for (WebElement tempInTime: tempsInTimeLine) {
        String sLIneTemp = tempInTime.getText();
        int lineTemp = Integer.parseInt(sLIneTemp.substring(0, sLIneTemp.indexOf("˚ ")));
        if (lineTemp > highestInTimeLine){
            highestInTimeLine  = lineTemp;
        }
        if (lineTemp < lowestInTimeLine ){
            lowestInTimeLine = lineTemp;
        }
        //int lineTemp = Integer.parseInt(sLIneTemp.substring(0, sLIneTemp.indexOf("˚ ")));
    }

    System. out.println("Highest Temp:" + highestInTimeLine);
    System. out.println("Lowest Temp:" + lowestInTimeLine );
}

Answer:

Instead of using indexOf("° "), try using indexOf("°"). It will work. The space you are putting after the degree symbol is unnecessary.

Question:

So, I started developing a framework using Cucumber/TestNG/Java/selenium I have a Context class that saves the scenariocontext with the help of enums in the form of key value pair Referenced from here

My issue is that: For a particular scenario in a feature, Step definitions are defined in multiple classes:

Sample feature

Feature: A feature
Scenario: Scenario
Given Statement 1
Then Statement 2

Class1

Class firstDef{
TestRunner test;
public firstDef(TestRunner test){
this.test = test
}
Brain context = new Brain();
@Given("Statement1")
void method1(){
}
}

Class 2

Class secondDef{
TestRunner test;
public secondDef(TestRunner test){
this.test = test
}
Brain context = new Brain();
@Given("Statement2")
void method1(){
}
}

TestRunner class

Class TestRunner{
//some code
@Test
public method1(){
//some code
}
}

So,

The brain class object for every step-definition will be different, this doesn't help as I want the context to be same throughout the scenario

Even if I instantiate the Brain in Runner class, the instance will be new for every instance of the test class

To overcome this, one possible solution that I have thought of is Serialization and de-serialization

In the @BeforeClass method, I will have:

File f = new File(path);
if(!f.exists()){
Brain context = new Brain();
FileOutputStream fos = new FileOutputStream(name);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(context);
}

Then I can deserialize wherever I want the context and serialize again after making changes to same reference variable

Is the above method correct or is there a better way to overcome the same problem


Answer:

Constructor injection with Cucumber PicoContainer works like a charm for the above problem

Just add the dependency:

<!-- https://mvnrepository.com/artifact/info.cukes/cucumber-picocontainer -->
    <dependency>
        <groupId>info.cukes</groupId>
        <artifactId>cucumber-picocontainer</artifactId>
        <version>1.2.5</version>
        <scope>test</scope>
    </dependency>

to your pom.xml(For Maven projects) and pass the HashMap class's reference variable through multiple step definition classes and it will remain the same over a scenario.

Please have a go through this article for detailed explaination

Question:

I want to generate automation test report in eclipse project. I didn't create a marven project and I used Eclipse, Cucumber and Selenium web driver for automation scripting. But I cannot find how to generate an automation report.

Please tell me if there is a way to generate an automation report for a Java eclipse project. I have created the main class. It is as belows.

package mCollector;

import org.junit.runner.RunWith;

import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;

@RunWith(Cucumber.class)
@CucumberOptions(
        format = {"pretty","html:target"},
        features = {"src"}
        )

public class mCollectorRunner {

}

But only from this, I could not generate automation script. What are the additional parts that I have been missed.


Answer:

Run your class as JUnit, then you should have report.html in target folder after test, you can change directory of report output by changing line

...
    format = {"pretty","html:target"},
...

to

...
    format = {"pretty","html:test-reports"},
...

It will create folder called 'test-reports' in your project directory.

Question:

I am trying to read fields from a file.properties with ResourcesBundle, here's the code:

public static final ResourceBundle QUERY_EXCEL = ResourceBundle.getBundle("ConsultaExcel"); 
String query=QueryManager.QUERY_EXCEL.getString("SQL.SELECT.consultarDatos"); 

When I run my project it throws an exception

Can't find bundle for base name ConsultaExcel, locale es_CO

the properties file is in Resource folder that is inside of src/main/resources


Answer:

I could solve this by reinstalling IntelliJ IDEA and installing the plugins by defects

Question:

I am writing very basic automation test with Selenium-Cucumber that is launching an IE browser and closing it at the end.

The problem is that the browser gets launched twice.

The test does not have much it other than few System.out statements. I am kind of new to both selenium-based automation testing and Cucumber and not able to understand why is it getting launched twice.

Please guide.

BrowserConfig.java

public class BrowserConfig {

    private static final String IE_DRIVER_EXE = "drivers/IEDriverServer.exe";
    private static final String WEBDRIVER_IE_DRIVER = "webdriver.ie.driver";
    private static final String BASE_URL = "https://www.google.com";

    public static WebDriver getIEWebDriver() {
        String filePath = ClassLoader.getSystemClassLoader().getResource(IE_DRIVER_EXE).getFile();
        System.setProperty(WEBDRIVER_IE_DRIVER, filePath);
        InternetExplorerOptions options = new InternetExplorerOptions().requireWindowFocus();
        options.setCapability(INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS, true);
        options.setCapability(ENABLE_ELEMENT_CACHE_CLEANUP, true);
        options.setCapability(IE_ENSURE_CLEAN_SESSION, true);
        options.setCapability(ACCEPT_SSL_CERTS, true);
        options.setCapability("nativeEvents", false);
        options.setCapability(INITIAL_BROWSER_URL, BASE_URL);
        WebDriver driver = new InternetExplorerDriver(options);
        driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
        return driver;
    }

    public static void releaseResources(WebDriver driver) {
        if (null != driver) {
            driver.close();
            driver.quit();
        }
    }

}

TestRunner.java

@RunWith(Cucumber.class)
@CucumberOptions(
        plugin = {"pretty", "json:target/cucumber-reports/cucumber.json"},
        features = {"src/test/resources/features"})
public class TestRunner extends ApplicationTests {

}

LoginStep.java

@Ignore
public class LoginStep {

    WebDriver driver;

    @Before
    public void setup() {
        if (this.driver == null) {
            this.driver = BrowserConfig.getIEWebDriver();
        }
    }

    @After
    public void cleanUp() {
        BrowserConfig.releaseResources(driver);
    }

    @Given("^The user is on the Login page$")
    public void doLogin() {
        System.out.println("The user is on the Login page");
    }

    @When("^The user enters the correct credentials on the Login page$")
    public void setWelcomePage() {
        System.out.println("The user enter the correct credentials on the Login page");
    }

    @Then("^The user is displayed Welcome page$")
    public void validate() {
        System.out.println("The user is displayed Welcome page");
    }

}

HelpStep.java

@Ignore
public class HelpStep {

    WebDriver driver;

    @Before
    public void setup() {
        if (this.driver == null) {
            this.driver = BrowserConfig.getIEWebDriver();
        }
    }

    @After
    public void cleanUp() {
        BrowserConfig.releaseResources(driver);
    }

    @When("^The user clicks on the Help menu link from the Welcome page$")
    public void setWelcomePage() {
        System.out.println("The user clicks on the Help menu link from the Welcome page");
    }

    @Then("^The user is displayed Help page$")
    public void validate() {
        System.out.println("The user is displayed Help page");
    }

}

help.feature

Feature: Check that the user is able to navigate to Help page

  Background:
    Given The user is on the Login page
    When The user enters the correct credentials on the Login page
    Then The user is displayed Welcome page

  Scenario:
    When The user clicks on the Help menu link from the Welcome page
    Then The user is displayed Help page

pom.xml

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>cucumber-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>cucumber-demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <cucumber.version>4.2.3</cucumber.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>3.141.59</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-java</artifactId>
            <version>${cucumber.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-junit</artifactId>
            <version>${cucumber.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-spring</artifactId>
            <version>${cucumber.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.19.1</version>
                <configuration>
                    <testFailureIgnore>true</testFailureIgnore>
                </configuration>
            </plugin>
            <plugin>
                <groupId>net.masterthought</groupId>
                <artifactId>maven-cucumber-reporting</artifactId>
                <version>3.14.0</version>
                <executions>
                    <execution>
                        <id>execution</id>
                        <phase>verify</phase>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                        <configuration>
                            <projectName>${project.artifactId}</projectName>
                            <outputDirectory>${project.build.directory}/cucumber-reports</outputDirectory>
                            <cucumberOutput>${project.build.directory}/cucumber-reports/cucumber.json</cucumberOutput>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

Answer:

Because you are initializing and call your driver twice in feature files.

Background part of your feature file are initializing browser firstly in LoginStep.java then your Scenario is also initialize browser in HelpStep.java.

I prefer using global Hooks.java class for @Before and @After hooks and inject driver between different .java classes.

Question:

Can we use cucumber automation testing to test a Java Application ? I am working on a client server model and my Client is a Java application, so i wanted to know if cucumber can be used to test my client (java) ?

Thanks in advance for your reply :)


Answer:

Cucumber is not the testing tool itself, but it's the BDD framework that helps to create easy mapping between "human-readable" steps (comprising features) and actual implementation of those steps. So, you may implement these steps in a variety of ways that Java allows (or other programming language that Cucumber supports) and using the tons of 3rd party libraries like Selenium, Rest assured etc.

So, the answer is "yes" as long as you know the right tool / library / approach that can test Java applications