Hot questions for Using Cucumber in xpath

Question:

I am trying to write a test in cucumber jvm which grabs the customers address from the page and assert its is not null.

<div class="padder">
<h3>Your details</h3>
<p>
<strong>MR Test Test</strong>
</p>
<p>Selly Road</p>
<p>London</p>
<p>GBR</p>
<p>TR02XZ</p>
</div>
</div>

I used xpath to find the first line of the address and the remaining p tags:

private static final By CUSTOMER_ADDRESS = By.xpath("//*[@id='yourDetails']/div/p[position() >=2]");

This is what I wrote so far but for some reason even though in the xpath I have declared to grab all the p tags after the 2nd p tag my below test does not work:

public List<WebElement> returnAllText(By element) {
    List<WebElement> all = driver.findElements(element);
    for (WebElement elements: all) {
       System.out.println(elements.getText());
    }
    return all;
}

When the loop runs it finds each line of the address but then it is lost when the return statement is run. How do I catch/store each p tag value and then group it as one string value and assert it is not null

I have debugged the code and the below is the results

When I debug line and evaluate the expression:

List<WebElement> all = driver.findElements(element)

result = {java.util.ArrayList@4562} size = 4
[0] = {org.openqa.selenium.remote.RemoteWebElement@4564}"[[RemoteWebDriver: chrome on MAC            (32479ef6b2783086b4c1d1ba0bbd1405)] -> xpath: //*[@id='yourDetails']/div/p[position() >=2]]"

[1] = {org.openqa.selenium.remote.RemoteWebElement@4565}"[[RemoteWebDriver: chrome on MAC (32479ef6b2783086b4c1d1ba0bbd1405)] -> xpath: //*[@id='yourDetails']/div/p[position() >=2]]"

[2] = {org.openqa.selenium.remote.RemoteWebElement@4566}"[[RemoteWebDriver: chrome on MAC (32479ef6b2783086b4c1d1ba0bbd1405)] -> xpath: //*[@id='yourDetails']/div/p[position() >=2]]"

[3] = {org.openqa.selenium.remote.RemoteWebElement@4567}"[[RemoteWebDriver: chrome on MAC (32479ef6b2783086b4c1d1ba0bbd1405)] -> xpath: //*[@id='yourDetails']/div/p[position() >=2]]"

Then I evaluate:

for(WebElement elements: all)

result = {java.util.ArrayList@4276} size = 4
[0] = {org.openqa.selenium.remote.RemoteWebElement@4288}"[[RemoteWebDriver: chrome on MAC (32479ef6b2783086b4c1d1ba0bbd1405)] -> xpath: //*[@id='yourDetails']/div/p[position() >=2]]"

[1] = {org.openqa.selenium.remote.RemoteWebElement@4289}"[[RemoteWebDriver: chrome on MAC (32479ef6b2783086b4c1d1ba0bbd1405)] -> xpath: //*[@id='yourDetails']/div/p[position() >=2]]"

[2] = {org.openqa.selenium.remote.RemoteWebElement@4290}"[[RemoteWebDriver: chrome on MAC (32479ef6b2783086b4c1d1ba0bbd1405)] -> xpath: //*[@id='yourDetails']/div/p[position() >=2]]"

[3] = {org.openqa.selenium.remote.RemoteWebElement@4291}"[[RemoteWebDriver: chrome on MAC (32479ef6b2783086b4c1d1ba0bbd1405)] -> xpath: //*[@id='yourDetails']/div/p[position() >=2]]"

Then I evaluate:

System.out.println(elements.getText())

result = {java.lang.String@4598}"London"
value = {char[9]@4599}
hash = 0
hash32 = 0

Evaluate:

return all;

result = {java.util.ArrayList@4276} size = 4
[0] = {org.openqa.selenium.remote.RemoteWebElement@4288}"[[RemoteWebDriver: chrome on MAC (32479ef6b2783086b4c1d1ba0bbd1405)] -> xpath: //*[@id='yourDetails']/div/p[position() >=2]]"

