Data Feeds
You can feed input data from CSV or JSON files.
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.
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:
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 1gwen.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
- npm
- pnpm
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
npm run gwen -- -b -i gwen/data/users.csv gwen/features/submit-user.feature
or
npm run gwen -- -b --input-data gwen/data/users.csv gwen/features/submit-user.feature
pnpm gwen -b -i gwen/data/users.csv gwen/features/submit-user.feature
or
pnpm 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.
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:
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 1gwen.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
- npm
- pnpm
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
npm run gwen -- -b -i gwen/data/users.json gwen/features/submit-user.feature
or
npm run gwen -- -b --input-data gwen/data/users.json gwen/features/submit-user.feature
pnpm gwen -b -i gwen/data/users.json gwen/features/submit-user.feature
or
pnpm 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.
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:
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 1gwen.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
- npm
- pnpm
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
npm run gwen -- -b -i gwen/data/users.json gwen/features/submit-user.feature
or
npm run gwen -- -b --input-data gwen/data/users.json gwen/features/submit-user.feature
pnpm gwen -b -i gwen/data/users.json gwen/features/submit-user.feature
or
pnpm 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
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:
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:
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
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
:
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
:
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.
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.
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
TheParallel
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