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!")
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.