1

I am having Linear Layouts like this :

enter image description here

Now some Linear Layouts have sub category and some don't have it. Similary some have discount and same don't have it.

So when I do something like this :

List<WebElement> allFieldsInLayout = driver.findElements(By.id("com.flipkart.android:id/product_list_product_item_layout"));
List<WebElement> allTitlesOnCurrentScreen = driver.findElements(By.xpath("//*[@resource-id='com.flipkart.android:id/product_list_product_item_main_text']"));
List<WebElement> allsubTitlesOnCurrentScreen   = driver.findElements(By.xpath("//*[@resource-id='com.flipkart.android:id/product_list_product_item_sub_text']"));
List<WebElement> allOfferPricesOnCurrentScreen = driver.findElements(By.xpath("//*[@resource-id='com.flipkart.android:id/product_list_product_item_price']"));
List<WebElement> allListPriceOnCurrentScreen   = driver.findElements(By.xpath("//*[@resource-id='com.flipkart.android:id/product_list_product_item_mrp']"));

And then try to print text inside them :

for(int i=0;i<allTitlesOnCurrentScreen.size();i++){

        System.out.println("TITLE : "+allTitlesOnCurrentScreen.get(i).getAttribute("text")
                        + "SUB TITLE : "+allsubTitlesOnCurrentScreen.get(i).getAttribute("text")
                        + "OFFER PRICE : "+allOfferPricesOnCurrentScreen.get(i).getAttribute("text")
                        + "LIST PRICE : "+allListPriceOnCurrentScreen.get(i).getAttribute("text")
        );
    }

I got Array Out of Bound exception. So I thought if its possible to get the resource ids of all child fields from outer Layout of this list. I tried like this :

for(int i=0;i<allFieldsInLayout.size();i++){
            List<WebElement> allElementsinCurrentLayout = allFieldsInLayout.get(i).findElements(By.xpath("//android.widget.RelativeLayout[@index='2']"));
            for(int j=0;j<allElementsinCurrentLayout.size();j++) {
                System.out.println("Layout " + allElementsinCurrentLayout.get(j));
            }
}

But it gives exception that

Cannot use xpath locator strategy from an element. It can only be used from the root element)

I want NULL in my list if I dont have corresponding sub title or if no discount is there. How to do it ?

GitCoder
  • 121
  • 2
  • 13
  • Why do you use this method to find each item? It may be easier to find each item by its ID (or name, tag , etc. ) , if you are looking for here it can find different ways to do it . – Gaston Flores Oct 11 '15 at 19:04
  • @GastonF. Which method you are talking ? – GitCoder Oct 11 '15 at 19:15
  • [Here](http://www.codota.com/android/methods/android.app.Activity/findViewById) there are examples that use findViewById. [Here](http://stackoverflow.com/a/6831562/1563878) find by resource name. [Here](http://stackoverflow.com/questions/8817377/android-how-to-find-multiple-views-with-common-attribute) other method. – Gaston Flores Oct 11 '15 at 19:30
  • @GastonF. I am using Appium framework – GitCoder Oct 11 '15 at 20:29
  • ok, I found a problem in your code, you're iterating over allTitlesOnCurrentScreen but try to get values ​​allListPriceOnCurrentScreen with the same index, perhaps your code should look something like [this](http://vpaste.net/CIYqs) – Gaston Flores Oct 12 '15 at 18:22

1 Answers1

0

In general, the way I approach problems like this is to find the top most element that contains all the product information for a single product. Return those elements as a collection and iterate through it. In each iteration, look for the different info containing elements... check for existence and get data if they exist. This method will allow you to neatly capture all properties/data for each product as a package.

The problem with your approach is that you are storing data elements, e.g. subtitles, separate from the product. So, imagine if your have 4 products on the page and only 2 of them have subtitles. You loop through the 4 products (by index) accessing the subtitles... you will have 2 problems: 1) You will run off the end of the subtitles array because there are only 2 and you are looping to 4. 2) Your subtitles array won't match up with the product in the product array.

