pythonselenium-webdriverautomated-testsseleniumbase

Is it possible to chain locators with seleniumbase?


I've tried to transfer my selenium code into seleniumbase however I'm receiving "Message: invalid argument: invalid locator" when I try to chain locators.

seleniumbase code:

 def get_products(self, sb):
        return sb.find_elements("//div[@class='card h-100']")

products = shop_page.get_products(sb)
        print(len(products))  # 4
        if len(products) > 0:
            for product in products:
                print(product)
                if product.find_element("div/h4/a").text == 'Blackberry':  # this line causes error
                    return ShopPage.add_to_cart(product)

I've been using locators chaining in raw selenium and it worked fine.

    def get_products(self):
        return self.driver.find_elements(By.XPATH, "//div[@class='card h-100']")

    def add_blueberry(products):
        if len(products) > 0:
            for product in products:
                if product.find_element(By.XPATH, "div/h4/a").text == 'Blackberry':
                    return ShopPage.add_to_cart(product)
        else:
            raise Exception("No products found!")

url: https://rahulshettyacademy.com/angularpractice/shop


Solution

  • You're mixing APIs. With SeleniumBase, you don't need to specify the by, as it autodetects the selector, but with regular webdriver and WebElement commands, you do.

    So once you actually find a list of elements with SeleniumBase, each item is a WebElement, and you would need to do:

    if product.find_element(By.XPATH, "div/h4/a").text == 'Blackberry':
    

    (It would be the same for both SeleniumBase and raw Selenium.)

    However, the SeleniumBase way of simplifying that would be something like:

    products = self.find_elements("//div[@class='card h-100']//div/h4/a")
    for product in products:
        print(product.text)
    

    The output of that on that page is:

    iphone X
    Samsung Note 8
    Nokia Edge
    Blackberry
    

    So rather than chaining selectors in separate commands, put the full selector in the initial self.find_elements() call.