Skip to main content

Data Feeds

You can feed input data from CSV or JSON files.

Ready Only

All input data is read-only at evaluation time by default since v4.0.0 (except in REPL mode). This can be disabled through the gwen.input.data.readOnly setting if required.

CSV data feeds

Since v1.0.0

CSV data files can be passed into the interpreter to perform feature execution over multiple data sets. The first row in a CSV data file must be a list of column names for the contained data that follows. The values in each record will be bound to attributes in the feature scope having these same names. Feature steps can reference the bound data using these names.

Say you have a users.csv file containing following user records.

CSV

File: data/users.csv

name,surname,job
Gwen,Stefani,Pop Singer
Gwyneth,Paltrow,Actress
Gwen,Cooper,Torchwood Agent

The first row in this file specifies a comma separated list of column names. The remaining rows specify the comma separated lists of values for each record. Now say you wanted to submit the details for each user to a web page through a single submit-user.feature file that accepts all the user data as input one at a time. You can do this in the feature by referencing CSV data values by their column names as follows:

Feature

File: features/submit-user.feature

Feature: Submit user ${name} ${surname}

Scenario: submit user details
Given I navigate to the user details page
When I type name in the first name field
And I type surname in the last name field
And I type job in the job field
And I click the save button
Then the alert msg should be "User ${name} saved"

Note: Interpolation of CSV fields ${name} ${surname} in the feature name and description is supported since v3.12.1

The current CSV record number or index is available as an implicit attribute:

  • gwen.data.record.number = current record number starting at 1
  • gwen.data.record.index = current record index starting at 0

You can execute this feature for all users in the CSV file by launching Gwen with the -i|--input-data option.

Examples

yarn gwen -b -i gwen/data/users.csv gwen/features/submit-user.feature

or

yarn gwen -b --input-data gwen/data/users.csv gwen/features/submit-user.feature

Gwen will read in the CSV file, and for each record will:

  • Bind the data to the feature
  • And execute the feature

A feature detail report will be generated for each data record. If you specify the --parallel launch option, the feature will execute all records in parallel.

JSON data feeds

Flat JSON data feeds

Since v3.47.0

Flat JSON data files can be passed into the interpreter to perform feature execution over multiple data sets. The values in each record will be bound to attributes in the feature scope by their names. Feature steps can reference the bound data using these names.

Say you have a users.json file containing following user records.

JSON

File: data/users.json

[
{ "name": "Gwen", "surname": "Stefani", "job": "Pop Singer" },
{ "name": "Gwyneth", "surname": "Paltrow", "job": "Actress" },
{ "name": "Gwen", "surname": "Cooper", "job": "Torchwood Agent" }
]

Now say you wanted to submit the details for each user to a web page through a single submit-user.feature file that accepts all the user data as input one at a time. You can do this in the feature by referencing JSON data values by their names as follows:

Feature

File: features/submit-user.feature

Feature: Submit user ${name} ${surname}

Scenario: submit user details
Given I navigate to the user details page
When I type name in the first name field
And I type surname in the last name field
And I type job in the job field
And I click the save button
Then the alert msg should be "User ${name} saved"

Note: Interpolation of JSON fields ${name} ${surname} is supported in the feature name and description too.

The current JSON record number or index is available as an implicit attribute:

  • gwen.data.record.number = current record number starting at 1
  • gwen.data.record.index = current record index starting at 0

You can execute this feature for all users in the JSON file by launching Gwen with the -i|--input-data option.

Examples

yarn gwen -b -i gwen/data/users.json gwen/features/submit-user.feature

or

yarn gwen -b --input-data gwen/data/users.json gwen/features/submit-user.feature

Gwen will read in the JSON file, and for each record will:

  • Bind the data to the feature
  • And execute the feature

A feature detail report will be generated for each data record. If you specify the --parallel launch option, the feature will execute all records in parallel.

Structured JSON data feeds

Since v3.66.0

Structured JSON data files can be passed into the interpreter to perform feature execution over multiple data sets. The values in each record will be bound to attributes in the feature scope by their path names. Feature steps can reference the bound data using these path names.

Say you have a users.json file containing following user records.

JSON

File: data/users.json

