No Page Objects – There’s no long way to go. We’re already there!

Specifications driven web automation with no page objects or selenium coding ~ We’ve done it!

Page Objects

I recently discovered a Page Objects Refactored article which suggests that ‘flaky’ web tests are often misattributed to Selenium web driver issues and that the problem instead is poorly coded page objects that were not written with solid OO principles in mind. Programming languages allow programmers to achieve the same or similar results in more than one way. For this reason, design patterns were introduced to help developers implement known solutions to known problems. But even design patterns require discipline and cannot be strictly enforced to any useful degree without introducing a specialised framework. Frameworks also are geared at software developers and not software users.

What is needed is a pre-programmed automation tool that frees users from development concerns.

No Page Objects

One of the primary goals of the gwen-web project is to give users a tool for automating web pages without needing to develop any page objects or compile any code. Gwen-web is an interpreter that accepts plain text Gherkin features as input and produces executing web driver instructions as output. All interactions with the web driver API happen in a precompiled and embedded web engine through a prescribed DSL. This web engine also handles many of the known gotchas and pitfalls that programmers typically face when working directly with the web driver. Users also have the flexibility to compose custom DSLs (their own step definitions) which are also expressed in Gherkin. With this approach, developing page objects and adopting design patterns is no longer required. Furthermore, programmer errors are eliminated and ‘flakiness’ is removed. The ability to compose specifications in plain Gherkin text is all that is necessary.

An example

Consider the following Gherkin feature:

 Feature: Google search

Scenario: Perform a google search
    Given I do a google search for "gwen-web"
     When I click the first result
     Then the page title should contain "gwen-interpreter/gwen-web"
      And the current URL should be ""

With Gwen, we can take a plain text feature like this one and execute it “as is”.

If you install gwen-web, you will find the above feature file located at features\google\GoogleSearch.feature relative to your root install directory (the location where you unpacked the distribution). If you open a command prompt to this location, you can execute this feature as follows:

On Windows:

gwen -b features\google\GoogleSearch.feature

On a Mac:

./gwen -b features/google/GoogleSearch.feature

When this is launched, gwen-web will:

  • Open a new browser session
  • Navigate to the google home page
  • Submit a Google search
  • Click the first result that comes back
  • Verify that the title of the resulting page contains some expected text
  • Check the URL of the resulting page

How does it work?

Alongside the GoogleSearch.feature file, you will also find a Google.meta file. This file is also a Gherkin feature file, but with a .meta file extension. It defines the step definition for the first step in our feature. The remaining steps are all predefined in the web engine. We don’t need to define step definitions for those since the web engine already knows how to execute them.

Here are the contents of the Google.meta file (minus the comments):

 Feature: Google search

Scenario: I do a google search for "<query>"
    Given I navigate to ""
      And the search field can be located by name "q"
     When I enter "$<query>" in the search field
     Then the page title should start with "$<query>"
      And the first match can be located by class name "r"
      And the first result can be located by tag name "a" in the first match

This meta defines an annotated scenario named: I do a google search for "<query>". This is how you define a step definition with Gwen. It’s simply just a @StepDef annotated scenario that in this case accepts a <query> string as a parameter followed by a sequence of steps that define its operations. When this meta file is processed by Gwen, the step definition is loaded and made available to any executing feature that is passed in. In our example, Gwen automatically discovers this meta file (because it is in the same directory as the feature itself) and preloads the step definition defined in it to memory. When the first step in our feature executes, Gwen matches it to the step definition by name and binds the passed in “gwen-web” string literal to the <query> parameter which is then used by the steps therein to perform the Google search.

Comparing the feature step with the step definition reveals the match that Gwen is able to detect:

I do a google search for "gwen-web"
I do a google search for "<query>"

Another example

You could also express this Serenity example as a feature specification like this:


   Feature: Complete a Todo

Background: Open a new browser
      Given I start a browser for James

  Scenario: I should be able to complete a todo
      Given I browse to the application home page
       When I add a "Walk the dog" item
        And I add a "Put out the garbage" item
        And I complete the "Walk the dog" item
       Then the "Walk the dog" item should be completed

  Scenario: I should see the number of todos decrease when an item is completed
      Given I browse to the application home page
       When I add a "Walk the dog" item
        And I add a "Put out the garbage" item
        And I complete the "Put out the garbage" item
       Then the number of items left should be "1"

And make it executable with a meta specification like this:


 Feature: Todo meta

Scenario: I browse to the application home page
    Given I navigate to ""
     Then the todo field can be located by id "new-todo"
      And the number of items left can be located by javascript "document.getElementById('todo-count').children[0]"
      And I locate the todo field

Scenario: I add a "<todo>" item
    Given I enter "$<todo>" in the todo field
      And the "$<todo>" item can be located by xpath "//*[@class='view' and contains(.,'$<todo>')]//label"
      And the "$<todo>" item checkbox can be located by xpath "//*[@class='view' and contains(.,'$<todo>')]//input[@type='checkbox']"

Scenario: I complete the "<todo>" item
    Given I click the "$<todo>" item checkbox

Scenario: the "<todo>" item should be completed
    Given the "$<todo>" item checkbox should be checked

And then launch it like this (assuming you have created the above two files):


gwen -b features\todo\CompleteATodo.feature


./gwen -b features/todo/CompleteATodo.feature

Composable automation

With Gwen we don’t have to do any heavy development work. We only need to compose specifications.

Notice that all the technical automation glue (JavaScript expressions, XPath locators etc..) are confined to meta. The features themselves are clean, readable, self documenting, and easily understood. You could easily have a BA or tester write the feature files upfront and then have a developer plug in some meta behind it. Or you could have tech savvy testers with enough HTML and JavaScript skills to write the meta themselves. Teams can choose to be as declarative or as imperative as they like in how they write their features. Tailored meta can always be crafted to suit.

So there you have it ~ web automation with #NoPageObjects and no selenium coding!

If you would like to see a more detailed example, then see our Automation by Meta blog post. See also our Wiki and FAQ pages for more information about Gwen.


Published by

Branko Juric

Imperative by day and functional by night. Co author of the Gwen automation platform.

One thought on “No Page Objects – There’s no long way to go. We’re already there!”

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s