Gwen Workspaces

Setting up Gwen for teams just got a whole lot easier!

Manually setting up and installing Gwen on multiple machines or build servers in a team environment can be tedious and can also result in inconsistent configurations across workstations. One of the reasons why we created gwen-gpm was to provide consistent installation across machines and platforms. But a team needs more than that. A team needs a consistent and seamless way of getting Gwen configured and running on any user workstation or build server too.

Introducing Gwen workspaces

Gwen workspaces solve this problem by defining a standard project structure on the file system complete with settings files and wrapper scripts that can easily be committed to Git and checked out on any machine. Any team member can then just checkout the workspace and start using Gwen straight away. Gwen and the native web drivers will be automatically downloaded and installed on any user workstation or build server if they are not already present (through an embedded Gwen package manager in the workspace).

It is assumed that the target browser is already installed on the system. If not, you will need to manually install it. The wrapper script installs Gwen and native drivers but not the browser itself.

The structure of this workspace is defined as follows:

gwen-workspace
|--/env                   : Put environment properties here
|--/features              : Put your Gherkin feature files here
|--/meta                  : Put your Gwen meta files here
|  gwen                   : Gwen launcher/wrapper script for linux
|  gwen.bat               : Gwen launcher/wrapper script for windows
|  gwen.properties        : Common Gwen properties
|  log4j.properties       : Gwen log settings
|  gwen-gpm.properties    : Downloadable package checksums
|  gwen-gpm.jar           : Gwen package manager
|  .gitignore             : Git ignore file

Create and Commit a Workspace to Git

To create a Gwen workspace for your team, perform the following (only one person in the team needs to do this):

  • Download and extract the latest gwen-workspace.zip to a location on your file system. (Also have a read of the README.txt file that is extracted in the root).
  • Tweak or add team wide settings to the gwen.properties file in the workspace root. You can also tailor the wrapper scripts if necessary (for example, if you want to change the default Gwen launch options or add some new ones).
  • Verify that it all works by launching gwen (on windows) or ./gwen (on linux). Type exit when done to quit the REPL session.
  • Commit and push the workspace to your remote Git repository (see online Git help if you are not sure how to do this)

Checkout Workspace from Git and Go..

To use the workspace on any machine, perform the following (all team members need to do this):

  • Ensure that the target browser is installed on the system
  • Checkout the workspace from Git
  • Open a command prompt to the root workspace location
  • Type..
    • gwen (on windows) or ./gwen (on linux) followed by the options you require
    • Gwen will execute using the settings in the workspace
      Note: this same command can be used on any build server that checks out the workspace too
    • Gwen and native web drivers will self install on the first call
    • Type exit when done to quit the REPL session (if you started Gwen in REPL mode).

The team can now manage all their Gwen settings, environment configurations, Gherkin feature files, and Gwen meta files in a single workspace that can easily be pulled down and executed on any machine.

Help

For help, open a command prompt in the workspace root and type:

  • gwen help (on windows platforms)
  • ./gwen help (on linux platforms)

Each folder in the workspace also includes a README.txt file that can help to guide you.

Advertisements

Gwen and Selenoid reduced test execution from 50 minutes to 5

Thats 1000% (10 times) quicker than executing features in sequence!!

Gwen has always had the capability to make use of selenium grid which is particularly useful when running in parallel, and after discovering selenoid by the guys over at Aerokube I had to give it a shot.

Installing selenoid was a breeze with the configuration manager docker setup.  Once installed, selenoid downloads the last two driver versions of chrome, firefox and opera, and starts a grid ready to run tests.

Gwen comes with 235 features out of the box, ready for anyone to try.  These features cover a number of different scenarios including a flood.io challenge, navigating etsy, completing a todo, navigating blogs, and searching in google.    The features are also written using both imperative and declarative styles declarative-vs-imperative-gherkin.

Typically running 235 features takes 49 minutes and 33 seconds when running the features sequentially, however running these in parallel with selenoid took only 4 minutes and 41 seconds.  Both samples were run using a 34 core machine.

 

Gwen running 235 features sequentially
Gwen running 235 features in parallel

I have also included a screenshot of the running docker images, taken at a point in time where parallel was running full swing.

Thats all for now, hope you enjoyed a brief look into Selenoid and Gwen.

Gwen Package Manager

Gwen just got a package manager that you can use to consistently manage your installations of the following packages across platforms:

The primary benefits of using this when working with Gwen include:

  • All downloads and installs are managed for you
  • You can easily update to the latest versions of packages
  • You can easily switch between versions of packages
  • All downloads are verified for integrity before they are installed
  • Installation is consistent across platforms

