Skip to main content

Introduction

Gwen = [G]iven [W]hen Th[en]

Gwen is a Gherkin interpreter for driving automated testing and robotic processing with feature specifications.

Automation is achieved through Gherkin bindings called meta specs, composed with the Gwen DSL and maintained 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.

Declare features

Write feature specs to describe how scenarios should behave.

tip

Write feature specs without giving any thought to automation.

Feature specs are used to communicate requirements in the language of your domain. They should be 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

Compose meta

Write meta specs to describe how steps will execute to automate scenarios.

tip

Write meta specs with automation in mind (as if you were a robot).

Meta specs are used to describe execution and are written in Gherkin too. Step definitions and bindings are defined in meta so your features remain clean and unconcerned with automation details.

For example, the following meta describes how the scenario in 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
@ForEach
Scenario: the following items are added
Given the todo field can be located by class "new-todo"
When I enter Item in the todo field
Then my todo list should contain 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:

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 through string interpolation 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 environment, 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
  And my todo list should be hidden

Calls DSL step:

Processing records in data tables

The second StepDef uses the @DataTable and @ForEach annotations which work together to process each record in the data table of the second step in the feature.

Feature Step 2
  When the following items are added
| Item |
| Get the milk |
| Walk the dog |
StepDef 2
  @Action
@StepDef
@DataTable
@ForEach
Scenario: the following items are added
Given the todo field can be located by class "new-todo"
When I enter Item in the todo field
Then my todo list should contain Item

Gwen will call the StepDef for each record in the table and bind each field value to its declared name in the header record. The second and third steps in this StepDef will enter each Item into the todo field and check that it was 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 now contains and displays each item. If it does not, then an assertion error will be raised.

StepDef 2, Steps 2 and 3
  When I enter Item in the todo field
Then my todo list should contain 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 rules and semantics

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

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.

Default Setting

Strict rules are enabled by default since Gwen 3. In prior versions, lenient was the default, meaning that these and other rules like Given-When-Then order were not enforced.

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.feature
features/todo.meta
Default setting

Associative meta is enabled by default since Gwen 3. In prior versions, all meta files discovered in a directory were unconditionally bound to all features in that directory and it's subdirectories.

Execute features

Launch Gwen to bind the meta and execute your features to automate.

Invoke the CLI to execute

The 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 settings files passed in will be loaded and all ${prop.name} placeholder references throughout the meta and feature files will resolve during execution.

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

Invoking Gwen

Execute feature in test environment (passing in test environment settings):

yarn gwen -b -c gwen/env/test.conf gwen/features/todo.feature

Gwen CLI

Testing & Robotics

Your Gwen usage need not be confined to just testing. You can automate robotic processing too!