Skip to main content

Introduction

Gwen is a Gherkin interpreter for driving automation with feature specifications.

Automation is achieved through Gherkin bindings called meta specs which you compose using DSL Steps and maintain alongside your feature files. An embedded web engine executes each step in your features according to the meta to automate operations in browsers for you.

1. Declare your feature specs#

Declare feature specs to describe how scenarios and examples must behave.

Feature specifications are used to communicate requirements that are clear, concise and declarative. For example, the following describes how adding items to a todo list should behave.

Feature Spec

File: features/todo.feature

Feature: Add todo items   Scenario: Create todo list    Given a new todo list     When the following items are added          | Item          |          | Get the milk  |          | Walk the dog  |     Then the list will contain 2 items

Gwen aims to take these "as is" and make them executable.

tip

Write feature specs without giving any thought to automation. When it makes sense to automate, compose your meta incrementally and maintain a useful subset that you can execute often.

2. Compose your meta specs#

Compose meta specs to describe what your feature specs will execute.

Meta specifications are used to describe how Gwen will execute features and are written in Gherkin too. All the step definitions and bindings required for automation are defined in meta so your features remain unconcerned with this detail.

For example, the following meta describes how the feature above can be executed to automate a test against a running todo application.

Meta Spec

File: features/todo.meta

Feature: Todo Meta

  @Context  @StepDef  Scenario: a new todo list      Given my todo list can be located by css ".todo-list"       When I navigate to "${todo.page.url}"       Then the page title should contain "TodoMVC"        And my todo list should be hidden
  @Action  @StepDef  @DataTable(header="top")  @ForEach  Scenario: the following items are added      Given the todo field can be located by class "new-todo"        And my new item is "${data[Item]}"       When I enter my new item in the todo field       Then my todo list should contain my new item
  @Assertion  @StepDef  Scenario: the list will contain <expected-count> items      Given the displayed count can be located by css ".todo-count strong"       Then the displayed count should be "$<expected-count>"

Declaring step definitions#

Each step definition is declared as a @StepDef annotated scenario with a name that matches that of the step in the feature it binds to. Each one calls out to one or more DSL Steps (or potentially other StepDefs) in its body to perform the specified operations at run time.

The first StepDef in our meta example binds to the first step in the feature and will only execute when it is interpreted for execution by Gwen.

Feature Step 1
  Given a new todo list
StepDef 1
  @Context  @StepDef  Scenario: a new todo list      Given my todo list can be located by css ".todo-list"       When I navigate to "${todo.page.url}"       Then the page title should contain "TodoMVC"        And my todo list should be hidden

Web elements selectors#

The first thing the above will do is bind the selector for locating the todo list element on the web page to the name my todo list. Later steps can then reference that element using this name to interact with it and Gwen will locate it dynamically.

StepDef 1, Step 1
  Given my todo list can be located by css ".todo-list"

Calls DSL step:

Navigating to a web page#

The next step in this StepDef will open a new browser window and navigate to the URL in the todo.page.url property.

StepDef 1, Step 2
  When I navigate to "${todo.page.url}"

Calls DSL step:

Accessing externalised properties#

We could have just hard coded the https://todomvc.com/examples/react URL in the above step, but externalising it enables us to target different environments without changing our meta. This is useful during development when you want to execute against a locally running instance of the application or during testing when it is running on a different host or port. With this approach you can define a settings file per environment and assign the URL for that environment to the todo.page.url property in each file. Then when you want to target an envionment, you pass the settings file for that environment to Gwen and the URL will be resolved accordingly.

Properties

File: env/test.properties

  # test instance url  todo.page.url = https://todomvc.com/examples/react

Checking the page title#

The next step in the same StepDef checks that the page title in the browser window contains the string literal "TodoMVC" in it. If it doesn't then an assertion error will be raised, otherwise execution will resume to the next step. It is generally a good idea when navigating to a page to verify that you did indeed land on that page before proceeding to interact with it. Checking the title is one way to do it which will suffice in this case.

StepDef 1, Step 3
  Then the page title should contain "TodoMVC"

Calls DSL step:

Verifying that an element is hidden from view#

The last step in this StepDef verifies that the web element containing the current list of todo items is hidden from view. We expect it to not be displayed because we haven't added any items to it yet. Recall that we bound this element in the first step earlier to the name my todo list. So here we reference it by that name and if Gwen cannot see it on the page then execution will resume, otherwise an assertion error will be raised.