Read all about it here and check it out. We’ve just released version 1.0.0. Please provide feedback so we can address any issues and make it better.

Gwen Supports Full Gherkin Syntax

With the recent addition of Data Tables and Doc Strings, Gwen now supports the full Gherkin syntax! We’ve also enhanced the REPL console with a paste mode to enable multi-line step evaluation. The latest web engine has been released with all the new capabilities.

This is a major milestone for Gwen. Thank you to all the users who raised issues or requests and to everyone who evaluated the web engine and provided feedback. It really helps us to keep making Gwen better when we hear from you. 🙂

Gwen Automation with Data Tables

Gwen now supports data tables and in this post I’m going to show you some examples of how they can be used with the web engine to automate some repetitive tasks on the TodoMVC web application.

Data tables are handy for when you want to work with lists of items in Gherkin, such as the list of todo items shown in this example below.

File: features/todo/tables/TodoTables.feature


 Feature: Managing todo items with data tables

Scenario: Complete a todo item

    Given I have the following active items
          | Walk the dog |
          | Get the milk |
          | Feed the cat |

     When I complete the "Get the milk" item

     Then the status of my items should be
          | Item         | Status    |
          | Walk the dog | active    |
          | Get the milk | completed |
          | Feed the cat | active    |

Note that this example is a high level (or declarative) feature specification that describes intended behaviour and not a low level (or imperative) list of statements that describe how automation is to be achieved or on what type of system it will be performed on. Those are automation bindings that can be captured in separate meta files that are also expressed in Gherkin when using Gwen. As it turns out, we already have a meta file that specifies some step definitions that call out to predefined steps in the web engine to interact with the TodoMVC app. One of the capabilities of Gwen is the ability to reuse this meta, so we will reuse it here to help compose some step definitions for our data tables above. You can have a look at that Todo.meta file here if you like.

Data Table Bindings

Looking at the first Given step in our feature, we can see that it contains three todo items in a table. The step implies that we have those three items in our todo list. So what we want to do is load those three items into our list in the todo app when running this step. To do that, we need to create a step definition for it that will launch the app, load the items, and verify that they are all active. We can do that with some new meta as follows:

File: features/todo/tables/TodoTables.meta

 Feature: TodoMVC tables meta

@StepDef
@DataTable(horizontal="Item")
Scenario: I have the following active items
    Given I launch the Todo app
     When I add a "${data[1][Item]}" item
      And I add a "${data[2][Item]}" item
      And I add a "${data[3][Item]}" item
     Then the "${data[Item]}" item should be active for each data record

This meta is also a Gherkin specification with a tagged scenario containing all the steps that will perform the desired operations on the data table.

  • This first @StepDef tag tells Gwen to load this scenario to memory and only execute its steps when a step in a feature references it by name. Note that the name of this scenario is the same expression used in the Given step in the feature. This is how step definitions work in Gwen.
  • The second @DataTable tag contains an attribute that declares the table to contain horizontal data records and that each one of those contains just one data cell that we will call “Item”. We need to do this since the table in the feature does not include a header record at the top and we have to assign each cell a name so we can access its data by that name.
  • The steps from lines 7 to 9 load the items one at a time by explicitly referencing the data in each record
  • The last step on line 10 checks that each item is active by iterating over each record of the table

With this in place and the latest web engine installed, we can now invoke the feature with Gwen as follows.

gwen -b features/todo/tables/TodoTable.feature

Gwen will automatically discover and load the automation bindings in all meta files that exist in the path of the feature file which in our case includes both the Todo.meta we want to reuse and the TodoTables.meta we just created. The Given step in the feature will execute to load the table items and verify that they are all active, and the When step will complete the second item. The Then step in the feature will fail as expected because we haven’t defined a step definition for it yet. The web browser output is shown below:

