#
E2E Scripting Guide
#
Overview
The E2E Scripting feature allows you to write JavaScript code that executes after each API call in your workflow. This enables you to extract data from responses, perform transformations, and pass values between APIs in your test flow.
You can access the script from here for each API:
#
When to Use Scripting vs. Existing Data Mapping
#
Existing Data Mapping (JSON → JSON)
For JSON-to-JSON data passing, you can use the existing advanced data mapping syntax documented in the E2E Testing Guide:
Named References:
{
"id": "%%Previous Connected API.response.id%%",
"userId": "%%Login API.response.userId%%"
}
JSON-e Expressions:
{
"userId": {
"$eval": "previous.response.userId"
},
"extractedId": {
"$eval": "split(previous.response.resourceUrl, '/').slice(-1)[0]"
}
}
Autofill:
{
"customerId": "__autofill__"
}
#
E2E Scripting (JSON ↔ XML or Complex Transformations)
Use E2E Scripting when you need:
- ✅ JSON → XML data mapping - Extract from JSON response, use in XML request
- ✅ XML → JSON data mapping - Parse XML response, use in JSON request
- ✅ XML → XML data mapping - Parse XML response, use in another XML request
- ✅ Complex transformations - String manipulation, calculations, conditional logic
- ✅ Multiple field extractions - Extract and process multiple fields with custom logic
- ✅ Dynamic data generation - Generate random values, timestamps, computed fields
💡 Best Practice: For simple JSON-to-JSON field mapping, use the existing
%%
or$eval
syntax. For XML handling or complex transformations, use scripting for a more generic and flexible experience.
#
Key Concepts
#
Script Execution Flow
For each API in your E2E workflow:
- API request is made with any variables/data you've configured
- Response is received from the server
- Assertions are processed (if any)
- 📍 Your script executes here with access to request/response
- Variables are stored and available for subsequent API calls
#
Available Objects in Scripts
Every script has access to four key objects:
#
Important Notes
- Scripts are written in vanilla JavaScript - no external libraries
- Variables are temporary - they exist only during the execution of a specific test combination
- Variables are different from Environment Variables - script variables are stored in
variables
object and only available during E2E execution, while Environment Variables are persistent across test runs - Each API node has its own script - scripts execute in order of the workflow
#
Using Variables Between APIs
#
Creating Variables
Store data in the variables
object within your script:
// Extract a field from response
variables.userId = response.response.id;
// Store multiple values
variables.authToken = response.headers.authorization;
variables.email = response.response.user.email;
#
Using Variables in Subsequent APIs
Reference stored variables using the {{variableName}}
syntax in any request field:
In Headers:
{
"Authorization": "Bearer {{authToken}}",
"X-User-ID": "{{userId}}"
}
In URL/Path:
/api/users/{{userId}}/profile
/api/accounts/{{accountId}}/details
In JSON Body:
{
"user_id": "{{userId}}",
"email": "{{email}}",
"account_id": "{{accountId}}"
}
In XML Body:
<request>
<userId>{{userId}}</userId>
<token>{{authToken}}</token>
</request>
#
Common Usage Patterns
#
Extract Data from JSON Response
// Simple field extraction
variables.userId = response.response.id;
variables.accountId = response.response.account_id;
// Nested field extraction
variables.email = response.response.user.profile.email;
// Extract from arrays
variables.firstItemId = response.response.items[0].id;
// Conditional extraction
if (response.statusCode === 200) {
variables.isSuccess = true;
variables.userData = JSON.stringify(response.response);
}
#
Extract Headers
// Get authorization token
variables.authToken = response.headers.authorization;
// Get custom headers
variables.requestId = response.headers["x-request-id"];
variables.apiVersion = response.headers["x-api-version"];
#
Process and Transform Data
// String manipulation
variables.upperCaseEmail = response.response.email.toUpperCase();
// Concatenation
variables.fullName = response.response.firstName + " " + response.response.lastName;
// Arithmetic operations
variables.totalPrice = response.response.price * response.response.quantity;
// Date operations
variables.timestamp = new Date().toISOString();
#
Debug Logging
// Log simple values
console.log("User ID:", response.response.id);
// Log objects
console.log("Full response:", response.response);
// Log headers
console.log("Response headers:", response.headers);
// Debug variables
console.log("All stored variables:", variables);
#
Working with Mixed JSON and XML APIs
#
Complete Example: JSON → XML → JSON Flow
Let's walk through a real-world example where you need to pass data between JSON and XML APIs.
#
API 1: JSON Login Request
Endpoint: POST /api/auth/login
Request Body (JSON):
{
"username": "john.doe@example.com",
"password": "securePassword123"
}
Response (JSON):
{
"success": true,
"userId": "USER-12345",
"sessionToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresIn": 3600,
"userData": {
"name": "John Doe",
"email": "john.doe@example.com",
"accountId": "ACC-67890"
}
}
Script for API 1:
// Extract user information from JSON response
variables.userId = response.response.userId;
variables.sessionToken = response.response.sessionToken;
variables.accountId = response.response.userData.accountId;
variables.userName = response.response.userData.name;
// Log for debugging
console.log("Login successful, User ID:", variables.userId);
console.log("Account ID:", variables.accountId);
#
API 2: XML Account Details Request
Endpoint: POST /api/soap/getAccountDetails
Request Body (XML):
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<AuthToken>{{sessionToken}}</AuthToken>
</soap:Header>
<soap:Body>
<GetAccountDetailsRequest>
<UserId>{{userId}}</UserId>
<AccountId>{{accountId}}</AccountId>
</GetAccountDetailsRequest>
</soap:Body>
</soap:Envelope>
Response (XML):
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<GetAccountDetailsResponse>
<Status>SUCCESS</Status>
<AccountDetails>
<AccountNumber>ACC-67890</AccountNumber>
<Balance>15000.50</Balance>
<Currency>USD</Currency>
<AccountType>PREMIUM</AccountType>
</AccountDetails>
<ErrorInfo>
<Code>0</Code>
<Message>Success</Message>
</ErrorInfo>
</GetAccountDetailsResponse>
</soap:Body>
</soap:Envelope>
Script for API 2:
// Strip XML declaration (required for DOMParser in browser)
response.response = response.response.replace(/^<\?xml.*?\?>/, "").trim();
// Parse XML response
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(response.response, "text/xml");
// Extract values from XML using DOM methods
const status = xmlDoc.getElementsByTagName("Status")[0].textContent;
const balance = xmlDoc.getElementsByTagName("Balance")[0].textContent;
const currency = xmlDoc.getElementsByTagName("Currency")[0].textContent;
const accountType = xmlDoc.getElementsByTagName("AccountType")[0].textContent;
const errorCode = xmlDoc.getElementsByTagName("Code")[0].textContent;
const errorMessage = xmlDoc.getElementsByTagName("Message")[0].textContent;
// Store extracted values in variables
variables.accountStatus = status;
variables.accountBalance = balance;
variables.accountCurrency = currency;
variables.accountType = accountType;
variables.errorCode = errorCode;
variables.errorMessage = errorMessage;
// Log extracted data
console.log("Account Status:", status);
console.log("Balance:", balance, currency);
console.log("Account Type:", accountType);
console.log("Error Code:", errorCode);
#
API 3: JSON Transaction Request
Endpoint: POST /api/transactions/create
Request Body (JSON):
{
"userId": "{{userId}}",
"accountId": "{{accountId}}",
"accountType": "{{accountType}}",
"currentBalance": "{{accountBalance}}",
"currency": "{{accountCurrency}}",
"transactionDetails": {
"amount": 100.00,
"type": "WITHDRAWAL",
"description": "ATM Withdrawal"
}
}
Response (JSON):
{
"success": true,
"transactionId": "TXN-99887766",
"newBalance": 14900.50,
"timestamp": "2024-01-15T10:30:00Z",
"message": "Transaction completed successfully"
}
Script for API 3:
// Extract transaction result
variables.transactionId = response.response.transactionId;
variables.newBalance = response.response.newBalance;
variables.transactionTimestamp = response.response.timestamp;
// Validate transaction
if (response.response.success) {
console.log("✓ Transaction successful:", variables.transactionId);
console.log("New balance:", variables.newBalance);
variables.transactionSuccess = true;
} else {
console.error("✗ Transaction failed");
variables.transactionSuccess = false;
}
// Log all variables for debugging
console.log("All variables:", variables);
#
Summary of the Flow
┌─────────────────────────────────────────────────────────────┐
│ API 1: JSON Login │
│ ↓ Response: userId, sessionToken, accountId │
│ ↓ Script: Extract and store in variables │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ API 2: XML Account Details │
│ ↓ Request: Uses {{userId}}, {{sessionToken}}, {{accountId}}│
│ ↓ Response: XML with balance, currency, accountType │
│ ↓ Script: Parse XML and extract fields to variables │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ API 3: JSON Transaction │
│ ↓ Request: Uses {{accountBalance}}, {{accountCurrency}} │
│ ↓ Response: Transaction confirmation │
│ ↓ Script: Validate and log results │
└─────────────────────────────────────────────────────────────┘
#
Advanced XML Parsing Techniques
#
Parsing XML Attributes
// Strip XML declaration
response.response = response.response.replace(/^<\?xml.*?\?>/, "").trim();
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(response.response, "text/xml");
// Get element with attributes
const accountElement = xmlDoc.getElementsByTagName("Account")[0];
// Extract attribute values
variables.accountId = accountElement.getAttribute("id");
variables.accountStatus = accountElement.getAttribute("status");
console.log("Account ID:", variables.accountId);
#
Parsing XML with Namespaces
response.response = response.response.replace(/^<\?xml.*?\?>/, "").trim();
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(response.response, "text/xml");
// Using getElementsByTagNameNS for namespaced elements
const namespace = "http://schemas.xmlsoap.org/soap/envelope/";
const bodyElement = xmlDoc.getElementsByTagNameNS(namespace, "Body")[0];
// Or use querySelector for more flexibility
const userId = xmlDoc.querySelector("UserId").textContent;
variables.userId = userId;
#
Handling Multiple Elements
response.response = response.response.replace(/^<\?xml.*?\?>/, "").trim();
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(response.response, "text/xml");
// Get all items
const items = xmlDoc.getElementsByTagName("Item");
// Extract first item
if (items.length > 0) {
variables.firstItemId = items[0].getElementsByTagName("Id")[0].textContent;
variables.firstItemName = items[0].getElementsByTagName("Name")[0].textContent;
}
// Count items
variables.itemCount = items.length;
console.log("Found", variables.itemCount, "items");
#
Error Handling for XML Parsing
try {
response.response = response.response.replace(/^<\?xml.*?\?>/, "").trim();
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(response.response, "text/xml");
// Check for parsing errors
const parserError = xmlDoc.getElementsByTagName("parsererror");
if (parserError.length > 0) {
console.error("XML parsing error:", parserError[0].textContent);
variables.xmlParseError = true;
} else {
// Extract data
variables.resultCode = xmlDoc.getElementsByTagName("Code")[0].textContent;
console.log("Successfully parsed XML, code:", variables.resultCode);
}
} catch (error) {
console.error("Error processing XML:", error.message);
variables.processingError = true;
}
#
Best Practices
#
1. Always Check for Existence
// ✓ Good - Safe access
if (response.response && response.response.user) {
variables.userId = response.response.user.id;
}
// ✗ Bad - May throw error if user is undefined
variables.userId = response.response.user.id;
#
2. Use Descriptive Variable Names
// ✓ Good - Clear and descriptive
variables.authToken = response.headers.authorization;
variables.customerId = response.response.customer.id;
// ✗ Bad - Unclear
variables.t = response.headers.authorization;
variables.id = response.response.customer.id;
#
3. Log Intermediate Values for Debugging
console.log("Response status:", response.statusCode);
console.log("User data:", response.response.user);
variables.userId = response.response.user.id;
console.log("Stored userId:", variables.userId);
#
4. Handle Errors Gracefully
if (response.statusCode === 200) {
variables.userId = response.response.id;
console.log("Success - User ID:", variables.userId);
} else {
console.error("API call failed with status:", response.statusCode);
variables.apiCallFailed = true;
}
#
5. Clean Up XML Before Parsing
// Always strip XML declaration for browser DOMParser
response.response = response.response.replace(/^<\?xml.*?\?>/, "").trim();
// Remove any BOM characters if present
response.response = response.response.replace(/^\uFEFF/, "");
#
6. Validate Extracted Data
// Extract with validation
const userId = xmlDoc.getElementsByTagName("UserId")[0];
if (userId && userId.textContent) {
variables.userId = userId.textContent;
console.log("User ID extracted:", variables.userId);
} else {
console.error("UserId not found in XML response");
variables.userId = null;
}
#
Debugging Tips
#
Check Variable Usage in Next API
When a variable isn't being replaced in the next API:
- Check the variable name - Ensure
{{variableName}}
matches exactly - Verify the script ran - Check console output in the script editor
- Confirm the value was set - Add
console.log("variables.userId =", variables.userId)
- Check for typos - Variable names are case-sensitive
#
Test Your Script
Use the Run Script button (▶️) in the Script Editor to test your script with mock data before running the full E2E workflow.
#
Using isDebug
for Testing
When you run your script using the Run Script button, a special isDebug
boolean variable is available. You can use this to inject custom response data for testing:
// Override response for debugging XML parsing
if (isDebug) {
// Inject a real XML response you want to test with
response.response = `<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<GetAccountDetailsResponse>
<Status>SUCCESS</Status>
<AccountDetails>
<AccountNumber>ACC-12345</AccountNumber>
<Balance>5000.00</Balance>
<Currency>USD</Currency>
</AccountDetails>
<ErrorInfo>
<Code>0</Code>
<Message>Success</Message>
</ErrorInfo>
</GetAccountDetailsResponse>
</soap:Body>
</soap:Envelope>`;
}
// Now test your parsing logic
response.response = response.response.replace(/^<\?xml.*?\?>/, "").trim();
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(response.response, "text/xml");
variables.accountNumber = xmlDoc.getElementsByTagName("AccountNumber")[0].textContent;
variables.balance = xmlDoc.getElementsByTagName("Balance")[0].textContent;
console.log("Extracted Account Number:", variables.accountNumber);
console.log("Extracted Balance:", variables.balance);
Use Cases for isDebug
:
- Test XML parsing with actual XML responses from your API
- Test complex JSON extraction logic with real response data
- Validate error handling with different response scenarios
- Debug script logic without running the entire E2E workflow
#
Request and Response Object Format
request
Object:
{
method: "POST", // HTTP method
url: "https://api.example.com/v1/users", // Full URL
query_params: { // Query parameters
"page": "1",
"limit": "10"
},
json_body: { // Request body (for JSON APIs)
"username": "john.doe",
"email": "john@example.com"
},
xml_body: "<xml>...</xml>", // Request body (for XML APIs)
headers: { // Request headers
"Content-Type": "application/json",
"Authorization": "Bearer token123",
"X-API-Key": "your-api-key"
},
path_params: { // Path parameters
"userId": "12345"
}
}
response
Object:
{
response: { // Response body (parsed JSON or raw XML string)
"success": true,
"data": {
"id": "USER-123",
"name": "John Doe"
}
},
headers: { // Response headers
"content-type": "application/json",
"x-request-id": "abc-123",
"date": "Mon, 15 Jan 2024 10:30:00 GMT"
},
statusCode: 200, // HTTP status code
testCaseId: "1232", // Internal test case ID
error: "No error", // Error message (if any)
elapsedTime: "631ms", // Time taken for the request
request: { // The actual request sent (same format as request object)
method: "POST",
url: "https://api.example.com/v1/users",
// ... (same structure as request object above)
}
}
Accessing Response Data:
// For JSON APIs
const userId = response.response.data.id;
const userName = response.response.data.name;
// For XML APIs (response.response will be a string)
const xmlString = response.response; // Raw XML string
// Access status code
if (response.statusCode === 200) {
console.log("Success!");
}
// Access headers
const requestId = response.headers["x-request-id"];
const contentType = response.headers["content-type"];
// Access timing information
console.log("Request took:", response.elapsedTime);
#
Limitations
- Scripts are executed in a browser environment (no Node.js APIs)
- No access to external libraries or imports
- Variables are scoped to the current test combination only
- Cannot make additional API calls from scripts
- File system access is not available
#
Examples Library
#
Random Test Data Generation
// Generate random ID
variables.randomId = "USER-" + Math.floor(Math.random() * 1000000);
// Generate random email
variables.randomEmail = "user" + Date.now() + "@test.com";
// Generate timestamp
variables.timestamp = new Date().toISOString();
#
Array Processing
// Get all IDs from an array
const ids = response.response.users.map(user => user.id);
variables.userIds = ids.join(",");
// Find specific item
const admin = response.response.users.find(user => user.role === "admin");
if (admin) {
variables.adminId = admin.id;
}
#
String Operations
// Extract part of a string
variables.domain = response.response.email.split("@")[1];
// Format data
variables.formattedDate = new Date(response.response.createdAt)
.toLocaleDateString("en-US");
// Clean data
variables.cleanedText = response.response.message.trim().toLowerCase();
#
Need Help?
If you encounter issues or have questions about E2E scripting:
- Use the Run Script button to test your script with mock data
- Check the Console Output panel for error messages
- Review the Script Usage Tips & Examples accordion in the Script Editor
- Verify that variable names match exactly between script and API request fields
Happy scripting! 🚀