StepDef 1, Steps 4

Processing records in data tables#

The second StepDef instrcuts Gwen to and @ForEach annotations which work together to process each record of data in the table of the second step in the feature. the env/test.properties

Feature Step 2
  When the following items are added       | Item          |       | Get the milk  |       | Walk the dog  |
StepDef 2
  @Action  @StepDef  @DataTable(header="top")  @ForEach  Scenario: the following items are added      Given the todo field can be located by class "new-todo"        And my new item is "${data[Item]}"       When I enter my new item in the todo field       Then my todo list should contain my new item

The header="top" attribute in the @DataTable annotation designates the topmost row in the table as the header record. Each name in this header will be bound to the respective data in each record as it is iterated over and made available to the steps in the body of the StepDef as data[name]. In this example the sole field named Item is referenced as data[Item] in the second step of the body.

StepDef 2, Step 2
  And my new item is "${data[Item]}"

Calls DSL step:

This step binds the resolved value to a string named my new item for use by the two steps that follow. We do this to eliminate the redundancy of having to resolve it twice and also to make maintenance easier should we ever decide to rename this field in the table. These steps enter this value into the todo field and verify that it was succesfully added to my todo list. This is the same my todo list that we earlier confirmed was absent when we opened the page in the browser. We reuse it here to check that it contains our newly added item (for the current record iteration). If it does not, then an assertion error will be raised.

StepDef 2, Steps 3 and 4
  When I enter my new item in the todo field  Then my todo list should contain my new item

Calls DSL steps:

Passing parameters to StepDefs#

The last StepDef accepts the number of expected items from the last step in the feature into a parameter placeholder named expected-count and then uses that to assert its value against the displayed count on the page. In this example, the value 2 will passed as the parameter.

Feature Step 3
  Then the list will contain 2 items
StepDef 3
  @Assertion  @StepDef  Scenario: the list will contain <expected-count> items      Given the displayed count can be located by css ".todo-count strong"       Then the displayed count should be "$<expected-count>"

Behavioral Semantics#

The following annotations on StepDefs are used to associate behavior types and enforce the following rules if you set your gwen.behavior.rules setting to strict.

Coming to Gwen 3

We are planning to enable strict rules by default in the upcomming Gwen 3 release. The current default is lenient meaning that these and other rules like Given-When-Then order are not enforced.

StepDefs annotated with..can only bind steps tied to keyword..because..
@Context GivenGivens imply context behavior
@ActionWhenWhens imply action behavior
@AssertionThenThens imply assertion behavior

* When binding to a step declared with And, But, or *, then the keyword in the first step in the chain of preceeding steps declared with either Given, When or Then will become the tying keyword. Should the topmost step in a chain be declared with *, then the tying keyword will be Given.

For example, the following binding will be permitted since the feature step is declared with the Then keyword and the StepDef is annotated with @Assertion.

Feature Step 3
  Then the list will contain 2 items
StepDef 3
  @Assertion  @StepDef  Scenario: the list will contain <expected-count> items      Given the displayed count can be located by css ".todo-count strong"       Then the displayed count should be "$<expected-count>"

If we were to change the keyword in the feature step to When however, it would not only read poorly but would no longer imply @Assertion behavior and Gwen would report the violation. Similarly, if we were to change the behavior annotation on the StepDef to @Context, then that behavior would not be implied by the Then keyword declared in the feature step.

Associative meta#

When the gwen.associative.meta setting is enabled, Gwen will automatically associate and bind all same named feature and meta files discovered in a directory with each other. In the following case, the meta would be considered associative.

features/todo.featurefeatures/todo.meta
Coming to Gwen 3

We are planning to enable associative meta by default in the upcomming Gwen 3 release. The current default is that all meta files discovered in a directory will unconditionally bind to all features in that directory and it's subdirectories.

3. Launch Gwen to automate#

Launch Gwen to bind your meta and execute your features to drive automation.

The example presented in this introduction would execute to automate a test.

Launcher CLI#

The Launcher CLI is used to launch Gwen and execute features. When launched on a directory, it will recursively discover and bind all meta and feature files in that directory and execute all the features. Any properties files passed in will be loaded and all ${prop.name} placeholder references throughout the meta and feature files will resolve during execution.

tip

Your Gwen usage need not be confined to just testing. You can automate other repetitive and robotic processes too.