Showing posts with label page object model. Show all posts
Showing posts with label page object model. Show all posts

Thursday, November 29, 2018

Automation Strategy (Email): Putting Intelligence into Your Library Methods

Summary

This is an email I sent to my team who had written some if statements which were dependent on the customer in use (customers could customize their UIs to some extent).  I let them know that since several customers will have similar UIs, we don't need to do an if based on each customer ID, we can put some intelligence into the method so it can decide what to do based on what the UI looks like.

In general, I'm not interested in testing that the UI is correct and that the test data is set up correctly - I'm interested in testing the logic, e.g. add to cart, change quantity, make a purchase.  That statement is relevant here because let's say customer 1234's should be set up to use UI version A and there's a bug in UI version A.  The test should fail.  But if the test data has customer 1234 set up to use UI version B, the automation will happily use UI version B and may pass.  But I would argue that's a data setup problem, not an automation problem, and would be a problem even if the test were run manually.

Email

Currently in ProductFlow.java we have code that looks like this:


 public void addProductToShoppingCart(CheckOutProduct checkOutProductString catalog) {
     
if (catalog.equals(StaticData.US_CATALOG_1234) {
         
//do one thing
     
else {
         
//do a different thing
     
}


If we use lots of manufacturers, this list will get big.  This method addProductToShoppingCart() does not have much intelligence in it, and theoretically the manufacturer's page could change.  Something we can do instead of blindly relying on the manufacturer ID is to make the method more intelligent.  The method could analyze the page, such as:


 public void addProductToShoppingCart(CheckOutProduct checkOutProductString catalog) {
     
if (navigationLinkA.isPresent()) {
         
//do one thing
     
}
     
if (navigationLinkB.isPresent()) {
         
//do a different thing
     
}


An example of this would be in the selling portal – some customers have a side navigation link with text "Part Numbers" and other have a link that has text "List by Part Number"

In fact, now that I think about it, a better solution would be to have a method called "navigateToPartList()" and put these if statements in there, then all addProductToShoppingCart() would do is call navigateToPartList()... 

As I've said many times before, let's keep pushing that work farther down the road (make someone else do it), and have lots and lots of very simple, reusable methods.

As always, this is not the best solution in all cases.  Using the customer ID is perfectly fine sometimes, this is just an alternative way of doing things.

Thursday, September 20, 2018

Automation Strategy: Keep Going With Page Objects (Don't Stop at Locators)

Stopping at the Simplest Implementation of POM

I don't love the Page-Object Model (POM).  Actually, I just don't love the way many teams implement it.  When they stop at giving their page elements locators, they end up with elements that look like


Reusing Page Objects in Other Page Objects

It's these last few that get me. Any time I see redundant code it makes me cringe. Let's level-up:


This can probably only be achieved if you've wrapped your Selenium tool's WebElement and WebDriver class. Hopefully you did this. It will take a little cleverness and adding some constructors, but it should be doable.

Dynamic Elements Using Methods, Not Variables

I find myself kicking the can down the road, or pushing the work down to a lower level like this all the time. "Make someone else do the work" I say. If I'm in the middle of writing a method and I think for one second that what I'm about to write could be used somewhere else, I try to encapsulate that work in a method. Better yet, I imagine what I'd pass into that method, what it would return to me, and continue writing my current method as if that helper method exists and keep going. Later on I'll write the helper methods into existence. 

In this case, while we're writing createAndViewOrder(), we don't want to worry about how we find the orderConfirmation element, we just want to assume it works and use it, so let's move it out of the method.  Before:


After:


Does this buy you a lot right now? Not really. But
  1. it might buy you something down the road during a refactor
  2. it makes your functional method easier to read
  3. it literally takes 15 extra seconds

Summary

It goes to a frame of mind that is good to get into when writing automation code - avoid UI specifics in functional methods, because you're likely to re-use that UI element again. There's a LOT of patterns when writing automation code from how your tests are constructed to how you find page objects to how you interact with the app, so you really have to be on guard and work against code duplication, this is just one of the ways.