Skip to main content
Version: 2x

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:

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);
});

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:

// 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);
}
};

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:

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;

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

  1. Use descriptive names for your memory variables to make scenarios more readable
  2. Prefer string interpolation for complex strings rather than concatenating multiple parts
  3. Create reusable computed functions for common operations or data generation
  4. Use TypeScript interfaces to define the structure of complex memory objects
  5. Document memory constants and functions for better team collaboration