[
{
"user": {
"name": "Gwen",
"surname": "Stefani",
"jobs": [
"Pop Singer",
"Solo Artist"
]
}
},
{
"user": {
"name": "Gwyneth",
"surname": "Paltrow",
"jobs": [
"Actress",
"Singer"
]
}
},
{
"user": {
"name": "Gwen",
"surname": "Cooper",
"jobs": [
"Actress",
"Torchwood Agent"
]
}
}
]

Now say you wanted to submit the details for each user to a web page through a single submit-user.feature file that accepts all the user data as input one at a time. You can do this in the feature by referencing JSON data values by their path names as follows:

Feature

File: features/submit-user.feature

Feature: Submit user ${user.name} ${user.surname}

Scenario: submit user details
Given I navigate to the user details page
When I type user.name in the first name field
And I type user.surname in the last name field
And I click the save button
Then the alert msg should be "User ${user.name} saved"

Note: Interpolation of JSON fields ${user.name} ${user.surname} is supported in the feature name and description too.

You can execute this feature for all users in the JSON file by launching Gwen with the -i|--input-data option.

The current JSON record number or index is available as an implicit attribute:

  • gwen.data.record.number = current record number starting at 1
  • gwen.data.record.index = current record index starting at 0

Nested Arrays

Nested arrays can be referenced as JSON Array objects, for example:

  And job 1 is "${user.jobs[0]}"
And job 2 is "${user.jobs[1]}"
And job count is defined by js "${user.jobs}.length"

Looping Nested Arrays

You can loop over JSON arrays with the following DSL

Nested string array Example:

  "user": { 
"name": "Gwen",
"surname": "Stefani",
"jobs": [
"Pop Singer",
"Solo Artist"
]
}
  And I type job in the job field for each job in user.jobs array

Nested object array Example:

  "user": { 
"name": "Gwen",
"surname": "Stefani",
"jobs": [
{ "name": "Pop Singer" },
{ "name": "Solo Artist" }
]
}
  And I type job.name in the job field for each job in user.jobs array

Single JSON Object

If your input JSON contains a single object instead of an array, it will be treated as an array containing a single record of that object.

For example, this:

  { 
"user": {
"name": "Gwen",
"surname": "Stefani",
"job": "Pop Singer"
}
}

Will be treated as:

  [
{
"user": {
"name": "Gwen",
"surname": "Stefani",
"job": "Pop Singer"
}
}
]

Top-level Array of JSON values

If your input JSON contains an array of non-object values (Strings or other primatives), each value will be bound to the name data when iterated.

For example, this:

  [
"string 1",
"string 2",
"string 3"
]

Will be treated the same as:

  {
"data" : [
"string 1",
"string 2",
"string 3"
]
}

Examples

yarn gwen -b -i gwen/data/users.json gwen/features/submit-user.feature

or

yarn gwen -b --input-data gwen/data/users.json gwen/features/submit-user.feature

Gwen will read in the JSON file, and for each record will:

  • Bind the data to the feature
  • And execute the feature

A feature detail report will be generated for each data record. If you specify the --parallel launch option, the feature will execute all records in parallel.

@Examples annotation

Since v2.10.0

Consider the following scenario outline with an examples table

Example

Scenario outline with inlined data

  Scenario Outline: I load items from data files
When I add a <Status> "<Item>" item

Examples:
| Item | Status |
| Walk the dog | pending |
| Get the milk | done |
| Feed the cat | pending |

CSV Data

The data table in the examples clause can be externalised to a CSV file and imported using the @Examples annotation as follows:

Example

CSV File: data/items.csv

Item,Status
Walk the dog,pending
Get the milk,done
Take out trash,pending

Scenario outline with externalised CSV data

  @Examples("data/items.csv")
Scenario Outline: I load items from data files
When I add a <Status> "<Item>" item

Or using relative path since v4.0.0

  @Examples("../data/items.csv")
Scenario Outline: I load items from data files
When I add a <Status> "<Item>" item

This will resolve to an identical outline when expanded at runtime:

  Scenario Outline: I load items from data files
When I add a <Status> "<Item>" item

Examples: Data file: data/items.csv
| Item | Status |
| Walk the dog | pending |
| Get the milk | done |
| Feed the cat | pending |

Flat JSON Data

Since v3.47.0

The data table in the examples clause can be externalised to a JSON file and imported using the @Examples annotation as follows:

Example

JSON File: data/items.json

