Edit

Write Gauge specifications

Setup

macOS

JavaScript

VS Code

Modify

This page provides information about what a specification is, how to write a specification, and other related information such as concepts, step implementation, specs directory, and so on.

VS Code

Note

You can author Gauge specifications by using any text editor. However for a better experience, it is recommended that you use Gauge IDE plugins.

Gauge projects can be created and run in VS Code by using the Gauge extension for VS Code. This plugin currently supports Gauge with Java, JavaScript, Ruby, Python, C# (.Net Core), and TypeScript.

Specifications (spec)

A specification is a business test case which describes a particular feature of the application that needs testing. Gauge specifications support a .spec or .md file format and these specifications are written in a syntax similar to Markdown.

  • Every spec can contain one or more Scenario.

  • Every spec can be marked with labels using Tags.

Specs directory

When a Gauge project is created and initialized, a specs directory is automatically created at <project_root> with a sample file, example.spec. This sample file helps you understand how to write a specification.

Note

The path and name of the specs directory can be changed by using key value pairs in the default.properties file of your project.

For more information about default.properties, see Local configuration of Gauge (default.properties).

Example

The following is an example of a Gauge specification:

# Search specification
Tags: search, admin

The admin user must be able to search for available products on the search page

## Successful search
Tags: successful

For an existing product name, the search result will contain the product name

* User must be logged in as "admin"
* Open the product search page
* Search for product "Cup Cakes"
* "Cup Cakes" should show up in the search results


## Unsuccessfull search

On an unknown product name search the search results will be empty

* User must be logged in as "admin"
* Open the product search page
* Search for product "unknown"
* The search results will be empty

For more information about Markdown, see Markdown Syntax.

Components of a specification

A specification consists of different sections; some of which are mandatory and few are optional. The components of a specification are listed as follows:

  • Specification heading

  • Scenario

  • Step

  • Parameters

  • Tags

  • Comments

Note

Tags - optional, executable component when the specification is run

Comments - optional, non-executable component when the specification is run

Specification heading

A specification must begin with a specification heading. A specification must contain only one specification heading.

Specification heading is written in the <H1> Markdown syntax in one of the following ways:

# Spec Heading

or

Spec Heading
============

Example

In the following example, # Search specification is the specification heading, followed by tags and steps (statements preceded by *).

# Search specification
Tags: search, admin

The admin user must be able to search for available products on the search page

* User must be logged in as "admin"
* Open the product search page

Scenario

Each scenario represents a single workflow in a particular specification. A specification must contain at least one scenario.

A scenario starts after a scenario heading or a scenario name. The scenario heading is written in Markdown <H2> syntax in one of the following ways:

## Scenario heading

or

Scenario heading
----------------

A scenario contains one or more steps in it. A scenario can be tagged by using tags.

Example

In the following example, the specification, Search specification contains the scenario, ## Successful search. This scenario heading is followed by tags and steps.

# Search specification

The admin user must be able to search for available products on the search page

## Successful search
Tags: successful

For an existing product name, the search result will contain the product name

* Search for product "Cup Cakes"
* "Cup Cakes" should show up in the search results

Table driven scenario

Experimental Feature

Gauge 1.0.3 adds an experimental feature to provide a table at scenario level. Gauge will iterate over the table and run that particular scenario against each row. Set allow_scenario_datatable variable to true in /env/default/default.properties to enable this feature.

Example

# Search specification

## Vowel counts in multiple word

 |Word  |Vowel Count|
 |------|-----------|
 |Gauge |3          |
 |Mingle|2          |
 |Snap  |1          |
 |GoCD  |1          |
 |Rhythm|0          |

This is the second scenario in this specification

Here's a step that takes a table

* The word <Word> has <Vowel Count> vowels.

Since this is an experimental feature there are few cases in which currently do not work:

  • IDE plugins does not support this feature.

  • CSV files can not be used as table for scenario.

  • Reporting plugins does not accommodate this feature.

Note

This feature is currently available in gauge >= 1.0.3,

Step

Steps are the executable components of a specification that are written by using the Markdown unordered list syntax. In a specification, steps can exist either within a scenario or outside a scenario. When steps are used outside a scenario, they can be of the following types:

  • Context steps

  • Tear Down steps.

Steps also exist inside a Concept.

Every step implementation has an equivalent code as per the language plugin used while installing Gauge. This code is run when the steps inside a spec are executed.

Example

In the following example, the two sentences preceded by asterisk, *, are the unordered steps listed inside the Successful search scenario.

# Search specification

## Successful search
Tags: successful

For an existing product name, the search result will contain the product name

* Search for product "Cup Cakes"
* "Cup Cakes" should show up in the search results

The values written in quotes, ", are parameters that are passed into the equivalent code of the step implementation for that particular language plugin.

Attention

The following characters are reserved for parameters and cannot be used in the text of a step:

  • "

  • <

  • >

Note

Parameters

Steps are defined to take values as parameters so that they can be reused with different parameter values.

The equivalent code of the step implementation for that particular language plugin must also have the same number of parameters as mentioned in the step.

Examples

In the following example, parameter values are "Cup Cakes" (within double quotes) within the two steps.

## Successful search
Tags: successful

For an existing product name, the search result will contain the product name

* Search for product "Cup Cakes"
* "Cup Cakes" should show up in the search results

In the following example, parameter values are "product 1" and "product 2".

* Check "product 1" exists
* Check "product 2" exists

A step can have the following types of parameters:

  • Simple parameters

  • Dynamic parameters

  • Table parameters

  • Special parameters

1. Simple parameters

