# 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:

  1. API request is made with any variables/data you've configured
  2. Response is received from the server
  3. Assertions are processed (if any)
  4. 📍 Your script executes here with access to request/response
  5. Variables are stored and available for subsequent API calls

# Available Objects in Scripts

Every script has access to four key objects:

Object Description Example Usage
request Current API request object request.url, request.json_body
response Complete response object including headers, status, body response.response, response.statusCode, response.headers
variables Object to store temporary variables for later API calls variables.userId = "123"
console For debugging output (log, error, warn) console.log("User ID:", userId)

# 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:

  1. Check the variable name - Ensure {{variableName}} matches exactly
  2. Verify the script ran - Check console output in the script editor
  3. Confirm the value was set - Add console.log("variables.userId =", variables.userId)
  4. 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:

  1. Use the Run Script button to test your script with mock data
  2. Check the Console Output panel for error messages
  3. Review the Script Usage Tips & Examples accordion in the Script Editor
  4. Verify that variable names match exactly between script and API request fields

Happy scripting! 🚀