Skip to main content

Introduction

Gwen logoGwen logo

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

Gwen is a Gherkin interpreter with built-in automation capabilities that can readily be utilised for end-to-end testing and robotic processing. Automation is achieved through Gherkin bindings in meta specs, composed with the Gwen DSL and maintained alongside your feature files. An embedded Selenium engine executes scenarios according to the meta you provide to perform operations in browsers for you.

Key features

Frequently asked questions

See the Gwen FAQ.

Usage

Declare features

Declare feature specs to describe how scenarios should behave.

Feature specs are used to communicate scenarios in the language of your domain. They should be clear, concise and declarative.

Keep features declarative

Write feature specs without giving any thought to automation.

For example, the following describes how adding items to a todo list should behave.

Feature Spec

File: gwen/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

Compose meta specs to describe how scenarios will execute.

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.

Meta is necessarily imperative

Write meta specs with execution and automation in mind.

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

Meta Spec

File: gwen/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 not be displayed

@Action
@DataTable
@ForEach
@StepDef
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 item count can be located by css ".todo-count"
Then the item count should contain "$<expected-count>"
And my todo list should be displayed

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 not be displayed

Web element 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/dist 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.

Conf

File: gwen/env/test.conf

todo {
page {
url = "https://todomvc.com/examples/react/dist"
}
}

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 not displayed

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, Step 4

  And my todo list should not be displayed

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
@DataTable
@ForEach
@StepDef
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 item count on the page. In this example, the value 2 will be 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 item count can be located by css ".todo-count"
Then the item count should contain "$<expected-count>"
And my todo list should be displayed

Calls DSL step:

Verifying that an element is displayed

Lastly, the final step in this StepDef verifies that the web element containing the current list of todo items is displayed (which it should be after items have been added).

StepDef 3, Step 3

  And my todo list should be displayed

Calls DSL step:

Behavioural rules and semantics

The following annotations on StepDefs are used to associate behaviour 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
@ActionWhenWhens imply actions
@AssertionThenThens imply assertions

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 item count can be located by css ".todo-count"
Then the item count should contain "$<expected-count>"
And my todo list should be displayed

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 behaviour and Gwen would report the violation. Similarly, if we were to change the behaviour annotation on the StepDef to @Context, then that behaviour would not be implied by the Then keyword declared in the feature step.

Strict by default

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
Associative by default

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.

Launch Gwen

        Gwen attractorGwen attractor

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

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.

Set default environment

Set the default target environment to test by updating the gwen.target.env setting in the gwen.conf file in the project root. This will ensure that all settings in the env/test.conf file are loaded when Gwen is launched and that all ${prop.name} placeholder references throughout all meta and feature files are resolved.

File: gwen.conf

  gwen {
target {
env = "test"
}
}

Settings

Launch Gwen

Quick setup (see getting started)

  yarn add -D @gweninterpreter/gwen-web
yarn gwen init
cp -R gwen/samples/* gwen/features

Execute the feature passing in the -b switch to exit when done:

  yarn gwen -b gwen/features/todo.feature

Or execute all features in the gwen/features directory

  yarn gwen -b gwen/features

Gwen CLI

Testing & Robotics

Your Gwen usage need not be confined to just testing. You can automate manually intensive and repetitive processes too!