Best practices using the Page Object Mode - selenium

I'm trying to figure out the best way of making my Page Objects simple, and whether to put absolutely all logic elsewhere. And whether all Selenium code/functionality should be in the Page Object, or in the Step Definition methods I use to access it.
I have the following structure:
Cucumber.feature files
Given blablabla
Java/Kotlin step definitions
#Given("^blablabla$") {
}
And the page object files
fun getOwnerFields(): MutableList<WebElement> {
return driver.findElements(By.if("owner-fields")
}
As a simple example.
Now, what I cannot come to an agreement with myself on, or find much of other's opinions about, is:
Should I do page actions - for instance, a button click, in the Step Definition class OR in the Page Object?
This:
#Given("^I click on the Next button$") {
startPage.nextButton().click()
}
PO:
fun nextButton(): WebElement {
return driver.findElement(By.id("next-button")
}
Or:v
#Given("^I click on the Next button$") {
startPage.clickNextButton()
}
PO:
fun clickNextButton(): WebElement {
return driver.findElement(By.id("next-button").click()
}
I've tended to think that it's best to keep all the page and selenium code in the Page Object. But in cases like this, it makes the PO bigger, because I'll need different methods for clicking, checking for visibility, counting etc. While if all this is done in the step definitions, the PO can practically contain nothing but getters and setters for the page elements.
Anyone got any light to shed? I know it's not THAT important, but I tend to be quite occupied with the best and/or cleanest way of organizing my code.

This is indeed opinion based question. It depends on the bunch of factors including what your app can and how flexible the user interaction is assumed to be.
As to me since your core abstraction is assumed to be on Gherkin statement level I would say I does not make sense to put a lot of abstraction on lower levels.
Button is not that good example actually because normally you only can click it so there would hardly be other types of interactions. But for other elements my choice would definitely fall on your first approach.
Such the approach would let you to concentrate on the logic that is specific for the step so that being in the step definition you can clearly see what's happening there without extra navigation through the classes.

Related

Initialize WebElements for part of a page

I'm following the Page Object model approach. I’m working on implementing a SearchResultsPage where a bunch of search results are displayed. In thinking about this page, I would like to implement it in such a way that it would support a getSearchResultByIndex(int index) method. Ideally, I would like the return type of this method to be a SearchResult, which would be a mini-page object (aka panel) that encapsulates the functionality found on a search result item since there are a number of attributes of a search result that the user can interact with. I don’t see how to accomplish this though. I was hoping to find a method like PageFactory.initElements() that would take in the WebDriver, a WebElement or selector (that identified an individual search result), and an instance of my SearchResult, but haven’t seen anything.
For clarity. Here's the basic structure of a SearchResults page.
<div class="searchResultsContainer">
<div class="searchResult">various internal fields to interact with/inspect</div>
<div class="searchResult">various internal fields to interact with/inspect</div>
...
<div class="searchResult">various internal fields to interact with/inspect</div>
</div>
It seems like this has to be a common problem out there that people have solved. I've used this "panel" notion for other common page elements like header, footer, etc, but never in the case where multiple instances of the same panel type are on the same page.
Any thoughts would be appreciated. Thanks.
If it were me I would approach it differently. I would split this into 2 page object classes. One for SearchResults, and one for SearchResultPage. The SearchResults would be the generic results list and actions you can take on those results. Within that class you would add a method to click on an individual search result, to pop up the details of that result, that would be what returns your SearchResultPage object.
Here is a rough sketch of what that method could look like inside your SearchResults page object. Not sure what language you are using but this is in C# (Java would be similar, Python much different but you'll get the general idea):
public SearchResultPage GetSearchResult()
{
// do something to click and show search details
return new SearchResultPage(_driver);
}
And then a skeleton of the SearchResultPage class object itself:
public class SearchResultPage
{
IWebDriver _driver;
// add whatever elements you want to work with specific to that single record view
//constructor
public SearchResultPage(IWebDriver driver)
{
_driver = driver;
}
// add whatever methods you want to interact with the elements in that view
}
The good thing about keeping the page objects separate in this case is SearchResults could actually be used in other areas of the application as well, if there are results on other pages that use the same elements etc. I find myself taking out common page elements (drop down menus, grids, etc) into their own objects all the time. Otherwise you end up repeating a lot of code if you stick to strict Page Object model where common functionality exists on multiple pages.
I think I've got this solved. I ended up abandoning PageFactory.initElements(), which I think I've learned is really key and likely an old-school way of implementing the page/object model. Adopting the use of By rather than FindBy seems to work much better as long as the appropriate conditional WebDriverWait.until(ExpectedConditions.elementToBeClickable(elementLocator)) is used.
After coming to this understanding, introducing the concept of a panel locator in my base Panel class allowed me to combine that locator with a nth-of-type(idx) locator to get things wired up and working as expected. Here's a simplified example of that in use in my SearchResultsPage:
public SearchResult getSearchResult(int idx) {
SearchResult res = new SearchResult(getWebDriver(),
By.cssSelector(".searchResultsContainer .seachResult:nth-of-type(" + idx + ")"));
return res;
}
My SearchResult class then just has a number of By locators defined that essentially call new ByChained(panelLocator, locator);
So glad to have solved this!

How to perform feasible web smoke test with Selenium WebDriver?

I have been doing some research on feasible and faster web page loading test with Selenium. A general idea of smoke testing is to click and navigate through the whole site to make sure the pages load properly. I was initially thinking to use some kind of ways to capture the http status code through some kind of http libraries since Selenium does not have any native support for that. But, I found it is not what I want since it will simply return Each and Every links of the site and most of them will be the ones I do not want. So the best way will be to perform actual click and take pages in return. The problem there is the execution time it will take. However, that’s what I am doing currently. Splitting the whole application into different modules and click through all VISIBLE links and take page objects in return with known selector. I am using FindElements() method to grab all the links of a page and click back and forth to test page load. I am doing something like the following:
Is there a better way to improve the performance?
WebElement deliveredChartDailyFocus = driver.findElement(By.id("delivered-chart-daily"));
deliveredChartDailyFocus.click();
// Get a list of all the <rect> elements under the #delivered-chart-daily element
List<WebElement> children = deliveredChartDailyFocus.findElements(By.tagName("rect"));
WebElement elementToClick = null; // variable for the element we want to click on
for (WebElement we : children) // loop through all our <rect> elements
{
if (we.isDisplayed())
{
elementToClick = we; // save the <rect> element to our variable
break; // stop iterating
}
}
if (elementToClick != null) // check we have a visible <rect> element
{
elementToClick.click();
}
else
{
// Handle case if no displayed rect elements were found
}
I would never call process of verification of every single link 'smoke testing'. For example how ISTQB defines this "A subset of all defined/planned test cases that cover the main functionality of a component or system, to ascertaining that the most crucial functions of a program work, but not bothering with finer details". And ths actually mean to exacute some meaningful scenarios and check some small flow/piece of functionality. Only clicking every link will check correctness of links but not computations or logic performed by server side. As for improving speed of passing tests you can consider running tests in parallel.

What should be the criteria for creating a new type of PageObject

If a button is optionally shown on a page (or part of page), does it qualify that part to be represented as two different PageObjects, where one PageObject provides methods to interact with the button while other PageObject does not? Or, should it be one page with a method which can throw an exception when the Button is not rendered.
What will be a maintainable solution - because in future releases the button may start appearing in both cases or the functionality may totally change.
In this case
the button may start appearing in both cases or the functionality may totally change
possible solution can be - Transporter design pattern. It's basically - navigation that aggregates reused page objects in one external object. Also centralizes the navigation control in the tested system according to the test requirements. This object encapsulates logic associated with the implementation of navigation within the tested system. Thus the problem of business logic does not interfere with the navigation within the system.
I think that Composite Page Object is acceptable and
maintainable solution
in both cases. Since It will allow you to structure your Page objects in a more “object-oriented” way by separating sub objects that can be reused on different pages and include them into the parent object. Consider this example:
Further reading about GUI automation patterns.

Error checking as navigating though UI

I have a number of objects which are used repeatedly as navigating though the pages of web application. I check each page for an error dialog as I navigate. As I repeatedly use these tests, if I do encounter an error, each test case which uses the navigation functions will fail. I don't want to maintain two sets of navigation functions so I am wondering if anyone knows of a good approach to take?
Thanks
You should not do assertions in your navigation classes. As much as I understand from you question, you have at the moment something similar to:
class Navigation{
public void navigateToSomePlace(){
navigate();
assertTrue(isInExpectedPlace());
}
}
But you should remove the validation from that method and implement it as a separate method which you can call when you need it. If you want better explanation, show some code.
Edit, how I would implement it:
class Navigation{
public void navigateToSomePlace(){
navigate();
}
public void validateIsInSomePlace(){
assertTrue(isInExpectedPlace());
}
}
So basically, when you are doing the navigation test you would call both of them, but if you only use it for navigating, you would only call the navigate()

How do you select elements in selenium that have a period in their id?

I am trying to write code that will select all options for an HTML drop-down menu. I have written the following code which I believe should work.
public void testSelectMultipleOptions () {
// code to get to report page
selectAllOptions("param.Status");
// code to run report and switch to the result page
}
public void selectAllOptions(String htmlID) {
List<WebElement> options = selenium.findElements(By.cssSelector("select#"+htmlID+" > option"));
for(WebElement option: options) {
option.click();
}
}
When I run this code no options are selected in the drop-down. I believe the problem I am having is caused by the fact that I have an HTML element with a period in the id but I do not have the ability to change the underling HTML code for the page.
There is incredibly bad development practice. I know you don't have the ability to change it, but if you can, point out that it's very very bad. Why? Two reasons.
In CSS, the rules based on classes generally start with a period.
In CSS selector frameworks, including jQuery/Sizzle and what Selenium is doing in this example, the period has a special meaning - mainly to select elements based on many rules. This is why it's tripping here here - you can see the same thing if you run the CSS selector direct into Chrome or Firebug - it will fall over as well.
Using a period in the ID for your elements is going against all this. Annoyingly the HTML spec allows for this.
Anyway, all is not lost, there are many ways around it.
First, you can escape it:
select#param\\.Status
Second, you could use a slightly more elaborate selector:
select[id='param.Status']
Finally, you could use XPath:
//select[#id='param.Status']