Simple parameters are values, which are used in a step within double quotes.

Example

In the following examples, Cup Cakes, gauge-java, and 100 are values within double quotes and are used in steps:

* Search for product "Cup Cakes"
* Create a "gauge-java" project
* Write "100" line specification

2. Dynamic Parameters

Dynamic parameters are used as placeholders instead of actual values. These parameters are used when referring to a table column value of a data table. Data tables are defined at the beginning of a spec. Dynamic parameters are also used as values in a Concept. Dynamic parameters have the following syntax: <dynamic_param>.

Example: Dynamic Parameters used in a spec which has a data table

In the following example, <name> is a dynamic parameter. <name> can take the values mentioned in the “name” column of the table. In this case, the values are “Alice”, “Bob”, or “Eve”.

# Create projects

    |id| name      |
    |--|-----------|
    |1 | Alice     |
    |2 | Bob       |
    |3 | Eve       |

## First scenario
* Say "hello" to <name>.

## Second scenario
* Say "namaste" to <name>.

Example: Dynamic parameters used in a Concept

In the following example, <username> and <project_name> are used in a Concept.

# Login as user <username> and create project <project_name>

* Login as user <username> and "password"
* Navigate to project page
* Create a project <project_name>

The dynamic parameters take actual values when a concept is invoked from within a spec. In the following specification, the concept is invoked within the “Successful login scenario” and the dynamic parameters, <username> and <project_name> take the values “john” and “Gauge java” respectively.

# Login specification

## Successful login scenario

* Login as user "john" and create project "Gauge java"

Note

3. Table Parameters

Table parameters are used when a step is executed for multiple values in a table. For a step with an inline table parameter, the entire table becomes the parameter value.

Example

In the following example, the step has an inline table parameter.

# Create projects

## First scenario

* Create the following projects
     |project name| username |
     |------------|----------|
     | Gauge java | Daredevil|
     | Gauge ruby | Iron Fist|

Note

Inline data tables can be used as special CSV parameters. For more information about CSV parameters, see special csv parameter.

Dynamic parameters used in inline tables

Dynamic parameters can be used in inline tables, which are used within a step. These parameters can take values from the data tables.

Example

In the following example, <name> is a dynamic parameter, which is used in the inline table. This parameter takes values from the data table.

# Create projects

    |id| name |
    |--|------|
    |1 | john |
    |2 | mike |

## First scenario

* Create the following projects
    |project name| username |
    |------------|----------|
    | Gauge java | <name>   |
    | Gauge ruby | <name>   |

4. Special Parameters

Special parameters provide the ability to pass large and complex data such as tables and files into the steps as parameters.

A special parameter has the following syntax: <prefix:value>.

  • prefix - defines the special type of parameter such as file or table

  • value - defines the value for the type of special parameter

The two types of special parameters are as follows:

  • File

  • CSV

Special Parameter: File

These are used to read files and pass the file content as a string parameter to the steps in a specification.

The syntax of file is as follows: <file:[value]>, [value] is the absolute or relative path to the file located at <project_root> (location at which the Gauge project is created).

Examples

In the following example, email.txt is the absolute value of the special parameter, file.

* Verify email text is <file:email.txt>

In the following example, content.txt is the file located at <project_root>/work/content.txt, /work/content.txt is the relative path passed as the value to file.

* Check if <file:/work/content.txt> is visible
Special Parameter: CSV

Tables are used to pass table values into steps by using the values from an external CSV file. The syntax of this parameter is as follows: <table:[value]> [value] is the absolute or relative path to the file located at <project_root> (location at which the Gauge project is created).

Examples

In the following example, data.csv is the absolute value of the special parameter, table.

* Step that takes a table <table:data.csv>

In the following example, users.csv is the file located at /Users/john/work/. /Users/john/work/ is the relative path passed as the value to table.

* Check if the following users exist <table:/Users/john/work/users.csv>

The following is an example of a sample CSV file, with the first row as table header and following rows are row values:

Id,Name
1,The Way to Go On
2,Ivo Jay Balbaert

Tags

Tags are used to associate labels with specifications or scenarios. Tags help in searching or filtering specs or scenarios.

Tags are written as comma separated values in the specification with a prefix Tags: . Both scenarios and specifications can be separately tagged, however, only one set of tags can be added to a single specification or scenario. A tag applied to a spec automatically applies to a scenario as well.

When the number of tags used is more, tags can be defined in multiple lines to enhance readability.

Example: Single line tag

In the following example, both the specification, Search specification, and scenario, Successful search, have tags. search and admin tags, which are used for the specification also apply to the scenario. Additionally, the scenario has its own set of tag, which is successful.

# Search specification
  Tags: search, admin

## Successful search
   Tags: successful

Example: Multi-line tag

In the following example, both the specification and scenario have tags in multiple lines. Tags have to be indented when written in multiple lines.

# Login specification

Tags: login,
 admin, user-abc

## Successful login scenario

Tags: admin,
 login-success

How to add comments in a specification

Any sentence in plain text which does not follow any syntax is seen as a comment in a spec. Comments help enhance readability of a spec without being executed.

Example

In the following example, The admin user must be able to search for available products on the search page is a comment. This is in plain text without any syntax and provides information about the specification. Similarly, For an existing product name, the search result will contain the product name is also a comment within the scenario and provides information about the scenario. These comments enhance readability without getting executed when the specification is run.

# Search specification
Tags: search, admin

The admin user must be able to search for available products on the search page

## Successful search
Tags: successful

For an existing product name, the search result will contain the product name