[
{ "Item": "Walk the dog", "Status": "pending" },
{ "Item": "Get the milk", "Status": "done" },
{ "Item": "Take out trash", "Status": "pending" }
]

Scenario outline with externalised JSON data

  @Examples("data/items.json")
Scenario Outline: I load items from data files
When I add a <Status> "<Item>" item

This will resolve to an identical outline when expanded at runtime:

  Scenario Outline: I load items from data files
When I add a <Status> "<Item>" item

Examples: Data file: data/items.json
| Item | Status |
| Walk the dog | pending |
| Get the milk | done |
| Feed the cat | pending |

Structured JSON Data

Since v3.66.0

Example

JSON File: data/items2.json

[
{
"Item": {
"Name": "Mow the lawn",
"Status": "pending"
}
},
{
"Item": {
"Name": "Do the washing",
"Status": "done"
}
},
{
"Item": {
"Name": "Take a break",
"Status": "pending"
}
}
]

Scenario outline with externalised JSON data

  @Examples("data/items2.json")
Scenario Outline: I load items from data files
When I add a <Item.Status> "<Item.Name>" item

This will resolve to the following outline when expanded at runtime:

  Scenario Outline: I load items from data files
When I add a <Item.Status> "<Item.Name>" item

Examples: Data file: data/items2.json
| Item.Name | Item.Status |
| Walk the dog | pending |
| Get the milk | done |
| Feed the cat | pending |

Where filter

Since v3.27.0

The data can also be filtered using a where JavaScript expression filter. For example, to get all the records where the data in the Status column matches pending:

Example

Scenario outline with externalised and filtered data

  @Examples(file="data/items.csv",where="'${Status}'=='pending'")
Scenario Outline: I load items from data files
When I add a <Status> "<Item>" item

Will resolve to the following containing pending Status records only:

  Scenario Outline: I load items from data files
When I add a <Status> "<Item>" item

Examples: Data file: data/items.csv, where: '${Status}'=='pending'
| Item | Status |
| Walk the dog | pending |
| Feed the cat | pending |

String interpolation syntax can also be used to reference a value in the data record or current scope. For example, to get all the records where the Status matches the value bound to an in-memory attribute named SelectedStatus:

Example

Scenario outline with externalised and filtered data

  @Examples(file="data/items.csv",where="'${Status}'=='${SelectedStatus}'")
Scenario Outline: I load items from data files
When I add a <Status> "<Item>" item

Since v3.47.0, a JSON data file can also be used.

Name prefix

Since v3.27.0

A prefix="string" attribute can be added to prepend a prefix to each column name in the CSV heaader record. This is useful for avoiding any potential name clashes with existing data in the current scope.

Example

Scenario outline sourced from CSV file having column names Status, Item

  @Examples(file="data/items.csv",prefix="todo.",where="'${todo.Status}'=='pending'")
Scenario Outline: I load items from data files
When I add a <todo.Status> "<todo.Item>" item

Will result in the column names todo.Status, todo.Item when todo. prefix is applied at runtime

  Scenario Outline: I load items from data files
When I add a <todo.Status> "<todo.Item>" item

Examples: Data file: data/items.csv, prefix: todo., where: '${todo.Status}'=='pending'
| todo.Item | todo.Status |
| Walk the dog | pending |
| Feed the cat | pending |

Since v3.47.0, a JSON data file can also be used.

Required flag

Since v3.20.0

A required=true attribute can be added to raise an error if no data is returned by the where clause filter.

Example

Scenario outline which raises an error if externalised and filtered data is empty

  @Examples(file="data/items.csv",where="'${Status}'=='${SelectedStatus}'",required=true)
Scenario Outline: I load items from data files
When I add a <Status> "<Item>" item

Since v3.47.0, a JSON data file can also be used.

Parallel processing

Since v3.69.0

The Parallel annotation can be used on examples to force each entry to run in parallel

  @Examples("data/items.csv")
@Parallel
Scenario Outline: I load items from data files
When I add a <Status> "<Item>" item

Restrictions

The Parallel annotation:

  • Cannot be used in a nested manner (an error will be raised on any such detection)
  • Will come to effect only when Gwen is invoked without the --parallel launch option (i.e: when no other parallel execution is taking place), and will be implicity removed otherwise.

See also: Parallel Scenario Outline Examples