0

Below is a working script for automating a little bit of Ebay's website. I'm very new to coding so this is definitely a messy code job. Which is why I would like to know how this code can be optimized using Java streams? I would also like to know if there is a easier way to write the FilterCarrier method in my code? Basically are there better ways to iterate? Thanks a lot!

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import javax.imageio.ImageIO;
import org.openqa.selenium.By;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.Point;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.io.FileHandler;

public class EbayTestCase {

    public static void main(String[] args) throws InterruptedException, IOException {
        // TODO Auto-generated method stub
        System.setProperty("webdriver.chrome.driver",
                "C:\\Users\\Mehdee\\Documents\\Eclipse projects\\Selenium\\ChromeDriver\\chromedriver.exe");
        WebDriver driver = new ChromeDriver();
        driver.manage().window().maximize();
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(30));
        // WebDriverWait w = new WebDriverWait(driver, Duration.ofSeconds(30));
        driver.get("https://www.ebay.com/");
        String[] carrFilter = { "Verizon", "T-Mobile", "Unlocked", "1&1" };
        driver.findElement(By.id("gh-ac")).sendKeys("iPhone 14");
        driver.findElement(By.id("gh-btn")).click();
        System.out.println(ResultCount(driver) + " For iPhone 14");
        Thread.sleep(1500);
        driver.findElement(By.cssSelector("input[aria-label='Apple iPhone 14 Pro Max']")).click();
        System.out.println(ResultCount(driver) + " For Apple iPhone 14 Pro Max");

        FilterCarrier(driver, carrFilter);

        ElementScreenshot(driver);
        driver.quit();

    }

    public static void ElementScreenshot(WebDriver driver) throws IOException {
        WebElement ele = driver.findElement(
                By.xpath("//body/div[5]/div[4]/div[2]/div[1]/div[2]/ul[1]/li[2]/div[1]/div[1]/div[1]/a[1]/div[1]"));
        File SC = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
        Point location = ele.getLocation();
        int height = ele.getSize().getHeight();
        int width = ele.getSize().getWidth();
        BufferedImage img = ImageIO.read(SC);
        BufferedImage cropped = img.getSubimage(location.getX(), location.getY(), width, height);
        ImageIO.write(cropped, "png", SC);
        File fis = new File("C:\\Users\\Mehdee\\Documents\\SeleniumScreenshots\\screenshot.png");
        FileHandler.copy(SC, fis);
        System.out.println("Screenshot has been successfully stored in C://Documents/SeleniumScreenshots directory");
    }

    public static String ResultCount(WebDriver driver) {
        String[] t = driver.findElement(By.cssSelector(".srp-controls__count-heading")).getText().split(" ");
        String resultCount = t[0] + " Results Found";
        return resultCount;
    }

    public static void FilterCarrier(WebDriver driver, String[] carrFilter) {
        List<WebElement> options = driver
                .findElements(By.xpath("//div[@id='x-refine__group_1__1']/ul/li/div/a/div/span/input"));
        int b = 0;
        for (int i = 0; i < options.size(); i++) {

            List<String> carrNames = Arrays.asList(carrFilter);
            WebElement option = options.get(i);
            String label = option.getAttribute("aria-label");
            if (carrNames.contains(label)) {
                b++;
                options.get(i).click();
                System.out.println(ResultCount(driver) + " for: " + label);
                options = driver.findElements(By.xpath("//div[@id='x-refine__group_1__1']/ul/li/div/a/div/span/input"));
                if (b == 4) {
                    break;
                }

            }
        }
    }
}
2
  • What exactly are you performing in FilterCarrier Method? Commented Jul 26, 2023 at 23:19
  • @undetectedSelenium ebay has mobile carrier filters on the navigation side bar. The FilterCarrier method clicks on the filter options based on the carrFilter list. Commented Jul 26, 2023 at 23:37

1 Answer 1

2

In my opinion, using stream() in this case will just make your code more complex and slow without any reason.

You need to keep your options list constantly updating, otherwise, StaleElementReferenceException will be thrown in option.getAttribute("aria-label"), which makes it incompatible with the stream() method because you can't change the list in the middle of iteration.

You could also use a forEach() on carrNames and verify the label, but that would not be performant.

But, you can improve your code like this:

// No reason to be public
private static void FilterCarrier(WebDriver driver, String[] carrFilter) {
  // Use new method
  List<WebElement> options = getOptions(driver);

  // Instantiated out of loop
  List<String> carrNames = Arrays.asList(carrFilter);

  for (int i = 0; i < options.size(); i++) {
    WebElement option = options.get(i);
    String label = option.getAttribute("aria-label");

    if (carrNames.contains(label)) {
      // Reuse the object
      option.click();

      System.out.println(ResultCount(driver) + " for: " + label);

      // Use new method
      options = getOptions(driver);
    }
  }
}

// Method to get options (Coding best practices)
private static List<WebElement> getOptions(WebDriver driver) {
  return driver.findElements(By.xpath("//div[@id='x-refine__group_1__1']/ul/li/div/a/div/span/input"));
}

I improved my answer based on @pcalkins and @MehdeeAhmed comments:

// No reason to be public
private static String ResultCount(WebDriver driver) {
    String[] t = driver.findElement(By.cssSelector(".srp-controls__count-heading")).getText().split(" ");
    String resultCount = t[0] + " Results Found";
    return resultCount;
}

// No reason to be public
private static void FilterCarrier(WebDriver driver, String[] carrFilter) {
    List<String> appliedFilters = new LinkedList<>();

    // Filters: { "Verizon", "T-Mobile", "Unlocked", "1&1" }
    Arrays.asList(carrFilter).forEach((carrName) -> {
        for (WebElement option : getOptions(driver)) {
            String label = option.getAttribute("aria-label");
            if (carrName.equals(label)) {
                option.click();
                appliedFilters.add(label);
                System.out.println(ResultCount(driver) + " for: " + formatAppliedFilters(appliedFilters));
                break;
            }
        }
    });
}

//Format all applied filters to display
private static String formatAppliedFilters(List<String> appliedFilters) {
    StringBuilder formated = new StringBuilder();

    for (int i = 0; i < appliedFilters.size(); i++) {
        if (!formated.isEmpty()) {
            if (i == appliedFilters.size() - 1) {
                formated.append(" & ");
            } else {
                formated.append(", ");
            }
        }
        formated.append(appliedFilters.get(i));
    }

    return formated.toString();
}

// Method to get options (Coding best practices)
private static List<WebElement> getOptions(WebDriver driver) {
    return driver.findElements(By.xpath("//div[@id='x-refine__group_1__1']/ul/li/div/a/div/span/input"));
}
Sign up to request clarification or add additional context in comments.

11 Comments

Thank you for your help. I have one question, In the code, the options don't get unclicked, so the filters add on top of each other, however the output prints only 1 label that carrNames contains. So, I want to know how I can add all the labels in the output? For example, the 2nd iteration should say "713 Results Found for: 1&1 & Unlocked" instead of "713 Results Found for: 1&1"
this feels bad.. sort of messing with the iterator.. I'd avoid that in case size of options changes.
@pcalkins But options size never changes, just the values.
I improved the answer! I hope it helps.
@DiegoBorba thanks a lot, your effort is extremely appreciated. Cheers!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.