Should Page Objects Return Page Objects? - java

We're currently working on building up a good test frame in our company. It's for a medium-to-large-sized webapp, perhaps with a couple dozen pages. We're currently writing mostly WebDriver Selenium UI-based tests.
We are trying to decide on some coding standards, and one thing we're discussing is whether to use Page Objects (PO) that always return PO (even if the page is the same), only return PO when you leave the current page for a new one, or even to not return PO. I've always thought returning PO is a key feature of the PO design pattern, but I may be incorrect about this.
Basically, we're trying to decide between the following patterns:
class SomePage {
// constructor
public SomePage(Driver) { //... }
// always return a page object
public SomePage fillInTextField(String val){
// details
return new SomePage(driver);
// only return a PO if it's a different page
public void fillInTextField(String val){
// details
return;
}
Is one preferable over the other?

It's a matter of style.
Using:
class SomePage {
...
// always return a page object
public SomePage fillInTextField(String val){
...
return this; // Note: NOT "new SomePage(driver)"
}
}
allows you to write things like:
SomePage somePage = HoweverYouGetASomePage();
NextPage nextPage = somePage.fillInTextField1("value1").fillInTextField2("value2").submit();
Using:
class SomePage {
...
// only return a PO if it's a different page
public void fillInTextField(String val){
...
return;
}
}
forces you to write things like:
SomePage somePage = HoweverYouGetASomePage();
somePage.fillInTextField1("value1");
somePage.fillInTextField2("value2");
NextPage nextPage = somePage.submit();
Which one you like depends on ... which one you like. But if you like being able to write the former, you need to always return the page object.

Short answer is that don't return same page objects if you are on the same page and state of the page is not changing. You would return new page objects if you are navigating from one page to another. It wouldn't make sense to return the same object when lets say you want to get some text or get a selected option from a page, since essentially nothing changed. If the state of the page is changing, then you would need to return the new page object otherwise you may likely face StaleElementException. In google docs, If you notice the LoginPage, getErrorMessage() does not return the same page object back
A little off from your original question, but I would recommend to use PageFactory, if you already aren't and are in the process of formalizing standards.

I've found it extremely maintainable to do this. Especially with Java 8. Using default methods in Java 8, components and widgets now become Mixins. By always returning a Page, you end up with test cases that look like this:
public class HomePageITest {
#Test
public we_should_be_able_to_search_from_the_homepage() {
pageFactory.getHomePage()
.get()
.doSomethingOnTheHomePage()
.clickSearchWidgetSubmitButton()
.doSomethingElseOnTheHomePage()
;
}
}
I have a blog post describing this in more detail here: http://blog.jsdevel.me/2015/04/pageobjects-done-right-in-java-8.html

As the PageObject Selenium help page said "Methods return other PageObjects"

Related

Checking "rules" in Java without lots of if statements

I'm creating a springboot banking API and in order to create a transaction a bunch of "rules" have to be checked.
e.g:
Current logged in user can't withdraw money from another user's savings account
Amount can't be higher/lower than certain number
etc.
This causes my createTransaction method to contain a lot of if statements (12!). This is what my code looks like in pseudo:
public ResponseEntity<String> createTransaction(Transaction body) {
if (check rule 1) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("...");
}
if (check rule 2) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("...");
}
// etc...
// Transaction complies to set rules
return ResponseEntity.status(HttpStatus.CREATED).body("Transaction successful!");
}
I can post my actual code if necessary but I think this paints the picture without having anyone to read 100 lines of code.
Because I have around 12 if statements checking these rules, my function is quite lengthy and difficult to read/maintain.
Googling for a solution didn't bring up results I was looking for. I've tried implementing exceptions but this didn't remove the amount of if statements. Maybe a switch could improve a bit, but I'm wondering if there's a clean OOP solution.
My question is: How can I clean this code up (OOP style)?
Thanks in advance.
You should create a TransactionRule interface that allows you to implement specific transaction rules, and then use a stream to get the final result:
public interface TransactionRule {
public boolean isAllowed(Transaction someTransaction);
}
Example implementation 1:
public class SufficientBudgetTransactionRule implements TransactionRule {
public boolean isAllowed(Transaction someTransaction) {
// Custom logic e.g.
return someTransaction.wallet.value >= someTransaction.transaction.value;
}
}
Example implementation 2:
public class NotInFutureTransactionRule implements TransactionRule {
public boolean isAllowed(Transaction someTransaction) {
// Custom logic e.g.
return someTransaction.transaction.datetime.isBefore(OffsetDateTime.now());
}
}
Then, you can store all the TransactionRules in a List and check whether they all validate like so:
private final List<TransactionRule> transactionRules; // Fill these of course
public boolean allTransactionRulesMatch(Transaction someTransaction) {
return transactionRules.stream()
.map(transactionRule -> transactionRule.isAllowed(someTransaction))
.allMatch(result => result);
}

Calculation in Wizard

This is more of a general question. We have a lot of wizard, some of which start a long-running process and display the result after. The question is: what is the correct way to do long calculations?
Formerly most wizards did their calculations in DialogPage#setVisible, something like that:
public void setVisible(final boolean visible) {
if (visible) {
getWizard().getContainer().run(true, true, new MyCalculation());
}
super.setVisible(visible);
}
I don't think that's a good idea, since usually getWizard() gets called a lot in these methods. Moreover, usually the parent wizard gets cast to a specific implementation to get input values from or set the result to other pages. So usually it looks something like this:
public void setVisible(final boolean visible) {
if (visible) {
Input input = ((MyCalculationWizard)getWizard()).getInputPage().getInput();
MyCalculation calculation = new MyCalculation(input);
getWizard().getContainer().run(true, true, calculation);
Output output = calculation.getOutput();
((MyCalculationWizard)getWizard()).getOtherPage().setOutput(output);
}
super.setVisible(visible);
}
Just from looking at the code you know that's very bad style.
So we replaced it with something that calculates in Wizard#getNextPage():
public IWizardPage getNextPage(final IWizardPage page) {
final IWizardPage nextPage = super.getNextPage(page);
if (nextPage == this.myResultPage)
getContainer().run(true, true, new MyCalculation());
return nextPage;
}
That way, the wizard is able to fine-tune a lot better than a page would, and the wizard already knows it's pages and can handle input and output a lot better than a page ever could.
The drawback is: getNextPage() gets called a lot for updating the buttons and every time really the wizard feels like it. So while it works for small processes, it does not cut it for long-running ones.
After some more poking around I found the following to work while overriding Wizard#setContainer:
public void setContainer(final IWizardContainer wizardContainer) {
final IWizardContainer oldContainer = getContainer();
if (oldContainer instanceof WizardDialog)
((WizardDialog) oldContainer).removePageChangingListener(this);
super.setContainer(wizardContainer);
if (wizardContainer instanceof WizardDialog)
((WizardDialog) wizardContainer).addPageChangingListener(this);
}
public void handlePageChanging(final PageChangingEvent event) {
final IWizardPage currentPage = (IWizardPage) event.getCurrentPage();
final IWizardPage nextPage = (IWizardPage) event.getTargetPage();
if (currentPage == this.myInputPage && nextPage == this.myResultPage)
getContainer().run(true, true, new MyCalculation());
}
The big advantage here is that the listener only gets called if the wizard wants to jump between pages, and we are able to really fine-tune the calculation (e.g. to not be called when calling 'Previous'). We are even able to not show the next page after all (event.doit = false).
The drawback is the cast of the container to WizardDialog, because potentially it could be an entirely different implementation.
So the question stands: What is the best way to start long processes in wizards?

I don't want to write driver.findelement(By.xpath("")) again and again

Hi this is the code below: What I want to do is this build a function in which i just pass the value of XPath, so i don't have to write driver.findElement(By.xpath("")) again and again.
driver.findElement(By.xpath("//*[#id='lead_source']")).sendKeys("Existing Customer");
driver.findElement(By.xpath("//*[#id='date_closed']")).sendKeys("08/07/2013");
driver.findElement(By.xpath("//*[#id='sales_stage']")).sendKeys("Opportuntiy Qualification");
driver.findElement(By.xpath("//*[#id='opportunity_monthly_volume']")).sendKeys("10895");
driver.findElement(By.xpath("//*[#id='probability']")).sendKeys("90");
driver.findElement(By.xpath("//*[#id='opportunity_sales_rep']")).sendKeys("Sales Rep");
driver.findElement(By.xpath("//*[#id='opportunity_sales_regions']")).sendKeys("Northeast");
driver.findElement(By.xpath("//*[#id='opportunity_current_lab']")).sendKeys("Current lab");
driver.findElement(By.cssSelector(Payermixcss +"opportunity_medicare")).sendKeys("5");
The best way would be to use the PageObject pattern. You could do something like this:
public class MyFormPageObject {
public MyFormPageObject enterLeadSource(String value) {
driver.findElement(By.id("lead_source")).sendKeys(value);
return this;
}
public MyFormPageObject enterDateClosed(String value) {
driver.findElement(By.id("date_closed")).sendKeys(value);
return this;
}
//...
}
// then in your test code
myFormPO.enterLeadSource("Existing Customer").enter("08/07/2013");
Note that as mentionned, you should use By.id if you have an identifier, because XPath is slower and not always well supported by all implementation of WebDriver.
Extract a method to upper level and just pass the values as parameters
eg:
yourMethod(Path path) {
driver.findElement(By.xpath(path))
}
As per your concern you can you use page object model and create the method and pass the variable to exact method.. I don't konw java but i know and concepts
private string variable= "Xpath value"
Pass this variable to method and it will interact with POM.. Before that u should know about POM. Then u can easily understand the concepts. Hope it will help full you...
To reduce the amount of code you have to write, you could use a function like this:
private WebElement findElementByXpath(String xpath) {
return driver.findElement(By.xpath(xpath));
}
The first line of your code would be:
findElementByXpath("//*[#id='lead_source']").sendKeys("Existing Customer");
It does not really reduce the length of the code but it only takes one CTRL + SPACE for autocompletion in Eclipse IDE.

where to write the logic for checking element exists in Page object pattern using Selenium Webdriver

I have two packages,one which represent class/classes for test and while other is for page object.
Inside the test class,I wanted to develop a logic where if a element is present i.e say a dropdown then follow one path and if not then follow another and then verify the results
While I see that page object pattern will be used to interact with the elements on the page then where should the logic for test go which is again dependent on the web element (dropdwwn present or not).
If we start checking the element is present or not in the test class and then pass the driver object to Page object class then wouldnt it be duplication of work.
I am not sure what should be correct approach for designing when the logic is based on whether certain webelements are present on webpage or not.
Thanks.
Write a separate class, say UTIL to hold these logic's. Also make use of this UTIL class for all your test data generation and error code handling.
The basic idea is to do something like:
try{
element.isDisplayed();
return true;
} catch(ElementNotFoundException e){
return false;
}
I've found two places for this code:
The first is in your page class that all of your pages inherit. If you don't have such a class, then a Utils class will work. Your function call will then look something like page.exists(page.getSaveButton()).
However, my favorite way (that will require a little more setup), is to write a wrapper class around WebElement (I call it EnhancedWebElement). It's constructor accepts a normal WebElement, and it redirects each function call to the WebElement, and has an exists() function.
Finally, to make every element have the exists() function, you will need to extend DefaultFieldDecorator, and override these functions:
#Override
public Object decorate(ClassLoader loader, Field field) {
if (!(WebElement.class.isAssignableFrom(field.getType())
|| isDecoratableList(field))) {
return null;
}
ElementLocator locator = factory.createLocator(field);
if (locator == null) {
return null;
}
if (EnhancedWebElement.class.isAssignableFrom(field.getType())) {
return proxyForLocator(loader, locator);
} else if (List.class.isAssignableFrom(field.getType())) {
return proxyForListLocator(loader, locator);
} else {
return null;
}
}
#Override
protected EnhancedWebElement proxyForLocator(ClassLoader loader, ElementLocator locator) {
InvocationHandler handler = new LocatingElementHandler(locator);
WebElement proxy= (WebElement) Proxy.newProxyInstance(
loader, new Class[] {WebElement.class, WrapsElement.class, Locatable.class}, handler);
return new EnhancedWebElement(proxy);
}
To implement it, wherever you call initElements, call this:
PageFactory.initElements(new EnhancedFieldDecorator(new DefaultElementLocatorFactory(driver)), this);
//Replace EnhancedFieldDecorator with the name of your decorator
This may be more than you are asking for, and if it is, that top function is what you are looking for.

Play 2 - How to set default value of template's parameter from Java controller?

Is it possible to define optional parameter when rendering an scala template in Play Framework 2?
My controller looks like this:
public static Result recoverPassword() {
Form<RecoveryForm> resetForm = form(RecoveryForm.class);
return ok(recover.render(resetForm));
// On success I'd like to pass an optional parameter:
// return ok(recover.render(resetForm, true));
}
My Scala template looks like this:
#(resetForm: Form[controllers.Account.RecoveryForm], success:Boolean = false)
Also tried:
#(resetForm: Form[controllers.Account.RecoveryForm]) (success:Boolean = false)
In both cases i got "error: method render in class recover cannot be applied to given types;"
From Java controller you can't omit assignation of the value (in Scala controller or other template it will work), the fastest and cleanest solution in this situation is assignation every time with default value, ie:
public static Result recoverPassword() {
Form<RecoveryForm> resetForm = form(RecoveryForm.class);
if (!successfullPaswordChange){
return badRequest(recover.render(resetForm, false));
}
return ok(recover.render(resetForm, true));
}
Scala template can stay unchanged, as Scala controllers and other templates which can call the template will respect the default value if not given there.
BTW: as you can see, you should use proper methods for returning results from Play's actions, see ok() vs badRequest() also: forrbiden(), notFound(), etc, etc
You can also use flash scope for populating messages and use redirect() to main page after successful password change, then you can just check if flash message exists and display it:
public static Result recoverPassword() {
...
if (!successfullPaswordChange){
return badRequest(recover.render(resetForm, false));
}
flash("passchange.succces", "Your password was reseted, check your mail");
return redirect(routes.Application.index());
}
in ANY template:
#if(flash.containsKey("passchange.succces")) {
<div class="alert-message warning">
<strong>Done!</strong> #flash.get("passchange.succces")
</div>
}
(this snippet is copied from Computer Database sample for Java, so you can check it on your own disk)

Categories

Resources