[1] = {org.openqa.selenium.remote.RemoteWebElement@4289}"[[RemoteWebDriver: chrome on MAC (32479ef6b2783086b4c1d1ba0bbd1405)] -> xpath: //*[@id='yourDetails']/div/p[position() >=2]]"

[2] = {org.openqa.selenium.remote.RemoteWebElement@4290}"[[RemoteWebDriver: chrome on MAC (32479ef6b2783086b4c1d1ba0bbd1405)] -> xpath: //*[@id='yourDetails']/div/p[position() >=2]]"

[3] = {org.openqa.selenium.remote.RemoteWebElement@4291}"[[RemoteWebDriver: chrome on MAC (32479ef6b2783086b4c1d1ba0bbd1405)] -> xpath: //*[@id='yourDetails']/div/p[position() >=2]]"

Answer:

Your debug results (only "London") and your statement in the question ("the loop [...] finds each line") contradict each other. I suggest that you rewrite your method like this:

public String returnAllText(By element) {
    List<WebElement> all = driver.findElements(element);
    StringBuilder sb = new StringBuilder();
    int i = 1;
    for (WebElement element: all) {
        sb.append( i++ ).append( ": " ).append( element.getText() );
    }
    return sb.toString();
}

And let's see what this produces after the return from the method. -- The numbering (i) can be removed later, and a line feed might be added, depending on how you want the composed lines.

Question:

I'm writing some automated tests with Cucumber and Selenium. Currently, I'm trying to write a function to select the passed date in a calendar picker. I need to use the current year that is displayed in the calendar when it pops up to determine some logic.

However, I can't for the life of me figure out the correct syntax to get the value of the current year into Java to work with it further. The first div is the reliably non-ambiguous tag by which I navigate to the calendar that I need to work with, I can even somehow select the year(in this case "2017") in the browser dev console, but I can't pass it into Java.

Relevant HTML:

<ib-selector class="float-rg fblock40" ng-if="!hideYearSelector" initial-label="dateYear" next-handler="nextYear()" prev-handler="prevYear()">
  <div class="calendar-month-year">
    <span class="arrow-cal-left" ng-click="prevHandler()" role="button" tabindex="0">
  </span> 2017
    <span class="arrow-cal-right" ng-click="nextHandler()" role="button" tabindex="0">
  </span>
  </div>
</ib-selector>

Answer:

with xpath (assuming that your's path is OK, as HTML in exmple actually is not relevant):

String text = driver.findElement(By.xpath("//ib-selector[@initial-label='dateYear']/div")).getText()

or if you want to use element:

WebElement el = driver.findElement(By.xPath("//ib-selector[@initial-label='dateYear']/div"));
String text = el.getText();

here is path relevant to HTML from the example:

 String text = driver.findElement(By.cssSelector(".calendar-month-year")).getText()

Question:

I am working on some test automation for a RIA I have written, and I am having some trouble when attempting to search for a given string within the DOM, then clicking on the DIV that encapsulates said string. I am using selenium with cucumber.

The structure of my tests look like this:

├── app
│   ├── containers
│   │   ├── AddCustomerContainer.java
│   │   ├── HomePageContainer.java
│   │   ├── LoginErrorPageContainer.java
│   │   └── LoginPageContainer.java
│   ├── NaviagtorFactory.java
│   ├── Navigation.java
│   ├── User.java
│   ├── Users.java
│   └── view
│       ├── AddCustomerView.java
│       ├── HomeView.java
│       ├── LoginErrorView.java
│       └── LoginView.java
├── constants
│   ├── Browsers.java
│   ├── CredentialsType.java
│   └── Outcome.java
└── utils
    ├── BrowserDriver.java
    ├── BrowserFactory.java
    └── FileUtils.java

the tests are run from Navigation.java, this is how I am trying to search for a string then click on it's parent currently:

//Navigation.java    
public void given_I_navigate_to_the_add_customer_page(){
        BrowserDriver.loadPage("localhost:3000");
        AddCustomerView.clickAddCustomer();
    }

then in AddCustomerView.java:

private static final AddCustomerContainer addCustomerContainer = PageFactory.initElements(BrowserDriver.getCurrentDriver(), AddCustomerContainer.class);

public static void clickAddCustomer(){
    LOGGER.info("Navigating to Add Customer");
    addCustomerContainer.getAddCustomerButton().click();
}

AddCustomerContainer.java:

@FindBy(how = How.XPATH, using = "//*")
    public WebElement all;

public WebElement getAddCustomerButton(){
    WebElement button = BrowserDriver.getText(all, "Add customer");
    return button;
}

And this is the getText function in the BrowserDriver.java

public static WebElement getText(WebElement element, String value) {
    return element.findElement(By.partialLinkText(value));
}

The text I am searching for is 'Add Customer' with the XPATH //* however when the tests run selenium just seemingly cannot find the string.

In respects of structure and driver set up, everything is OK, as I am running several other tests which function as expected. Finding a string is somewhat of an enigma, however.

I have tried several methods of getting the string:

return element.findElement(By.linkText("Add customer"));
return element.findElement(By.partialLinkText("Add customer"));
return element.findElement(By.xpath("//*[contains(text(),'Add customer')]"));

None of which work... Any suggestions? Cheers!

Edit: This is the HTML, it is worth mentioning that this appears in a frame however I used chrome to get the xpath and it was //*[@id="login-success"]/p[1]/a[2]:

<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>
OATime
</title>
<link href="style.css" rel="stylesheet" type="text/css">
<meta http-equiv="refresh" content="30">

<style type="text/css"></style></head>

<body id="login-success" class="chooser">
<br>
<p align="center">
<strong>version_TOKEN</strong>
<br>
<br>
<a target="main" href="/customer-list" class="screenlink">List customers</a><br>
<a target="main" href="/customer-edit" class="screenlink">Add customer</a><br>
<br>
<a target="_top" href="/logout" class="screenlink">Sign out</a>
</p>
</p>
</body></html>

Answer:

With selenium you need to set the context on the frame where the targeted element is. So in your case it should be something like this:

@FindBy(how = How.XPATH, using = "//*")
public WebElement all;

public WebElement getAddCustomerButton(){
    BrowserDriver.switchTo().frame(0);
    WebElement button = BrowserDriver.getText(all, "Add customer");
    return button;
}

And to set back the default context once you're done with the frame:

    BrowserDriver.switchTo().defaultContent();

Question:

I am beginner in test automation. I wanted to automate a demo website, however I am not able to locate the element My Account -> Login URL: https://phptravels.net/home I tried to locate this by CSSseletor, Xpath etc, but I always get the error -org.openqa.selenium.NoSuchElementException

public class LandingPage {

    public WebDriver driver;

    By myAccount = By.className("dropdown dropdown-login dropdown-tab");
    By login = By.xpath("//a[@class='dropdown-item active tr']");
    By navBar = By.id("mobileMenuMain");


    public LandingPage(WebDriver driver) {
        this.driver = driver;
    }

    public WebElement getMyAccount() {
        return driver.findElement(myAccount);
    }
    public WebElement getNavigation() {
        return driver.findElement(navBar);
    }

    public WebElement getLogin() {
        return driver.findElement(login);

-------------------------


@RunWith(Cucumber.class)
public class stepDefinition extends Base {

    @Given("^Initialize the browser with Chrome$")
    public void initialize_the_browser_with_chrome() throws Throwable {
        driver = initializeDriver();
    }

    @And("^Navigate to the \"([^\"]*)\" Website$")
    public void navigate_to_the_something_website(String strArg1) throws Throwable {
        driver.get(strArg1);

    }

   @And("^Click on My Account link in Home Page to land on sign in page$")
    public void click_on_My_Account_link_in_home_page_to_land_on_sign_in_page() throws Throwable {

       LandingPage landingPage = new LandingPage(driver);
       landingPage.getMyAccount().click();
       landingPage.getLogin().click();

       /*if (landingPage.getPopUpSize() > 0) {
           landingPage.getPopUp().click();
       }*/

   }
    @When("^User enters (.+) and (.+) and logs in$")
    public void user_enters_and_and_logs_in(String email, String password) throws Throwable {
        LoginPage loginPage = new LoginPage(driver);
        loginPage.getEmail().sendKeys(email);
        loginPage.getPassword().sendKeys(password);
        loginPage.getLoginbtn().click();
    }

    @Then("^Verify that user is successfully logged in$")
    public void verify_that_user_is_successfully_logged_in() throws Throwable {
        PortalHomePage p = new PortalHomePage(driver);
        Assert.assertTrue(p.getDemoUser().isDisplayed());
    }

    @And("^Close the browsers$")
    public void close_the_browsers() throws Throwable {
        driver.quit();
    }
}

Could anyone help?


Answer:

by Id you will have an issue because the id dropdownCurrency is used twice on the page and searching by class it should be .dropdown.dropdown-login.dropdown-tab

Question:

I have a HTML code

<a id="cmplobremoveTéléphonie+default" class="cmpLOB-remove-btn" onclick="cmpLobRemoveButtonHandler(event, this);" style="text-decoration:none;" href="javascript:void(0)">Retirer</a>

I need to click on the element with xpath as @id='cmplobremoveTéléphonie+default'.

In Cucumber, I have a feature file step as

When Click on remove Button and click on confirm "Téléphonie"

The corresponding method is,

@When("^Click on remove Button and click on confirm \"([^\"]*)\"")
    public void remove_Button(String remove) throws Throwable {
        String remove_Required = "cmplobremove" +remove +"+default";
        driver.baseDriver.findElement(By.id(remove_Required)).click();
        Thread.sleep(1000);
        driver.baseDriver.findElement(By.linkText("Confirm")).click();
        log.info(remove + "is removed");
    }

When I try to execute the above step, I'm getting the following NullPointerException,

org.openqa.selenium.NoSuchElementException: Unable to locate element: {"method":"id","selector":"groupIcon+default+T?l?phonie"}

It seems the french text cannot be passed in a similar way to English Text as a string argument. As you can see that Téléphonie is mentioned as T?l?phonie. Seems something to do with UTF-8/UTF-16.

Solutions are appreciated on how to parse the value.


Answer:

try altenative for identifying that element as below using:

 driver.baseDriver.findElement(By.xpath("//a[contains(.,'Retirer')]").click();
 Thread.sleep(1000);
 driver.baseDriver.findElement(By.linkText("Confirm")).click();

Question:

I'm using selenium and cucumber to automate a web application and I'm currently in a bit of a conundrum on cucumber sending false passes with how the API is built. Basically I'm encapsulating a host of commands within a try catch block, and while it works fine, if a xpath were to change(unlikely) I would like to have the step essentially "fail" but not completely kill the program. Here is where my code is:

@Then("^Create a meeting$")
public void meetingCreation() throws Throwable{
    try{
        //check to make sure driver is on calendar page

        ieBreakingThings = ieDriverWait.until(ExpectedConditions.elementToBeClickable(By.xpath("//button[@ng-click='CreateMeeting()'][@aria-label='Add Meeting']")));
        chromeBreakingThings = chromeDriverWait.until(ExpectedConditions.elementToBeClickable(By.xpath("//button[@ng-click='CreateMeeting()'][@aria-label='Add Meeting']")));

        if (!ieBreakingThings.isDisplayed() || !chromeBreakingThings.isDisplayed())
        {
            chromeDriver.findElement(By.xpath("//div[@class='navigationLinkIcon icon-calendar']")).click();
            ieDriver.findElement(By.xpath("//div[@class='navigationLinkIcon icon-calendar']")).click();
            ieDriver.findElement(By.xpath("//button[@ng-click='CreateMeeting()'][@aria-label='Add Meeting']")).click();
            chromeDriver.findElement(By.xpath("//button[@ng-click='CreateMeeting()'][@aria-label='Add Meeting']")).click();
        }
        else
        {   
            ieDriver.findElement(By.xpath("//button[@ng-click='CreateMeeting()'][@aria-label='Add Meeting']")).click();
            chromeDriver.findElement(By.xpath("//button[@ng-click='CreateMeeting()'][@aria-label='Add Meeting']")).click();
        }
        //fill in text fields
        ieBreakingThings = ieDriverWait.until(ExpectedConditions.elementToBeClickable(By.xpath("//input[@name = 'meetingName'][@ng-model='MeetingName']")));
        chromeBreakingThings = chromeDriverWait.until(ExpectedConditions.elementToBeClickable(By.xpath("//input[@name = 'meetingName'][@ng-model='MeetingName']")));
        chromeDriver.findElement(By.xpath("//input[@name = 'meetingName'][@ng-model='MeetingName']")).click();
        chromeDriver.findElement(By.xpath("//input[@name = 'meetingName'][@ng-model='MeetingName']")).sendKeys("Web Release Test Meeting");
        ieDriver.findElement(By.xpath("//input[@name = 'meetingName'][@ng-model='MeetingName']")).click();
        ieDriver.findElement(By.xpath("//input[@name = 'meetingName'][@ng-model='MeetingName']")).sendKeys("Web Release Test Meeting");
        chromeDriver.findElement(By.xpath("//input[@ng-model = 'MeetingLocation']")).click();
        chromeDriver.findElement(By.xpath("//input[@ng-model = 'MeetingLocation']")).sendKeys("some address");
        ieDriver.findElement(By.xpath("//input[@ng-model = 'MeetingLocation']")).click();
        ieDriver.findElement(By.xpath("//input[@ng-model = 'MeetingLocation']")).sendKeys("some address");
    }catch(TimeoutException | ElementNotVisibleException ex){
        System.out.println("Meeting Creation Failed");
    }
    }

So the above works fine, but if an xpath were to change it would catch the exception, say the meeting creation failed, but cucumber would still report it as passing since it actually executed the method correctly.

Any advice?


Answer:

I believe Cucumber will only report a failure if there is a failed assertion somewhere within the test execution. You could add in a (legitimate) assertion somewhere to verify something that you are expecting to see.

Question:

I have a set of Cucumber tests I wish to execute using selenium and Chrome. Most of my test work fine. I am currently trying to parametertize one particular step so that anyone using the Test can simply name the elements they want and the test will find them.

The Cucumber test looks something like this:

When I go to the "Inventory" / "Inventory" application

And I search the "Description" field for "a"  

I was able to get the when statement to parameterized very easily, but the And Statement is giving me a bit more trouble. The page itself has several sets of tables with a consistent id scheme The xpath for the header with the word "Description" looks like this:

//label[@id='m6a7dfd2f_ttrow_[C:2]_ttitle-lb']

and the input field has this xpath

//td[@id='m6a7dfd2f_tfrow_[C:2]-c']/input

For reference the immediate next input field, located below the label room, has this xpath

//td[@id='m6a7dfd2f_tfrow_[C:3]-c']/input

So each label and input field have the same id scheme and only the number following "c:" seems to change. That number is the same for both the label and it's corresponding input value. I would like to some how scan the page for the word "Description" and extract the ID of the element associated with it and then truncate it down to the number. I already have variables set up to hold the rest and it would hopefully as follows:

@When("^I search the \"([^\"]*)\" field for \"([^\"]*)\"$")
public void i_search_the_field_for(String searchField, String searchItem) throws Throwable {
String baseinputXPath = "//td[@id='m6a7dfd2f_tfrow_[c:";
String endinputXPath = "]-c']/input";
String elementNumber = "The return of some sort of method based on searchField";//TODO
driver.findElement(By.xpath(baseinputXPath + elementNumber + endinputXPath)).clear();
driver.findElement(By.xpath(baseinputXPath + elementNumber + endinputXPath)).sendKeys(searchItem);
driver.findElement(By.id("search_button_img")).click();

If there is a way to pull out that number based only on the description text, that would be super helpful.


Answer:

Use a xpath to search for the WebElement with word 'Description' in a label tag.

"//label[text(),'Description']" or "//label[.='Description']" or "//label[contains(text(),'Description')]"

Use the getAttribute("id") to get the id.