Similarly, we now add a step definition for the last Then step in our feature to our meta to verify the status of all items and complete all our binding work.

    • The table in this step includes a header record, so we specify header="top" in the @DataTable tag to link the names in that header to the cells in each data record.

    File: features/todo/tables/TodoTables.meta

     Feature: TodoMVC tables meta
    
    @StepDef
    @DataTable(horizontal="Item")
    Scenario: I have the following active items
        Given I launch the Todo app
         When I add a "${data[1][Item]}" item
          And I add a "${data[2][Item]}" item
          And I add a "${data[3][Item]}" item
         Then the "${data[Item]}" item should be active for each data record
    
    @StepDef
    @DataTable(header="top")
    Scenario: the status of my items should be
         Then the "${data[Item]}" item should be ${data[Status]} for each data record
    

    Now the entire feature is executable!

    Simplifying it Further

    For the sake of demonstrating explicit table data access, the steps from lines 7 to 9 in our meta process each record one at a time. Imagine if we had a lot more records? There would be a lot of redundancy wouldn’t there? We can remove this by reducing these steps into a single step that loops through each record in the same way that the steps on line 10 and 15 do.

    File: features/todo/tables/TodoTables.meta

     Feature: TodoMVC tables meta
    
    @StepDef
    @DataTable(horizontal="Item")
    Scenario: I have the following active items
        Given I launch the Todo app
         When I add a "${data[Item]}" item for each data record
         Then the "${data[Item]}" item should be active for each data record
    
    @StepDef
    @DataTable(header="top")
    Scenario: the status of my items should be
         Then the "${data[Item]}" item should be ${data[Status]} for each data record
    

    Now there is no need to explicitly specify the index for each record when referencing each data cell. But for cases where you might need to cross reference different records or really want to be explicit in how you access each data cell, the earlier approach of not iterating will give you the flexibility you need. It really depends on your particular use case and you should always choose the approach that works the best in the given circumstance.

    The feature and meta files created here are available in our samples features/todo/tables folder on Github and are also bundled with the Gwen-web binary distribution. If you download and install it, you can execute the feature in the same way that we did above in your installation directory.

    And, that’s it! Our feature with tables is executable and all redundancy has been removed from the bindings. We have mapped declarative feature steps to imperative steps in meta and reused some existing meta too! 🙂

Evaluating Gwen with Modern JavaScript Web Apps

Gwen-web was designed to take the development pain out of web automation and make it easier to achieve with all types of web applications regardless of the underlying technologies or frameworks they were built with. Our goal was to make Gwen work consistently with web pages built on any kind of server or client side framework. All web pages are just HTML documents when they hit the browser after all. But this HTML is not always static and with the recent trend of modern JavaScript framework adoption, web pages are getting more and more dynamic. A lot more things happen in web pages nowadays. Lots of JavaScript code gets loaded and all types of browser events trigger functions and Ajax requests at various times resulting in all sorts of dynamic and asynchronous rendering that makes for a very rich user experience. This might make things more pleasant for human users but it is often a hard challenge for automation programs (or robots).

The Evaluation Test

So I thought I’d try Gwen out on some web pages built on the popular and modern JS frameworks of today to see how well it performs. To do this, I wrote a feature suite that mimics these Serenity tests and ran it over the various JS implementations of the publicly available TodoMVC web application (this is a project which offers the same Todo web application implemented on different JavaScript frameworks).

It is important to note that Gwen uses the Java implementation of the Selenium web driver and is not a JS framework itself but rather a Java executable that reads plain text Gherkin features and dynamically interprets them into automated web page interactions. The evaluation performed here provides us with an indication of how well Gwen interacts with web applications built on different types of JS frameworks.

The Evaluation Results

The suite consists of 26 scenarios which I ran over 33 different JS implementations of the Todo app (for a total of 858 scenarios). I ran it in a Chrome browser on a Mac. It took about 50 minutes to run every scenario in sequence. I also ran the tests in parallel (on a dual CPU quad core machine) which took about half the time and produced consistent results. Gwen was executed with the gwen.feature.failfast setting overriden to false to force all scenarios in a feature to execute even if one or more prior ones fail.

94% of Scenarios Passed 🙂

All tests completed successfully and passed for the following frameworks.

  • JavaScript:
    • Backbone.js
    • AngularJS
    • Ember.js
    • KnockoutJS
    • Dojo
    • Knockback.js
    • CanJS
    • Polymer
    • React
    • Mithril
    • Ampersand
    • Vue.js
    • Marionette.js
    • Vanilla JS
    • Vanilla ES6
    • jQuery
  • Compile-to-JS:
    • Spine
    • Dart
    • GWT
    • TypeScript + Backbone.js
    • TypeScript + AngularJS
    • TypeScript + React
    • Serenade.js
    • Reagent
    • Scala.js + React
    • Scala.js + Binding.scala
    • js_of_ocaml
    • Humble + GopherJS

6% of Scenarios Failed

Some tests failed for the following frameworks. I have not investigated these in detail but have included my initial findings below.

  • JavaScript:
    • Flight
      • 15 scenarios failed, 11 passed
      • Intermittent element hits and misses
      • Entered data leaks or is lost
    • TroopJS + RequireJS
      • 15 scenarios failed, 11 passed
      • Unresponsive to enter key being sent to field
  • Compile-to-JS:
    • Closure
      • 5 scenarios failed, 21 passed
      • Unresponsive to checkbox being clicked
    • Elm
      • 8 scenarios failed, 18 passed
      • Intermittently not sending some characters to field
    • AngularDart
      • 3 scenarios failed, 23 passed
      • Intermittently not rendering conditionally visible buttons

