Test Data Management
The @qavajs/memory
module provides powerful capabilities to store, retrieve, and manipulate variables between test steps. This allows you to create more dynamic and data-driven test scenarios.
Basic Usage
Memory allows you to save values during test execution and reference them later:
When I save text of 'Answer' as 'userAnswer'
Then I expect text of 'Another Answer' to equal '$userAnswer'
Memory API
Using the Memory Value Parameter Type
All built-in steps can consume memory params.
Then I expect text of 'Title' to equal '$userAnswer'
The value
parameter type provides a strongly-typed API to access memory and can be used in custom step:
// Reading from memory
When('Read memory {value}', async function(memoryValue) {
// memoryValue.value() retrieves the actual value from memory
expect(memoryValue.value()).to.equal('stored value');
});
// Writing to memory
When('Set memory {value} as {string}', async function(memoryKey, value) {
// memoryKey.set() stores a value in memory
memoryKey.set(value);
});
Direct Memory Access in Custom Steps
You can also access the memory object directly in your step definitions:
- JavaScript
- TypeScript
const memory = require('@qavajs/memory');
When(/^I save value '(.+)' as '(.+)'$/, async function (value, key) {
memory.setValue(key, value);
});
Then(/^value in '(.+)' should equal '(.+)'$/, async function (variable, expectedValue) {
const actualValue = memory.getValue(variable);
expect(actualValue).to.equal(expectedValue);
});
import memory from '@qavajs/memory';
When(/^I save value '(.+)' as '(.+)'$/, async function (value: string, key: string) {
memory.setValue(key, value);
});
Then(/^value in '(.+)' should equal '(.+)'$/, async function (variable: string, expectedValue: string) {
const actualValue = memory.getValue(variable);
expect(actualValue).to.equal(expectedValue);
});
In your Gherkin scenarios, you can access previously saved variables using the $
prefix:
When I save value '42' as 'myNumber'
Then value in 'myNumber' should equal '42'
And I expect text of 'Result Field' to equal '$myNumber'
Advanced Features
Constants and Computed Values
You can define constant values and computed functions that can be referenced in your feature files:
- JavaScript
- TypeScript
// memory.js
module.exports = {
// Constants
maxRetries: 3,
baseUrl: 'https://example.com',
// Computed values (functions that return dynamic values)
timestamp: function() {
return Date.now();
},
randomUsername: function() {
return 'user_' + Math.floor(Math.random() * 10000);
}
};
// memory.ts
export default {
// Constants
maxRetries: 3,
baseUrl: 'https://example.com',
// Computed values (functions that return dynamic values)
timestamp: function() {
return Date.now();
},
randomUsername: function() {
return 'user_' + Math.floor(Math.random() * 10000);
}
};
Reference these values in your Gherkin scenarios:
# Using constants
Then I expect retry count to be '$maxRetries'
When I navigate to '$baseUrl/login'
# Using computed values
Then I expect registration timestamp to be '$timestamp()'
When I register with username '$randomUsername()'
String Interpolation
Use curly braces to interpolate memory values within strings:
When I save '42' as 'score'
Then I expect text of 'Result' to equal 'Your score is {$score} points'
Built-in JavaScript Execution with $js
Use the built-in $js
computed function to execute JavaScript code directly from your Gherkin scenarios:
# Math operations
When I expect the result to equal '$js(42 * 2.5)'
# String manipulation
Then I expect the username to be '$js("user_" + Math.floor(Math.random() * 1000))'
# Date formatting
And I expect the date format to be '$js(new Date().toLocaleDateString())'
Escaping the $ Symbol
When you need to use a literal $
character in your tests, escape it with a double backslash:
When I expect the price to be '\\$42.99'
# This will expect the actual text to be "$42.99"
Parallel Execution Support
For parallel test execution, you can assign unique values for each Cucumber thread using the parallel
function:
- JavaScript
- TypeScript
const { parallel } = require('@qavajs/memory/utils');
class Memory {
// Each parallel thread will get a different user from this array
testUser = parallel([
{ username: 'user1@example.com', password: 'password1' },
{ username: 'user2@example.com', password: 'password2' },
{ username: 'user3@example.com', password: 'password3' }
]);
// You can also use parallel with primitive values
port = parallel([8080, 8081, 8082]);
}
module.exports = Memory;
import { parallel } from '@qavajs/memory/utils';
export class Memory {
// Each parallel thread will get a different user from this array
testUser = parallel([
{ username: 'user1@example.com', password: 'password1' },
{ username: 'user2@example.com', password: 'password2' },
{ username: 'user3@example.com', password: 'password3' }
]);
// You can also use parallel with primitive values
port = parallel([8080, 8081, 8082]);
}
Use these values in your scenarios:
When I login with username '$testUser.username' and password '$testUser.password'
And I connect to port '$port'
Best Practices
- Use descriptive names for your memory variables to make scenarios more readable
- Prefer string interpolation for complex strings rather than concatenating multiple parts
- Create reusable computed functions for common operations or data generation
- Use TypeScript interfaces to define the structure of complex memory objects
- Document memory constants and functions for better team collaboration