Sunday, October 25, 2015

Simplify Locators with HTML Data Attributes


Back in September, during the 2015 Selenium Conference, I presented the concept of using data-* attributes during a lightning talk. And again during Nashville's Selenium Users Group Meetup the following week. Sharing my experience with creating simple locators against an Angular SPA. Although the concept is not revolutionary, it seem new to most individuals. Many struggling trying to find a solution that does not leave them with brittle locators.

Despite the fact that there are a number of test frameworks that offer support for heavy-laden JavaScript applications, many relying on the internals of that JavaScript framework to create locators -- But the questions I ask, "Should your locators become coupled to your Javascript framework? What happens when developers move on to the next framework? Will it require a rewrite of your locators?

By implementing data attributes, allows the QA engineer the freedom to name the attribute, along with its value to something meaningful within the test. And at the same time, is not dependent on any external framework. Thus, leaving the idea that if the underlaying JavaScript framework changes, the locator is not impacted nor should the test itself.


Examples:

CSS - By.cssSelector(“[data-qa-hook=‘category.name.label’]”);
XPath - By.xpath(“//*[@data-qa-hook=‘category.textbox’]”);
JS - document.querySelectorAll(“[data-qa-hook='category.button']");



Tuesday, June 23, 2015

Advancing Readability

How many times have you come across an automation test where it simply flowed beautifully off your lips with complete clarity? Or consider tests having the fluidness and grace of a relaxing stream, peacefully traveling through nature? I would say, it’s remarkably rare. 

And what I am referring to, is readability. I believe test should have these types of characteristics and attributes associated with them. 

Examples litter the internet, promoting page object design with fragment statements, choppy commands and multiple-line block assertions; furthermore, it seldom addresses readability and leaves the reader perplexed and confused on what is happening within the test.

The documentation defines page object as, an object that models a web page or web component and provides that single location when change occurs; in addition, the page object should expose “services” back to the test. 

Despite the great power page objects furnishes, the design does not provide all the mechanisms necessary to construct tests with all the characteristics described above.

To achieve this level of readability, required new thinking, a new approach, and a new design. A design that is flexible, easy to implement and works with the current page objects already in your project. Welcome to H.P.A. — 

Handlers
Provides the fluidness as the test moves from page object to page object, by displaying visual clues where the reader is within the application

Page Objects
Page Objects continues the traditional role except for methods returning another page object, they instead return a handler

Assertions 
Drives clarity and exposes "expectation of correctness” within the test, similar to page objects, by revealing assertion methods to the reader.



Currently, the design has been implemented across numerous applications from typical multiple page application to SPAs (Single Page Application), while allowing the developer more flexibility to adjust  and fit the correct approach to his/her given situation. For example, within SPAs, there are times when a handler or an assertion class is unnecessary. With HPA, there are no hard rules that must be followed, or strict framework coding conventions.

View and Checkout an Working Example @ https://github.com/5hawnknight/hpa-design-example

Below is example of a HPA design and some typical tests --


H.P.A Design Test - 

public void test()
{
       myApp()
                  .home()
                      .header()
                          .selectAccountButtonAsVisitor()
                               .logInAsUser(person)
                  .home()
                      .header()
                          .openSideNavigation().selectLibrary()
                  .library()
                      .searchAndOpenEPubInReader(epub)
                  .readerPage()
                      .getReader(epub)
                  .reader()
                      .leaveReaderPane()
                  .readerPage()
                        .header()
                            .selectAccountButtonAsUser()
                                 .signOut();
      assertions().readerPaneAssertions().verifyReaderPaneIsNotDisplayed(epub);
}

Typical Tests -
public void test()
{
   Login login = new Login(driver);
   login.typeUsername("userX");
   login.typePassword("pwX");
   Dashboard dashboard = login.submitLogin();
   dashboard.typeDestination("Canada");
   SearchResults results = dashboard.submitSearch();
   Assert.assertEquals(true, 0 < webDriver.getPageSource().indexOf("Search Tag"));
}

or

  public void shouldBeAbleToSearchForCats() {
      searchPage.open();
      searchPage.searchFor("cats")
                .selectsCategory("Pets")
                .shouldDisplayTitlesWith("cats");
}


Sunday, February 8, 2015

Interaction With HTML Tables


Over the last several months, there has been several opportunities where during a discussion, the subject of HTML tables becomes front and center. The solutions, though, vary greatly from highly nested "for loops" with non descriptive variables to more object oriented, which is the approach being describe here. With small, single purpose methods with good descriptive names, this type of approach allows for cleaner, more readable and maintainable code.

Quick Description And Guide Lines
  • Creates a list of page objects, one for each row in the table
  • Row page object can only perform actions on that single row
  • Use generic non brittle locators for both the table but also for those within the row page object
  • Search base on an unique column or a combination of columns 
  • Return the row page object that matches the search criteria 
  • Performs actions on that page object (row)

In addition, pagination can be easily implemented with a few additional methods.

A working example can be found @ https://github.com/5hawnknight/solid-prototype-table


Friday, January 23, 2015

Waits

Implicit Waits
  • Default setting for "wait" is 0
  • Set once and its use is continue through the life of the webdriver instance
  • Waits for the presence of the web element 
Explicit Waits
  • Define certain condition on the webelement
  • Define the wait period
  • Able to use convenience methods from the ExpectedConditions class (Java API)
  • Able to create more elaborate wait methods - FluentWaits (Java API)



Why
  • Waits allow the webdriver and the HTML code to stay synchronized; therefore, when the webdriver tries to interact with webelements on the page, those webelements are "ready" for use.
When
  • Any call of a new page object
Where
  • From the page object itself (returning this or a boolean)

Disclaimer - These are my technical notes around Selenium, various code and frameworks.