Conclusion


Gwen interacted successfully with a large majority of the popular JS implementations. All tests passed for 28 of the 33 implementations evaluated. More than 94% of all scenarios passed in total.

Try it Yourself

All the todoMVC features used in this evaluation are also bundled in the gwen-web distribution as of release 2.3.3. If you install the latest gwen-web distribution, you can run it by calling the following command in the directory where you install Gwen (to run in parallel mode, just add the --parallel switch):

  • Windows:
    • gwen features/todoMVC
  • Linux:
    • ./gwen features/todoMVC

Gwen Gets Scenario Outlines

After some consideration, full support for scenario outlines has been added to gwen-web as of version 2.3.0 to give users more power and better support BDD.

Standard Execution

The following example shows a meta file that defines a step definition for joining two strings together and a feature file containing a scenario outline that exercises it with different string values.

Meta file:

Feature: Join Strings Meta

  @StepDef
  Scenario: I join the two strings
      Given the result is "${string 1}${string 2}"

Feature file:

Feature: Join Strings

  Scenario Outline: Joining <string 1> and <string 2> should yield <result>

    This scenario is evaluated at the point where the outline is declared.
    Joining <string 1> and <string 2> should yield <result>

    Given string 1 is "<string 1>"
      And string 2 is "<string 2>"
     When I join the two strings
     Then the result should be "<result>"

    Examples: Basic string concatenation

      The header row contains the placeholder names. The body rows that
      follow contain the data that is bound to each scenario that is evaluated.

      | string 1 | string 2 | result   |
      | howdy    | doo      | howdydoo |
      | any      | thing    | anything |

The Gwen interpreter will expand and evaluate each record in the body of the Examples table at the point where the scenario outline is declared in the feature. This example contains just one Examples clause in the outline but many can be specified.

Evaluated scenario outlines appear in HTML reports as follows.

Each Examples table record in the report (excluding the header) is rendered as a hyperlink that when hovered over and clicked will reveal the expanded scenario.

Outlines as StepDefs for Deferred Execution

For cases where you may want to reuse a scenario outline across many scenarios or features, you can make it a step definition in the meta and then call it by name in the feature where you want it to execute.

Meta file:

Feature: Join Strings Meta

  @StepDef
  Scenario: I join the two strings
      Given the result is "${string 1}${string 2}"

  @StepDef
  Scenario Outline: Joining <string 1> and <string 2> should yield <result>

    This outline is loaded into memory and execution is deferred until a call is made.
    Joining <string 1> and <string 2> should yield <result>

    Given string 1 is "<string 1>"
      And string 2 is "<string 2>"
     When I join the two strings
     Then the result should be "<result>"

    Examples: Basic string concatenation

      The header row contains the placeholder names. The body rows that
      follow contain the data that is bound to each scenario that is evaluated.

      | string 1 | string 2 | result   |
      | howdy    | doo      | howdydoo |
      | any      | thing    | anything |

Feature file:

Feature: Join Strings

  Scenario: Join different pairs of strings and compare their results
      Given Joining <string 1> and <string 2> should yield <result>

The Gwen interpreter will load the outline in the meta to memory and execute it when it is called by the scenario in the feature. Any number of scenarios in any features can call the outline in this way as long as the meta is in scope.

Calls to scenario outlines are rendered as steps in HTML reports (just like all calls to step definitions are).

When the step is hovered over and clicked, the called outline is revealed as a StepDef.

Each Examples table record in the report (excluding the header) is rendered as a hyperlink that when hovered over and clicked will reveal the expanded scenario.

Notes about outlines as StepDefs

  • They are reusable
  • They can be called from anywhere, including backgrounds and the REPL console too!
  • If the name of the outline contains data placeholders, then their bound table values are substituted into the expanded scenario name prefixes at evaluation time. Specifying placeholders in the name is handy in this way but it is also optional. We could have named the outline ‘joining two strings should yield a compound string‘ instead and called it by that name if we wanted to. In this case the expanded scenarios would all have this same name prefix. Either way, the expanded scenarios will always be given unique names that are suffixed with the example record number (see report snapshots above). If you are using placeholders in the name though, then your call to the step definition should also include the same placeholder name literals (as shown in this example) to prevent potential name clashes with any other step definitions you may have with a similar name. If a name clash does occur, Gwen will report it and you will need to rename.