Imagine this is your page

Product1
Subtitle1

Product2

Product3
Subtitle3

Product4

Your array of products will contain: Product1, Product2, Product3, Product4

Your array of subtitles will contain: Subtitle1, Subtitle3

So when you loop using the product index you will get:

Product1, Subtitle1
Product2, Subtitle3 // notice the mismatch 2 and 3
Product3, Array out of index error

So you ran off the end of your subtitles array and your subtitles don't match up with the corresponding product. Hopefully that makes more sense with the example...

Anyway, here's how I do this. I didn't have the mobile app so I went to flipkart.com and searched for flip covers and wrote the code below to demonstrate what I'm talking about. This code works, I just ran it.

public static void main(String[] args)
{
    WebDriver driver = new FirefoxDriver();
    driver.manage().window().maximize();
    driver.get("http://www.flipkart.com/search?q=flip+cover&as=on&as-show=on&otracker=start&as-pos=4_q_flip+cover&sid=search.flipkart.com&storePath=search.flipkart.com&type=pr&redirectToResponseURL=false&redirection=true&isMsiteTraffic=1");
    List<Product> products = new ArrayList<>(); // List of Product type that will contain each product on the page
    List<WebElement> productContainers = driver.findElements(By.cssSelector("div.gd-col.gu3")); // the outermost element that contains all data related to a given product
    // loop through the product container elements and extract each bit of data that we care about
    for (WebElement productContainer : productContainers)
    {
        String name = productContainer.findElement(By.cssSelector("a[data-tracking-id='prd_title']")).getText().trim();
        String ratingStars = ""; // we have to initialize these variables at this scope so we can access them later outside the IF below
        String NoOfRatings = ""; // NOTE: if a rating does not exist for this product, ratingStars and NoOfRatings will be empty string, ""
        // these next two lines are how we determine if a piece of data exists... get the element using .findElements...
        List<WebElement> ratingContainer = productContainer.findElements(By.cssSelector("div.pu-rating"));
        // ... and then check to see if the list is empty
        if (!ratingContainer.isEmpty())
        {
            // ratings exist for this product, grab the relevant data
            WebElement rating = ratingContainer.get(0).findElement(By.cssSelector("div.fk-stars-small"));
            ratingStars = rating.getAttribute("title"); // product rating in stars
            NoOfRatings = ratingContainer.get(0).getText().trim(); // the total number of ratings, you can parse this string and extract the number, if desired
        }
        String finalPrice = productContainer.findElement(By.cssSelector("div.pu-final")).getText().trim(); // the price, you can extract the number, if desired
        products.add(new Product(name, finalPrice, ratingStars, NoOfRatings)); // add all the relevant data into a nice, neat package just for this one product
    }

    // dumps the data for the products on the page
    for (Product product : products)
    {
        System.out.println("Product: " + product.name);
        System.out.println("Rating: " + product.ratingStars);
        System.out.println("Number of ratings: " + product.NoOfRatings);
        System.out.println("Final price: " + product.finalPrice);
        System.out.println("-----------------------------");
    }
}

// this class holds just 4 bits of data for each product, you can obviously add more to the class if you want to store more data
public static class Product
{
    public String name;
    public String finalPrice;
    public String ratingStars;
    public String NoOfRatings;

    public Product(String name, String finalPrice, String ratingStars, String NoOfRatings)
    {
        this.name = name;
        this.finalPrice = finalPrice;
        this.ratingStars = ratingStars;
        this.NoOfRatings = NoOfRatings;
    }
}

The output looks like

-----------------------------
Product: KolorEdge Flip Cover for Lenovo A6000 Plus (Black)
Rating: 3 stars
Number of ratings: (26 ratings)
Final price: Rs. 160
-----------------------------
Product: Jeelo Flip Cover for Motorola Moto G 2nd Generation (Bl...
Rating: 3 stars
Number of ratings: (128 ratings)
Final price: Rs. 137
-----------------------------
...
JeffC
  • 22,180
  • 5
  • 32
  • 55