Lets check how the below segment can be changed to page object model.
1 2 3 4 5 6 | List<WebElement> products = driver.findElements(By.cssSelector(".mb-3")); WebElement prod =products.stream().filter(product-> product.findElement(By.cssSelector("b")).getText().equals(productName)).findFirst().orElse(null); prod.findElement(By.xpath("//div[@class='card-body']/button[2]")).click(); |
Lets take the web element descriptions first; Here we are locating a products list (findElements by the classname csslocator). Since its a list we make it of the type List<WebElement> (line 1). This is how it is done by using @FindBy (we discussed in part 1)
@FindBy(css = ".mb-3") List<WebElement> products;
Afterwards we can do an action class to findElements. I have called a wait method from the abstract components. You can ignore that for the moment. -- let's not distract ourselves with that in this post peepsies ..
public List<WebElement> getProductList(){ waitExplicity(productBy); return products; }
Next (line 3-4) we go through the list and filter the product which matches the product name that we specify through a String. This is how it is converted to an action method.
public WebElement getProductByName(String productName){ WebElement prod =getProductList().stream().filter(product-> product.findElement(By.cssSelector("b")).getText().equals(productName)).findFirst().orElse(null); return prod; }
Let me add bit of details here; If you look at the line 3 of our first code snippet, the stream filter results are assigned to a variable called prod. How is the prod extracted? By traversing though the products, which is the list of products. With me? ook one step ahead-
How do we get the products from our POM & Action Methos approach? via the getProductList action method.
So that's what we have done above. We have getProductList().stream().filter .... instead previous products.stream().filter ....
Now next is the fun part! See what we do when we do addToCart.
public void addToCart(String productName){ WebElement chosenProduct = getProductByName(productName); chosenProduct.findElement(addtoCartBtn).click(); }
We use getProductByName(productName) and assign the returning WebElement to 'chosenProduct' variable. same concept as above. The list web element is replaced by the action method that we created to get the list webelement.
In the next line we do a findElement from within the chosenProduct context, not driver context (noticed!) This is not POM struff. Its about how Selenium facilitate different locator contexts.
However, we cannot use the elements defined in POM to other context. Only driver context could use them. So we have to use the long By.locator methods or we could defined them separately and use here. See.. notice the line 1 below.
By addtoCartBtn = By.xpath("//div[@class='card-body']/button[2]"); public void addToCart(String productName){ WebElement chosenProduct = getProductByName(productName); chosenProduct.findElement(addtoCartBtn).click(); //You cannot use Page objects when you are using a WebElement context }
So that's about what I learnt on this.. See below for the connected code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | @FindBy(css = ".mb-3") List<WebElement> products; //WebElements defined under By type to be used in WebElement context. //You can use POs only in driver context By productBy = By.cssSelector(".mb-3"); By addtoCartBtn = By.xpath("//div[@class='card-body']/button[2]"); public List<WebElement> getProductList(){ waitExplicity(productBy); return products; } public WebElement getProductByName(String productName){ WebElement prod =getProductList().stream().filter(product-> product.findElement(By.cssSelector("b")).getText().equals(productName)).findFirst().orElse(null); return prod; } public void addToCart(String productName){ WebElement chosenProduct = getProductByName(productName); chosenProduct.findElement(addtoCartBtn).click(); } |