* User must be logged in as "admin"
* Open the product search page
* Search for product "Cup Cakes"
* "Cup Cakes" should show up in the search results

Concepts

Concepts provide the ability to combine re-usable, logical groups of steps into a single unit. A concept presents the summary of a business intent by combining logical groups of steps.

Concepts follow the same rules or guidelines that are required while using steps within a spec. Multiple concepts can be used within a spec and concepts can be nested too. When the specification is run, all concepts and their steps are executed in the defined order.

Defining a concept

Concepts are defined in a .cpt file format. By default, Gauge will scan for concepts <project_root> directory, where <project_root> is the location at which the Gauge project is created. The recommended path for concepts at <project_root>/specs. Concepts can also be inside nested directories within the specs directory. Multiple concept definitions can be invoked from within a concept definition. A concept definition consists of a concept header and concept steps.

Note

The path and name of the concepts directory can be changed by using gauge_concepts_dir property in the default.properties file of your project. E.g. gauge_concepts_dir=concepts

Concept header

Concept header defines the name of the concept and the parameters used in the concept. Concept header is written in the H1 format of Markdown syntax. Parameters are defined as <parameters>.

Example

In the following example, the concept header is preceded by #. <username> and <project_name> are parameters used in the concept.

# Login as user <username> and create project <project_name>

Concept steps

Concept steps are used in a way similar to using steps in a specification. These follow the concept header. If parameters are used from the the concept header, then these parameters must be used within < >. Parameters within concepts steps can also have static values, which are written within double quotes " ".

Example

The following example shows a concept (.cpt) file with a concept header (preceded by #) and <username> and <project_name> as parameters. Parameters are defined in the concept header. This concept has three steps. “password” is the static value of another parameter used in one of the concept steps.

# Login as user <username> and create project <project_name>

* Login as user <username> and "password"
* Navigate to project page
* Create a project <project_name>

This concept is invoked from a spec as follows:

# Login specification

## Successful login scenario

* Login as user "john" and create project "Gauge java"

Contexts

Contexts or Context steps are steps defined in a spec prior to a scenario. These steps allow you to specify a set of conditions that are necessary for executing scenarios in a spec. If there are multiple scenarios, context steps are executed prior to every scenario in the specification. A context step must be preceded by * and are executed in the defined order. Hence, they are similar to steps used in a scenario or concept.

Example

In the following example, the context steps are User is logged in as Mike and Navigate to the project page. These steps are defined and executed prior to the two scenarios, ## Delete single project and ## Delete multiple projects.

When the specification is run, the workflow is as follows:

  1. Context steps execution

  2. Delete single project scenario execution

  3. Context steps execution

  4. Delete multiple projects scenario execution

# Delete project

These are context steps

* User is logged in as "mike"
* Navigate to the project page

## Delete single project

* Delete the "example" project
* Ensure "example" project has been deleted

## Delete multiple projects

* Delete all the projects in the list
* Ensure project list is empty

Tear Down Steps

Tear Down Steps are defined in a spec after the last scenario. These steps allow you to specify some sort of a conclusion after every execution of a scenario in a spec. They are used to perform a tear down function.

If there are multiple scenarios, tear down steps are executed after every scenario in the specification. A tear down step must be preceded by * and are executed in the defined order. Hence, they are similar to steps used in a scenario or concept.

Three or more consecutive underscores, ___, indicates the start of tear down steps.

___
* Tear down step 1
* Tear down step 2
* Tear down step 3

Example

In the following example, the tear down steps that start after the three or more consecutive underscores, ___, are Logout user "mike" and Delete user "mike".

When the specification is run, the workflow is as follows:

  1. Context steps execution

  2. Delete single project scenario execution

  3. Tear down steps execution

  4. Context steps execution

  5. Delete multiple projects scenario execution

  6. Tear down steps execution

# Delete project

* Sign up for user "mike"
* Log in as "mike"

## Delete single project

* Delete the "example" project
* Ensure "example" project has been deleted

## Delete multiple projects

* Delete all the projects in the list
* Ensure project list is empty

____________________
These are teardown steps

* Logout user "mike"
* Delete user "mike"

Step implementations

Every step implementation has an equivalent code as per the language plugin used while installing Gauge. The code is run when the steps inside a spec are executed. The code must have the same number of parameters as mentioned in the step.

Steps can be implemented in different ways such as simple step, step with table, step alias, and enum data type used as step parameters.

Simple step

This is a simple step implementation, which has simple parameters.

Example

In the following example of a step, “hello” and “gauge” are two simple parameters. Hence, the step implementation must also contain the same number of parameters.

* Say "hello" to "gauge"
Implementation
// The Method can be written in **any C# class** as long as it is part of the project.
public class StepImplementation {

    [Step("Say <greeting> to <product name>")]
    public void HelloWorld(string greeting, string name) {
        // Step implementation
    }
}
// This Method can be written in any java class as long as it is in classpath.

public class StepImplementation {

    @Step("Say <greeting> to <product name>")
    public void helloWorld(String greeting, String name) {
        // Step implementation
    }
}
step("Say <greeting> to <name>", function(greeting, name) {
    throw 'Unimplemented Step';
});

// Asynchronous step implementation
step("Say <greeting> to <name>", async function(greeting, name) {
    // Async code
    throw 'Unimplemented Step';
});

Handling asynchronous code in steps with done

step("Say <greeting> to <name>", function(greeting, name, done) {
    try {
        setTimeout(function () {
            // Code for step
            done();
        }, 1000);
    } catch(e) {
        done(e);
    }
});

// Handling errors in promises with done
step("Say <greeting> to <name>", function(greeting, name, done) {
    // Let promise1 be some promise we need to wait for.
    promise1
        .then(done)
        .catch(function(e) { done(e);});
});
@step("Say <greeting> to <product name>")
def hello_world(greeting, name):
    assert False, "Add implementation code"
step 'Say <greeting> to <product name>' do |greeting, name|
    # Code for the step
end

Step with table

When steps have an inline table as a parameter, the step implementation must have the appropriate parameter.

Example

In the following example, “hobbit” and the table are step parameters.

* Create following "hobbit" characters
  |id |name   |
  |---|-------|
  |123|frodo  |
  |456|bilbo  |
  |789|samwise|

If this data is in an external csv file, pass it as table reference

* Create following "hobbit" characters <table:hobbits.csv>
Implementation
// Here Table is a custom data structure defined by gauge.
// This is available by adding a reference to the Gauge.CSharp.Lib.
// Refer : http://nuget.org/packages/Gauge.CSharp.Lib/

public class StepImplementation {

    [Step("Create following <race> characters <table>")]
    public void CreateCharacters(string race, Table table) {
        // Step implementation
    }

}
// Table is a custom data structure defined by gauge.
public class StepImplementation {

    @Step("Create following <race> characters <table>")
    public void createCharacters(String race, Table table) {
        // Step implementation
    }

}
step("Create following <race> characters <table>", async function(race, table) {
    table.entries(function (entry) {
        console.log(`ID ${entry["id"]}`);
        console.log(`Name ${entry["name"]}`);
    });
});
# Here Table is a custom data structure defined by gauge.

@step("Create following <race> characters <table>")
def create_characters(race, table):
    assert False, "Add implementation code"
# Here table is a custom data structure defined by gauge-ruby.

step 'Create following <race> characters <table>' do |race, table|
    puts table.rows
    puts table.columns
end

Step alias

Step alias is a feature when there are multiple step names for the same step functionality. The parameters in the step implementation must match the number and type of parameters used in all the steps names. Step alias feature can be used in a specification when the same functionality is expressed in different ways. This enhances readability of the specification.

Step alias feature helps you follow good software engineering practices such as the DRY (Don’t Repeat Yourself) principle at the code level, while ensuring that the functionality is expressed clearly.

Example 1

In the following example, Create a user "user 1" and Create another user "user 2" are step aliases because they have the same functionality, but are expressed differently. However, Verify "user 1" has access to dashboard and Verify "user 2" has access to dashboard are not step aliases.

# User Creation

## Multiple Users

* Create a user "user 1"
* Verify "user 1" has access to dashboard
* Create another user "user 2"
* Verify "user 2" has access to dashboard
Implementation
public class Users {

    [Step("Create a user <user_name>", "Create another user <user_name>")]
    public void CreateUser(string user_name) {
        // create user user_name
    }

}
public class Users {

    @Step({"Create a user <user_name>", "Create another user <user_name>"})
    public void createUser(String user_name) {
        // create user user_name
    }

}
step(["Create a user <username>", "Create another user <username>"], function (username) {
    // do cool stuff
});
from getgauge.python import step

@step(["Create a user <user name>", "Create another user <user name>"])
def create_user(user_name):
    print("create {}.".format(user_name))
step 'Create a user <user name>','Create another user <user name>' do |user_name|
    // create user user_name
end

Example 2

In the following example, the functionality of sending an email in both scenarios is the same. However, the steps are expressed differently.

## User Creation

* User creates a new account
* A "welcome" email is sent to the user

## Shopping Cart

* User checks out the shopping cart
* Payment is successfully received
* An email confirming the "order" is sent
Implementation
public class Users {

    [Step({"A <email_type> email is sent to the user",
    "An email confirming the <email_type> is sent"})]
    public void SendEmail(string email_type) {
        // Send email of email_type
    }

}
public class Users {

    @Step({"A <email_type> email is sent to the user",
    "An email confirming the <email_type> is sent"})
    public void sendEmail(String email_type) {
        // Send email of email_type
    }

}
step(["A <email_type> email is sent to the user",
"An email confirming the <email_type> is sent"],
function (email_type) {
    // do cool stuff
});
from getgauge.python import step

@step(["A <email_type> email is sent to the user",
"An email confirming the <email_type> is sent"])
def email(email_type):
    print("create {}.".format(email_type))
step 'A <email_type> email is sent to the user',
'An email confirming the <email_type> is sent' do |email_type|
    email_service.send email_type
end

Enum as a step parameter

The constant values of “Enum” data type can be used as parameters in a step. However, the type of parameter should match the Enum name in the step implementation code.

Note

Enum as a step parameter is currently supported for Java only.

Example

In the following example, the parameter SOUTH is of the “Enum” data type. In the equivalent code, the parameter <direction> matches with the Enum name, Direction. The Implementation section shows the step implementation for Java.

* Navigate towards "SOUTH"

Implementation

public enum Direction { NORTH, SOUTH, EAST, WEST; }

@Step("Navigate towards <direction>")
public void navigate(Direction direction) {
    //  code here
}

Execution hooks

Test execution hooks can be used to run arbitrary test code at different levels during the test suite execution.

By default, Gauge clears the state after each scenario so that new objects are created for next scenario execution.

You can configure the level at which Gauge clears the in-memory objects by using the java.properties file.

For more information about configuring the appropriate environment variable in the java.properties file, see Language plugin configurations.

By default, Gauge clears the state after each scenario so that new objects are created for next scenario execution.

You can configure the level at which Gauge clears the in-memory objects by using the csharp.properties file.

For more information about configuring the appropriate environment variable in the csharp.properties file, see Language plugin configurations.

Implementation

public class ExecutionHooks
{

    [BeforeSuite]
    public void BeforeSuite() {
        // Code for before suite
    }

    [AfterSuite]
    public void AfterSuite() {
        // Code for after suite
    }

    [BeforeSpec]
    public void BeforeSpec() {
        // Code for before spec
    }

    [AfterSpec]
    public void AfterSpec() {
        // Code for after spec
    }

    [BeforeScenario]
    public void BeforeScenario() {
        // Code for before scenario
    }

    [AfterScenario]
    public void AfterScenario() {
        // Code for after scenario
    }

    [BeforeStep]
    public void BeforeStep() {
        // Code for before step
    }

    [AfterStep]
    public void AfterStep() {
        // Code for after step
    }

}
public class ExecutionHooks {

    @BeforeSuite
    public void BeforeSuite() {
        // Code for before suite
    }

    @AfterSuite
    public void AfterSuite() {
        // Code for after suite
    }

    @BeforeSpec
    public void BeforeSpec() {
        // Code for before spec
    }

    @AfterSpec
    public void AfterSpec() {
        // Code for after spec
    }

    @BeforeScenario
    public void BeforeScenario() {
        // Code for before scenario
    }

    @AfterScenario
    public void AfterScenario() {
        // Code for after scenario
    }

    @BeforeStep
    public void BeforeStep() {
        // Code for before step
    }

    @AfterStep
    public void AfterStep() {
        // Code for after step
    }

}
beforeSuite(fn, [opts]) {
    // Code for before suite
}

beforeSpec(fn, [opts]) {
    // Code for before spec
}

beforeScenario(fn, [opts]) {
    // Code for before scenario
}

beforeStep(fn, [opts]) {
    // Code for before step
}

afterSuite(fn, [opts]) {
    // Code for after suite
}

afterSpec(fn, [opts]) {
    // Code for after spec
}

afterScenario(fn, [opts]) {
    // Code for after scenario
}

afterStep(fn, [opts]) {
    // Code for after step
}

Handling asynchronous code in hooks

// using done
beforeStep(function (context, done) {
    setTimeout(function() {
        done();
    }, 1000);
});

// using async functions
beforeStep(async function () {
    // async code for before step
});
from getgauge.python import before_step, after_step, before_scenario, after_scenario, before_spec, after_spec, before_suite, after_suite

@before_step
def before_step_hook():
    print("before step hook")

@after_step
def after_step_hook():
    print("after step hook")

@before_scenario
def before_scenario_hook():
    print("before scenario hook")

@after_scenario
def after_scenario_hook():
    print("after scenario hook")

@before_spec
def before_spec_hook():
    print("before spec hook")

@after_spec
def after_spec_hook():
    print("after spec hook")

@before_suite
def before_suite_hook():
    print("before suite hook")

@after_suite
def after_suite_hook():
    print("after suite hook")
before_suite do
    # Code for before suite
end

after_suite do
    # Code for after suite
end

before_spec do
    # Code for before spec
end

after_spec do
    # Code for after spec
end

before_scenario do
    # Code for before scenario
end

after_scenario do
    # Code for after scenario
end

before_step do
    # Code for before step
end

after_step do
    # Code for after step
end

Current Execution Context in the Hook

To get additional information about the current specification and scenario and step execution, an additional parameter called ExecutionContext can be added to the hooks method.

using Gauge.CSharp.Lib;
using static Gauge.CSharp.Lib.ExecutionContext;

[BeforeScenario]
public void BeforeScenario(ExecutionContext context)
{
    String scenarioName = context.CurrentScenario.Name;
    //Code for before scenario
}

[AfterSpec]
public void AfterSpec(ExecutionContext context)
{
    Specification specification = context.CurrentSpecification;
    //Code for after spec
}
@BeforeScenario
public void loginUser(ExecutionContext context) {
    String scenarioName = context.getCurrentScenario().getName();
    // Code for before scenario
}

@AfterSpec
public void performAfterSpec(ExecutionContext context) {
Specification currentSpecification = context.getCurrentSpecification();
    //Code for after spec
}
beforeScenario(function (context) {
    var scenario = context.currentScenario
    // Code for before scenario
});

afterSpec(function (context) {
    var specification = context.currentSpec
    //Code for after spec
});
from getgauge.python import before_step, after_scenario

@before_step
def before_step_hook(context):
    print(context)

@after_spec
def after_spec_hook(context):
    print(context)
before_spec do |execution_info|
    puts execution_info.inspect
end

after_spec do |execution_info|
    puts execution_info.inspect
end

Filtering Hooks execution based on tags

You can specify tags for which the execution hooks can run. This ensures that the hook only runs on scenarios and specifications that have the specified tags.

Note

Tags cannot be specified on @BeforeSuite and @AfterSuite hooks.

// A before spec hook that runs when tag1 and tag2
// is present in the current scenario and spec.
[BeforeSpec("tag1, tag2")]
public void LoginUser() {
    // Code for before scenario
}

// A after step hook runs when tag1 or tag2
// is present in the current scenario and spec.
// Default tagAggregation value is Operator.AND.
[AfterStep("tag1", "tag2")]
[TagAggregationBehaviour(TagAggregation.Or)]
public void PerformAfterStep() {
    // Code for after step
}
// A before spec hook that runs when tag1 and tag2
// is present in the current scenario and spec.
@BeforeSpec(tags = {"tag1, tag2"})
public void loginUser() {
    // Code forbefore scenario
}

// A after step hook runs when tag1 or tag2
// is present in the currentscenario and spec.
// Default tagAggregation value is Operator.AND.
@AfterStep(tags = {"tag1", "tag2"}, tagAggregation = Operator.OR)
public void performAfterStep() {
    // Code for after step
}
// A before spec hook that runs when tag1 and tag2
// is present in the current scenario and spec.
beforeSpec(function () {
    //implementation
}, { tags: [ "tag1", "tag2" ]});

// A after step hook runs when tag1 or tag2
// is present in the currentscenario and spec.
// Default tagAggregation value is Operator.AND.
afterStep(function () {
    //implementation
}, { tags: [ "tag1", "tag2" ]});
// A before spec hook that runs when tag1 and tag2
// is present in the current scenario and spec.
@before_spec("<tag1> and <tag2>")
def before_spec_hook():
    print("before spec hook with tag")

// A after step hook runs when tag1 or tag2
// is present in the currentscenario and spec.
// Default tagAggregation value is Operator.AND.
@after_step("<tag1> and <tag2>")
def after_step_hook():
    print("after step hook with tag")
# A before spec hook that runs when
# tag1 and tag2 is present in the current scenario and spec.
before_spec({tags: ['tag2', 'tag1']}) do
    # Code for before scenario
end

# A after step hook runs when tag1 or tag2
# is present in the current scenario and spec.
# Default tagAggregation value is Operator.AND.
after_step({tags: ['tag2', 'tag1'], operator: 'OR'}) do
    # Code for after step
end

Data Store

Data (Objects) can be shared in steps defined in different classes at runtime using DataStores exposed by Gauge.

There are three different types of DataStores based on the lifecycle of when in-memory objects get cleared.

ScenarioStore

This DataStore keeps values added to memory during the lifecycle of the scenario execution. Values are cleared after every scenario is executed.

using Gauge.CSharp.Lib;

// Adding value
var scenarioStore = DataStoreFactory.ScenarioDataStore;
scenarioStore.Add("element-id", "455678");

// Fetching Value
var elementId = (string) scenarioStore.Get("element-id");

// avoid type cast by using generic Get
var anotherElementId = scenarioStore.Get("element-id");
import com.thoughtworks.gauge.datastore.ScenarioDataStore;

// Adding value
ScenarioDataStore.put("element-id", "455678");

// Fetching Value
String elementId = (String) ScenarioDataStore.get("element-id");
// Adding value
gauge.dataStore.scenarioStore.put(key, value);

// Fetching Value
gauge.dataStore.scenarioStore.get(key);
# Import Package
from getgauge.python import data_store

# Adding value
data_store.scenario["key"] = value
# OR
data_store.scenario.key = value

# Fetching Value
data_store.scenario["key"]
# OR
data_store.scenario.key
// Adding value
scenario_store = DataStoreFactory.scenario_datastore;
scenario_store.put("element-id", "455678");


// Fetching Value
element_id = scenario_store.get("element-id");

SpecStore

This DataStore keeps values added to memory during the lifecycle of the specification execution.

Values are cleared after every specification is executed.

using Gauge.CSharp.Lib;

// Adding value
var specStore = DataStoreFactory.SpecDataStore;
specStore.Add("element-id", "455678");

// Fetching Value
var elementId = (string) specStore.Get("element-id");

// avoid type cast by using generic Get
var anotherElementId = specStore.Get("element-id");
// Import Package
import com.thoughtworks.gauge.datastore.SpecDataStore;

// Adding value
SpecDataStore.put("key", "455678");

// Fetching value
String elementId = (String) SpecDataStore.get("key");
// Adding value
DataStore specStore = gauge.dataStore.specStore.put(key, value);

// Fetching value
DataStore specStore = gauge.dataStore.specStore.get(key);
# Import Package
from getgauge.python import data_store

# Adding value
data_store.spec["key"] = value
# OR
data_store.spec.key = value

# Fetching value
data_store.spec["key"]
# OR
data_store.spec.key
// Adding value
spec_store = DataStoreFactory.spec_datastore;
spec_store.put("element-id", "455678");

// Fetching Value
element_id = spec_store.get("element-id");

SuiteStore

This DataStore keeps values added to memory during the lifecycle of the entire test suite execution.

Values are cleared after the entire test suite is executed.

Warning

It is not recommended to use SuiteStore when executing specs in parallel. The values are not retained between parallel streams of execution.

using Gauge.CSharp.Lib;

// Adding value
var suiteStore = DataStoreFactory.SuiteDataStore;
suiteStore.Add("element-id", "455678");

// Fetching Value
var suiteStore = DataStoreFactory.SuiteDataStore;
var elementId = (string) suiteStore.Get("element-id");

// Avoid type cast by using generic Get
var anotherElementId = suiteStore.Get("element-id");
// Import Package
import com.thoughtworks.gauge.datastore.SuiteDataStore;

// Adding value
SuiteDataStore.put("element-id", "455678");

// Fetching value
String elementId = (String) SuiteDataStore.get("element-id");
// Adding value
DataStore suiteStore = gauge.dataStore.suiteStore.put(key, value);

// Fetching value
DataStore specStore = gauge.dataStore.suiteStore.get(key);
# Import Package
from getgauge.python import data_store

# Adding value
data_store.suite["key"] = value
# OR
data_store.suite.key = value

# Fetching value
data_store.suite["key"]
# OR
data_store.suite.key
// Adding value
suite_store = DataStoreFactory.suite_datastore;
suite_store.put("element-id", "455678");

// Fetching Value
suite_store = DataStoreFactory.suite_datastore;
element_id = suite_store.get("element-id");

Taking Custom Screenshots

When Gauge takes a screenshot, Gauge captures whatever is displayed on the screen. This is the default behavior. If you want to customize this behavior and enable Gauge to take screenshots of your choice, (for example, you might want a screenshot of only the browser page) you can use appropriate driver APIs in the step implementation of the language runner used while creating the Gauge project.

//Using Webdriver public
class CustomScreenGrabber : ICustomScreenshotGrabber {

    // Return a screenshot byte array
    public byte[] TakeScreenshot() {
        var driver = DriverFactory.getDriver();
        return ((ITakesScreenshot) driver).GetScreenshot().AsByteArray;
    }
}
public class CustomScreenshotGrabber implements CustomScreenshotWriter {

    // Return a screenshot file name
    @Override
    public String takeScreenshot() {
        TakesScreenshot driver = (TakesScreenshot) DriverFactory.getDriver();
        String screenshotFileName = String.format("screenshot-%s.png", UUID.randomUUID().toString());
        try {
            Files.write(Path.of(System.getenv("gauge_screenshots_dir"), screenshotFileName),
                    driver.getScreenshotAs(OutputType.BYTES));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return screenshotFileName;
    }

}
// Using Taiko
// Return a screenshot file name
gauge.customScreenshotWriter = async function () {
    const screenshotFilePath = path.join(process.env['gauge_screenshots_dir'], `screenshot-${process.hrtime.bigint()}.png`);
    await screenshot({ path: screenshotFilePath });
    return path.basename(screenshotFilePath);
};
# Using Webdriver
from uuid import uuid1
from getgauge.python import custom_screenshot_writer

# Return a screenshot file name
@custom_screenshot_writer
def take_screenshot():
    # Use appropriate webdriver instance
    image = driver.get_screenshot_as_png()
    file_name = os.path.join(os.getenv("gauge_screenshots_dir"), "screenshot-{0}.png".format(uuid1().int))
    file = open(file_name, "wb")
    file.write(image)
    return os.path.basename(file_name)
# Using Webdriver
Gauge.configure do |config|
    config.custom_screenshot_writer = -> {
        screenshot_data = driver.screenshot_as(:png)
        file = File.join(config.screenshot_dir, "screenshot-#{(Time.now.to_f*10000).to_i}.png")
        File.write(file, screenshot_data)
        File.basename(file)
    }
end

Note

If multiple custom ScreenGrabber implementations are found in classpath then gauge will pick one randomly to capture the screen. This is because gauge selects the first ScreenGrabber it finds, which in turn depends on the order of scanning of the libraries.

Adding screenshots in reports

If there is any failure while running a spec, Gauge captures a screenshot on such a failure. This is the default behavior. If you want to enable Gauge to capture a screenshot at any point in time when a spec is run, call:

GaugeScreenshots.Capture();
Gauge.captureScreenshot();
gauge.screenshot();
from getgauge.python import Screenshots

Screenshots.capture_screenshot()
Gauge.capture

The APIs can be used in step implementations or hooks. These screenshots are displayed after steps in the execution reports.

Custom messages in reports

Custom messages or data can be added to execution reports by using APIs in the step implementations or hooks.

These messages are displayed after the steps in the execution reports.

GaugeMessages.WriteMessage("Custom message for report");
var id = "4567";
GaugeMessages.WriteMessage("User id is {0}", id);
Gauge.writeMessage("Custom message for report");
String id = "4567";
Gauge.writeMessage("User id is %s", id);
gauge.message("Custom message for report");
from getgauge.python import Messages

Messages.write_message("Custom message for report")
Gauge.write_message("Custom message for report")
id = "4567"
Gauge.write_message("User id is" + id)

Continue on Failure

Step implementations are non-recoverable by default and Gauge does not execute subsequent steps upon failure. Sometimes, it is necessary to execute all steps in a scenario irrespective of whether the previous step has failed or not.

To enable such a requirement, Gauge supports a feature called ContinueOnFailure. This feature allows language runners to mark steps as recoverable. To make a step implementation continue on failure, the step implementation needs to be explicitly marked in the test code.

Each language runner uses a different syntax, depending on the language idioms, to allow a step implementation to be marked to continue on failure.

// The ``[ContinueOnFailure]`` attribute tells Gauge to continue executing others
// steps even if the current step fails.

public class StepImplementation {
    [ContinueOnFailure]
    [Step("Say <greeting> to <product name>")]
    public void HelloWorld(string greeting, string name) {
        // If there is an error here, Gauge will still execute next steps
    }

}
// The ``@ContinueOnFailure`` annotation tells Gauge to continue executing other
// steps even if the current step fails.

public class StepImplementation {
    @ContinueOnFailure
    @Step("Say <greeting> to <product name>")
    public void helloWorld(String greeting, String name) {
        // If there is an error here, Gauge will still execute next steps
    }

}
// The ``@ContinueOnFailure`` annotation tells Gauge to continue executing other
// steps even if the current step fails.

gauge.step("Say <greeting> to <product>.", { continueOnFailure: true}, function (greeting,product) {
});
# The ``@ContinueOnFailure`` annotation tells Gauge to continue executing other
# steps even if the current step fails.

@continue_on_failure([RuntimeError])
@step("Say <greeting> to <product>")
def step2(greeting,product):
    pass
# The ``:continue_on_failure => true`` keyword argument
# tells Gauge to continue executing other steps even
# if the current step fails.

step 'Say <greeting> to <name>', :continue_on_failure => true do |greeting, name|
    # If there is an error here, Gauge will still execute next steps
end

ContinueOnFailure can take an optional parameter to specify the list of error classes on which Gauge would continue to execute further steps in case of failure. Having an optional parameter can be used to control for what type of errors the Gauge execution must continue, instead of just continuing execution for every error.

For example, when a RuntimeException error occurs, it is ideally not expected to continue further execution. However, if it is an assertion error, it might be fine to continue test execution.

This is currently supported only with Java and Python.

If ContinueOnFailure has no parameters, then the step execution continues by default regardless of the type of error that occurs.

@ContinueOnFailure({AssertionError.class, CustomError.class})
@Step("hello")
public void sayHello() {
  // code here
}

@ContinueOnFailure(AssertionError.class)
@Step("hello")
public void sayHello() {
  // code here
}

@ContinueOnFailure
@Step("hello")
public void sayHello() {
  // code here
}
@continue_on_failure([RuntimeError])
@step("Step 2")
def step2():
    pass

Note

  • ContinueOnFailure is executed after the step method is executed. If there is a failure in executing the step, for example, due to parameter count or type mismatch, then Gauge does not execute the ContinueOnFailure feature.

  • ContinueOnFailure does not apply to hooks. Hooks always fail on first error.

  • Each step implementation has to be marked explicitly if the step needs to continue on failure.

  • It is not possible to globally apply ContinueOnFailure on all the steps.

  • If an implementation uses step aliases, marking that implementation to continue on failure ensures that all the aliases also continue on failure. So, if a step alias is supposed to break on failure and another step alias is supposed to continue on failure, the step aliases need to be extracted to two different step implementations.

Gauge Project Structure

When a Gauge project is initialized for a particular language plugin, a project structure is created at <project_root>. The project structure consists of language-specific files depending on the language plugin used and some common files and directories for all language plugins.

<project_root> - location at which the Gauge project is created.

Common Gauge project files

Regardless of the language plugin used, few common files and directories are created when a Gauge project is initialized.

The following are the common files and directories in the Gauge project structure:

  • env

  • logs

  • specs

  • manifest.json

├── env
│  └── default
│     └── default.properties
├── logs
├── manifest.json
├── specs
   └── example.spec

Env Directory

The env directory contains multiple environment specific directories. Each directory has .property files which define the environment variables set during spec execution for that specific environment.

A env/default directory is created when a Gauge project is initialized. The default directory has the default.properties file, which contains the default environment variables set during spec execution. This directory also has the language specific .property file which contains language-specific environment variables.

Note

Specs Directory

The specs directory contains all the specification files for the project. A sample specification file called example.spec is created in this directory to understand the format of a specification file.

A specification is a business test case, written in Markdown, which describes a particular feature of the application that needs testing.

For more information about what a specification is and spec directory, see Specifications (spec) and Specs directory.

Manifest file

The manifest.json file contains information such as the language used and plugins required for the Gauge project.

After the Gauge project is initialized, manifest.json has the following information:

{
  "Language": "<language>",
  "Plugins": [
    "html-report"
  ]
}

Language - indicates the programming language used for the test code. Gauge uses this language runner for executing specs.

Plugins - indicates the plugins used for the project. Some plugins are used by default for each gauge project. Plugins can also be added to the project by installing the required plugin.

For example, if you want to add xml-report plugin to the manifest.json file, you must install the xml-report plugin. After the plugin is installed, manifest.json has the following content:

{
  "Language": "<language>",
  "Plugins": [
    "html-report",
    "xml-report"
  ]
}

For more information about installing a plugin and related details, see Install Plugins.

Language-specific project files

When the Gauge project is initialized, depending on the language plugin used, language-specific files are created in the project.

The following project structure shows the project structure for the selected language when used for creating a Gauge project.

├── foo.csproj
├── foo.sln
├── manifest.json
├── packages.config
├── StepImplementation.cs
│
├── env
│   └───default
│           csharp.properties
│
├───packages
    └───<Nuget Package Binaries>
├───Properties
│       AssemblyInfo.cs
│
└───specs
        example.spec

packages.config

Nuget Package Binaries contains nuget dependencies for Gauge.

StepImplementation.cs

This file contains the implementations for the sample steps defined in example.spec.

csharp.properties

This file defines configurations for CSharp runner plugin. For more information about language-specific configuration, see Language plugin configurations.

├── manifest.json
├── libs
└── src
    └── test
        └── java
            └── StepImplementation.java
├── env
    └── default
        └── java.properties
└───specs
    example.spec

libs

This contains the additional java dependencies required for the project.

src

This directory contains the classes including step implementations.

java.properties

This file defines configurations for Java runner plugin. For more information about language-specific configuration, see Language plugin configurations.

├── manifest.json
└── tests
        └── step_implementation.js
├── env
    └── default
        └── js.properties
└───specs
        example.spec

tests

This directory contains the test code including step implementations.

js.properties

This file defines configurations for JavaScript runner plugin. For more information about language-specific configuration, see Language plugin configurations.

├── manifest.json
└── step_impl
        └── step_impl.py
├── env
    └── default
        └── python.properties
└───specs
    example.spec

step_impl

This directory contains the test code including step implementations.

python.properties

This file defines configurations for Python runner plugin. For more information about language-specific configuration, see Language plugin configurations.

├── manifest.json
├── env
│   └── default
│       └── ruby.properties
└── step_implementations
    └── step_implementation.rb
└───specs
        example.spec

step_implementations directory

This directory contains all the .rb files with the test code including step implementations in ruby.

ruby.properties

This file defines configurations for Ruby runner plugin. For more information about language-specific configuration, see Language plugin configurations.