Skip to Content

How to Configure Different Nodes in Business Workflow

Overview

Business Workflow Test Automation provides various node types, each serving a specific purpose in your workflow. This comprehensive guide explains how to configure each node type, including all parameters, scripts, and best practices.

Every node has three configuration tabs:

  • Parameters: Node-specific settings and inputs
  • Pre-Script: JavaScript executed before the node runs
  • Post-Script: JavaScript executed after the node completes

1. Simple Conditional

Purpose

Controls workflow branching based on a boolean condition. Routes execution to different paths based on whether a condition evaluates to true or false.

When to Use

  • Decision points in business logic
  • Validation checks before proceeding
  • Route workflows based on data values
  • Handle different scenarios (success vs. failure)
  • Check prerequisites before expensive operations

Parameters Tab

Condition Field:

A JavaScript expression that evaluates to true or false.

Syntax:

// Basic comparison inputs.userStatus === "active" // Numeric comparison inputs.orderTotal > 100 // Multiple conditions with AND inputs.isAdmin === true && inputs.accountAge > 30 // Multiple conditions with OR inputs.paymentStatus === "success" || inputs.paymentStatus === "pending" // Null/undefined checks inputs.userId !== null && typeof inputs.userId !== 'undefined' // String contains inputs.errorMessage.includes("timeout") // Array length inputs.cartItems.length > 0 // Negation !inputs.isGuest // Complex nested conditions (inputs.orderTotal > 100 && inputs.isPremium) || inputs.hasDiscount

Common Condition Examples:

Status Checks:

inputs.paymentStatus === "success" inputs.accountStatus === "verified" inputs.orderStatus === "completed"

Numeric Comparisons:

inputs.cartTotal > 50 inputs.retryCount < 3 inputs.stockLevel >= inputs.orderQuantity

Boolean Checks:

inputs.emailVerified === true inputs.hasActiveSubscription !inputs.isBlocked

Existence Checks:

typeof inputs.userId !== 'undefined' inputs.orderId !== null inputs.email && inputs.email.length > 0

String Matching:

inputs.userRole === "admin" || inputs.userRole === "moderator" inputs.country === "US" || inputs.country === "CA"

Pre-Script Tab

Optional. Use to prepare data before evaluating the condition.

Example:

// Normalize data before condition check if (typeof inputs.userStatus === 'string') { inputs.userStatus = inputs.userStatus.toLowerCase(); } // Log for debugging console.log("Checking condition with status: " + inputs.userStatus); // Set fallback values if (!inputs.retryCount) { inputs.retryCount = 0; }

Post-Script Tab

Optional. Use to log which path was taken or set additional variables based on the branch.

Example:

// Log which branch was taken if (inputs.conditionResult === true) { console.log("Condition passed - proceeding to success path"); } else { console.log("Condition failed - proceeding to failure path"); } // Set tracking variables inputs.lastConditionCheck = new Date().toISOString();

Connection Points

Output Ports:

  • True: Connect to nodes that execute when condition is true
  • False: Connect to nodes that execute when condition is false

Use Case Examples

Example 1: Payment Validation

// Condition inputs.paymentStatus === "success" && inputs.transactionId !== null // True → Create Order // False → Send Payment Failure Email

Example 2: Stock Check

// Condition inputs.availableStock >= inputs.requestedQuantity // True → Reserve Inventory // False → Send Out of Stock Notification

Example 3: User Role Check

// Condition inputs.userRole === "admin" || inputs.userRole === "supervisor" // True → Allow Action // False → Show Access Denied

Example 4: Retry Logic

// Condition inputs.retryCount < inputs.maxRetries && inputs.lastAttemptFailed // True → Retry Operation // False → Send Failure Notification

Best Practices

Do:

  • Keep conditions simple and readable
  • Use meaningful variable names
  • Test both true and false paths
  • Add comments for complex conditions
  • Log condition evaluation for debugging

Don’t:

  • Create overly complex nested conditions
  • Use undefined variables (check existence first)
  • Forget to handle both branches
  • Mix business logic with condition evaluation
  • Use side effects in conditions

2. Event Conditional

Purpose

Similar to Simple Conditional but adds timeout functionality. Waits for a condition to become true, with a maximum wait time. Useful for asynchronous operations and approval workflows.

When to Use

  • Approval workflows with timeout deadlines
  • Waiting for external events (webhooks, callbacks)
  • Polling for status changes with maximum wait
  • Asynchronous operation completion
  • Time-sensitive decisions

Parameters Tab

Timeout:

Maximum time to wait for the condition to become true.

Timeout Value:

  • Numeric value (integer)
  • Example: 5, 30, 120

Timeout Unit:

  • Milliseconds: Very short waits (1000 = 1 second)
  • Seconds: Short waits (60 = 1 minute)
  • Minutes: Medium waits (30 = 30 minutes)
  • Hours: Long waits (24 = 1 day)
  • Days: Very long waits (7 = 1 week)
  • Months: Extremely long waits (3 = 3 months)

Examples:

5 seconds 2 minutes 1 hour 2 days 1 month

Condition Field:

Same as Simple Conditional - JavaScript boolean expression.

inputs.approvalStatus === "approved" inputs.paymentProcessed === true inputs.webhookReceived === true

How It Works

  1. Check Condition: Evaluates the condition
  2. If True: Immediately proceeds on True path
  3. If False: Waits and rechecks periodically
  4. If Becomes True: Proceeds on True path
  5. If Timeout Expires: Proceeds on False path

Pre-Script Tab

Example:

// Initialize tracking inputs.conditionCheckStartTime = new Date().toISOString(); inputs.checkCount = 0; console.log("Starting event conditional with timeout: " + inputs.timeoutValue + " " + inputs.timeoutUnit);

Post-Script Tab

Example:

// Log outcome if (inputs.conditionMetBeforeTimeout) { console.log("Condition met within timeout period"); const elapsed = (new Date() - new Date(inputs.conditionCheckStartTime)) / 1000; console.log("Time elapsed: " + elapsed + " seconds"); } else { console.log("Timeout expired - condition not met"); }

Connection Points

Output Ports:

  • True: Condition became true within timeout
  • False: Timeout expired without condition becoming true

Use Case Examples

Example 1: Approval Workflow

// Timeout: 2 days // Condition: inputs.approvalStatus === "approved" // True → Approval received → Process request // False → Timeout expired → Send reminder or escalate

Example 2: Payment Processing

// Timeout: 5 minutes // Condition: inputs.paymentStatus === "completed" // True → Payment completed → Create order // False → Payment timeout → Cancel transaction

Example 3: Email Verification

// Timeout: 24 hours // Condition: inputs.emailVerified === true // True → Email verified → Activate account // False → Verification timeout → Send reminder

Example 4: Webhook Callback

// Timeout: 30 seconds // Condition: inputs.webhookCallbackReceived === true // True → Callback received → Process data // False → Callback timeout → Use fallback method

Best Practices

Do:

  • Set realistic timeouts for the operation
  • Consider using shorter timeouts for testing
  • Handle timeout scenarios gracefully
  • Log timeout events for monitoring
  • Provide user feedback on delays

Don’t:

  • Set extremely long timeouts without reason
  • Ignore timeout scenarios
  • Use event conditionals for instant checks (use Simple Conditional)
  • Forget to test timeout path
  • Block critical workflows with long waits

3. Signal

Purpose

Sends a signal that can be used to coordinate between workflows or trigger events. Useful for orchestrating complex, multi-workflow processes.

When to Use

  • Coordinating parallel workflows
  • Triggering dependent processes
  • Synchronization points in distributed workflows
  • Event notifications between systems
  • Workflow orchestration

Parameters Tab

Signal Name:

A unique identifier for the signal.

Naming Convention:

  • Use descriptive names
  • lowercase_with_underscores or camelCase
  • Indicate the event being signaled

Examples:

order_created payment_completed inventory_reserved email_sent user_verified approval_granted process_started task_completed

Signal Value (Optional):

Can include data with the signal using variables:

{ "orderId": "${inputs.orderId}", "status": "completed", "timestamp": "${inputs.completionTime}" }

Pre-Script Tab

Example:

// Prepare signal data inputs.signalData = { orderId: inputs.orderId, userId: inputs.userId, status: "completed", timestamp: new Date().toISOString() }; console.log("Sending signal: order_completed for order " + inputs.orderId);

Post-Script Tab

Example:

// Confirm signal sent console.log("Signal sent successfully: " + inputs.signalName); inputs.signalSentAt = new Date().toISOString();

How Signals Work

Sending Signals:

  • Signal node executes when reached in workflow
  • Signal is broadcast with the specified name
  • Any workflows waiting for this signal are notified

Receiving Signals (in other workflows):

  • Use “Wait for Signal” functionality
  • Specify signal name to wait for
  • Workflow pauses until signal received

Use Case Examples

Example 1: Order Processing Coordination

Workflow A - Order Creation:

HTTP Request: Create Order ↓ Signal: Send "order_created"

Workflow B - Fulfillment (separate workflow):

Wait for Signal: "order_created" ↓ HTTP Request: Start Fulfillment Process

Example 2: Multi-Stage Approval

Workflow A - First Approval:

Compliance Approval: Manager Approval ↓ Simple Conditional: Approved? True ↓ Signal: Send "manager_approved"

Workflow B - Second Approval:

Wait for Signal: "manager_approved" ↓ Compliance Approval: Director Approval

Example 3: Parallel Processing

Workflow A - Payment Processing:

HTTP Request: Process Payment ↓ Signal: Send "payment_completed"

Workflows B and C (both waiting):

Wait for Signal: "payment_completed" ↓ Workflow B: Send Receipt Email Workflow C: Update Accounting System

Best Practices

Do:

  • Use descriptive, unique signal names
  • Document what each signal means
  • Include relevant data with signals
  • Test signal coordination thoroughly
  • Log signal sending/receiving

Don’t:

  • Use generic signal names (“signal1”, “event”)
  • Forget to handle cases where signal might not arrive
  • Create circular signal dependencies
  • Overuse signals when simpler approaches work
  • Forget to clean up or reset signals

4. Wait Activity

Purpose

Pauses workflow execution for a specified duration. Useful for rate limiting, simulating delays, or allowing time for external processes to complete.

When to Use

  • Rate limiting between API calls
  • Simulating realistic delays (think time, processing time)
  • Allowing asynchronous operations to complete
  • Throttling requests to avoid overwhelming services
  • Testing timeout scenarios
  • Waiting for email delivery before checking

Parameters Tab

Duration:

Time to wait, specified in milliseconds.

Conversion Guide:

1 second = 1,000 milliseconds 5 seconds = 5,000 milliseconds 1 minute = 60,000 milliseconds 5 minutes = 300,000 milliseconds 1 hour = 3,600,000 milliseconds

Can use variables:

${inputs.waitTime} ${inputs.delayInMs}

Examples:

1000 // 1 second 5000 // 5 seconds 30000 // 30 seconds 60000 // 1 minute 300000 // 5 minutes

Pre-Script Tab

Example:

// Calculate dynamic wait time if (inputs.retryCount > 0) { // Exponential backoff: 1s, 2s, 4s, 8s... inputs.waitTime = Math.pow(2, inputs.retryCount) * 1000; } else { inputs.waitTime = 1000; // Initial wait } console.log("Waiting for " + (inputs.waitTime / 1000) + " seconds");

Post-Script Tab

Example:

// Log wait completion console.log("Wait completed"); inputs.lastWaitCompletedAt = new Date().toISOString();

Use Case Examples

Example 1: Rate Limiting API Calls

Loop Over Items: Process 100 records Inside loop: HTTP Request: Update record Wait Activity: 100ms (rate limit to 10 requests/sec)

Example 2: Retry with Backoff

HTTP Request: Call External Service Simple Conditional: Request failed? True ↓ Wait Activity: 5000ms (5 seconds) Loop back to retry

Example 3: Email Delivery Wait

SES Email: Send verification email Wait Activity: 3000ms (allow email to send) HTTP Request: Check email delivery status

Example 4: Simulating User Think Time

UI Test: User fills form Wait Activity: 2000ms (user reviews before submitting) UI Test: User submits form

Example 5: Asynchronous Processing

HTTP Request: Trigger async job Wait Activity: 10000ms (10 seconds) HTTP Request: Check job status Loop if not complete

Dynamic Wait Calculation

Pre-Script Examples:

Linear Backoff:

// Wait increases linearly: 1s, 2s, 3s, 4s... inputs.waitTime = (inputs.retryCount + 1) * 1000;

Exponential Backoff:

// Wait doubles each time: 1s, 2s, 4s, 8s... inputs.waitTime = Math.pow(2, inputs.retryCount) * 1000;

Random Jitter:

// Add randomness to avoid thundering herd const baseWait = 5000; const jitter = Math.random() * 2000; // 0-2 seconds inputs.waitTime = baseWait + jitter;

Based on Response Time:

// Wait proportional to last response time if (inputs.lastResponseTime) { inputs.waitTime = inputs.lastResponseTime * 2; // Wait 2x response time } else { inputs.waitTime = 1000; // Default }

Best Practices

Do:

  • Use appropriate wait times for the operation
  • Consider shorter waits for testing
  • Add logging to track wait times
  • Use dynamic waits when appropriate
  • Document why waiting is necessary

Don’t:

  • Use waits as a substitute for proper status checking
  • Set unnecessarily long waits
  • Wait in tight loops without exit conditions
  • Forget to test the scenario without waits
  • Use waits to hide timing bugs

5. HTTP Request

Purpose

Makes HTTP API calls to external services or your own backend. The most commonly used node for testing APIs and integrating with services.

When to Use

  • Calling REST APIs
  • Creating resources (POST)
  • Retrieving data (GET)
  • Updating resources (PUT/PATCH)
  • Deleting resources (DELETE)
  • Triggering webhooks
  • Integrating with third-party services

Parameters Tab

Host:

The base URL of the API.

Format:

https://api.example.com http://localhost:3000 https://staging-api.company.com

Can use variable:

${inputs.apiHost} ${inputs.environment === "prod" ? "https://api.example.com" : "https://staging-api.example.com"}

Endpoint Path:

The specific API endpoint path (without the host).

Format:

/users /users/123 /orders /products/search /auth/login

Can include variables:

/users/${inputs.userId} /orders/${inputs.orderId}/items /products/category/${inputs.categoryId}

Method:

HTTP method to use.

Options:

  • GET: Retrieve data
  • POST: Create resources
  • PUT: Replace resources
  • PATCH: Update resources partially
  • DELETE: Delete resources
  • HEAD: Get headers only
  • OPTIONS: Get allowed methods

Authentication Type:

How to authenticate the request.

Options:

1. Predefined Auth:

  • Use saved authentication configuration
  • Select from dropdown of configured auth profiles
  • Keeps credentials centralized and secure

2. Header Auth:

  • Add authentication in request headers
  • Common for API keys, custom tokens
  • Example:
    Key: Authorization Value: Bearer ${inputs.authToken} Key: X-API-Key Value: ${inputs.apiKey}

3. Query Auth:

  • Add authentication in query parameters
  • Less secure, visible in URLs
  • Example:
    Key: api_key Value: ${inputs.apiKey} Key: token Value: ${inputs.accessToken}

4. Bearer Token:

  • Special case of header auth
  • Automatically adds: Authorization: Bearer <token>
  • Simply provide the token value

Query Params (Optional):

URL query parameters (the part after ? in URLs).

Format:

Key: page Value: 1 Key: limit Value: 20 Key: sort Value: name Key: order Value: asc

Can use variables:

Key: userId Value: ${inputs.userId} Key: status Value: ${inputs.filterStatus} Key: from Value: ${inputs.startDate}

Results in URL:

/products?page=1&limit=20&sort=name&order=asc

Headers (Optional):

HTTP headers to send with the request.

Common Headers:

Content-Type: application/json Accept: application/json Authorization: Bearer ${inputs.token} X-Request-ID: ${inputs.requestId} User-Agent: E2E-Test-Automation/1.0

Body (Optional):

Request payload for POST, PUT, PATCH methods.

Format: JSON

Example:

{ "userId": "${inputs.userId}", "action": "updateProfile", "data": { "email": "${inputs.newEmail}", "firstName": "${inputs.firstName}", "lastName": "${inputs.lastName}" } }

Simple Example:

{ "email": "user@example.com", "password": "securepass123" }

Complex Example:

{ "order": { "userId": "${inputs.userId}", "items": [ { "productId": "${inputs.productId}", "quantity": ${inputs.quantity}, "price": ${inputs.price} } ], "shipping": { "address": "${inputs.shippingAddress}", "method": "${inputs.shippingMethod}" }, "payment": { "method": "credit_card", "token": "${inputs.paymentToken}" } } }

Pre-Script Tab

Prepare request data before the API call.

Example:

// Build complex request body inputs.requestPayload = { userId: inputs.userId, timestamp: new Date().toISOString(), action: "purchase", items: inputs.cartItems.map(item => ({ id: item.productId, quantity: item.quantity, price: item.price })) }; // Set dynamic headers inputs.requestId = "REQ-" + Date.now(); // Log request details console.log("Making API call to: " + inputs.apiHost + inputs.endpoint); console.log("Method: " + inputs.method); console.log("Request body: " + JSON.stringify(inputs.requestPayload));

Post-Script Tab

Process the API response.

Example:

// Parse response const response = JSON.parse(outputs.responseBody); // Check status if (outputs.statusCode === 200 || outputs.statusCode === 201) { // Extract data from successful response inputs.userId = response.data.id; inputs.userName = response.data.name; inputs.userEmail = response.data.email; console.log("API call successful"); console.log("User ID: " + inputs.userId); } else if (outputs.statusCode === 404) { console.error("Resource not found"); inputs.resourceNotFound = true; } else if (outputs.statusCode >= 500) { console.error("Server error: " + outputs.statusCode); throw new Error("API server error"); } else { console.error("API call failed with status: " + outputs.statusCode); console.error("Response: " + outputs.responseBody); throw new Error("API call failed"); } // Extract specific fields if (response.pagination) { inputs.totalPages = response.pagination.totalPages; inputs.currentPage = response.pagination.currentPage; } // Track response time inputs.lastApiResponseTime = outputs.responseTime;

Available Outputs

After the HTTP Request completes, these outputs are available:

outputs.statusCode:

  • HTTP status code (200, 404, 500, etc.)

outputs.responseBody:

  • Response body as string (usually JSON)
  • Parse with JSON.parse(outputs.responseBody)

outputs.responseHeaders:

  • Response headers as object

outputs.responseTime:

  • Time taken for the request in milliseconds

outputs.requestUrl:

  • Full URL that was called

Use Case Examples

Example 1: User Login

// Parameters Host: https://api.example.com Path: /auth/login Method: POST Body: { "email": "${inputs.userEmail}", "password": "${inputs.userPassword}" } // Post-Script const response = JSON.parse(outputs.responseBody); if (outputs.statusCode === 200) { inputs.authToken = response.token; inputs.userId = response.userId; inputs.loginSuccessful = true; }

Example 2: Get User Profile

// Parameters Host: ${inputs.apiHost} Path: /users/${inputs.userId} Method: GET Headers: Authorization: Bearer ${inputs.authToken} // Post-Script const user = JSON.parse(outputs.responseBody); inputs.userName = user.name; inputs.userEmail = user.email; inputs.accountStatus = user.status;

Example 3: Create Order

// Parameters Host: https://api.example.com Path: /orders Method: POST Headers: Content-Type: application/json Authorization: Bearer ${inputs.authToken} Body: { "userId": "${inputs.userId}", "items": ${JSON.stringify(inputs.cartItems)}, "total": ${inputs.orderTotal} } // Post-Script const order = JSON.parse(outputs.responseBody); if (outputs.statusCode === 201) { inputs.orderId = order.orderId; inputs.orderNumber = order.orderNumber; inputs.orderCreatedAt = order.createdAt; }

Example 4: Retry Logic

// Pre-Script if (!inputs.retryCount) { inputs.retryCount = 0; } // Post-Script if (outputs.statusCode >= 500 || outputs.statusCode === 408) { // Server error or timeout inputs.retryCount++; if (inputs.retryCount < 3) { console.log("Request failed, retry " + inputs.retryCount); inputs.shouldRetry = true; } else { throw new Error("Max retries exceeded"); } } else { inputs.shouldRetry = false; }

Best Practices

Do:

  • Use meaningful variable names
  • Validate response status codes
  • Parse JSON safely with try-catch
  • Log important request/response details
  • Handle different status codes appropriately
  • Use variables for dynamic values
  • Set appropriate headers
  • Document expected responses

Don’t:

  • Hardcode sensitive credentials
  • Ignore error status codes
  • Assume response format without checking
  • Make requests without authentication when required
  • Forget to handle timeout scenarios
  • Use GET requests with body (not standard)
  • Expose API keys in logs

6. Compliance Approval

Purpose

Sends an approval request email and waits for approval response. Useful for workflows requiring human approval with timeout handling.

When to Use

  • Multi-stage approval workflows
  • Compliance review processes
  • Budget approval workflows
  • Change request approvals
  • Document review and sign-off

Parameters Tab

Timeout:

Maximum time to wait for approval.

Format: Similar to Event Conditional

  • Value: Number
  • Unit: Seconds, Minutes, Hours, Days

Examples:

2 days 24 hours 3 days 1 week (7 days)

To Email:

Recipient’s email address who will approve/reject.

Format:

approver@example.com ${inputs.managerEmail} ${inputs.approverEmail}

Can be multiple (comma-separated):

manager@example.com,director@example.com

Email Subject:

Subject line of the approval email.

Example:

Approval Required: Order #${inputs.orderNumber} Budget Approval Request - $${inputs.amount} Document Review: ${inputs.documentName}

Email Body:

Content of the approval email. Can be plain text or HTML.

Plain Text Example:

Hello, Please review and approve the following request: Order Number: ${inputs.orderNumber} Customer: ${inputs.customerName} Amount: $${inputs.orderTotal} Click below to approve or reject: [Approve] [Reject] This request will expire in 2 days.

HTML Example:

<html> <body> <h2>Approval Required</h2> <p>Hello ${inputs.approverName},</p> <p>Please review the following purchase order:</p> <table border="1" cellpadding="10"> <tr><td><strong>Order Number:</strong></td><td>${inputs.orderNumber}</td></tr> <tr><td><strong>Customer:</strong></td><td>${inputs.customerName}</td></tr> <tr><td><strong>Amount:</strong></td><td>$${inputs.orderTotal}</td></tr> <tr><td><strong>Date:</strong></td><td>${inputs.orderDate}</td></tr> </table> <p> <a href="${inputs.approveUrl}" style="background-color: green; color: white; padding: 10px 20px; text-decoration: none;">Approve</a> <a href="${inputs.rejectUrl}" style="background-color: red; color: white; padding: 10px 20px; text-decoration: none; margin-left: 10px;">Reject</a> </p> <p><small>This request expires in ${inputs.timeoutDays} days.</small></p> </body> </html>

Pre-Script Tab

Example:

// Prepare approval email data inputs.approverName = inputs.managerName; inputs.timeoutDays = 2; // Generate approval URLs const approvalToken = "APPROVE-" + inputs.orderId + "-" + Date.now(); inputs.approveUrl = "https://example.com/approve?token=" + approvalToken; inputs.rejectUrl = "https://example.com/reject?token=" + approvalToken; // Store for tracking inputs.approvalRequestSentAt = new Date().toISOString(); inputs.approvalToken = approvalToken; console.log("Sending approval request to: " + inputs.approverEmail);

Post-Script Tab

Example:

// Check approval result if (outputs.approved === true) { console.log("Request approved by: " + inputs.approverEmail); inputs.approvalStatus = "approved"; inputs.approvedAt = new Date().toISOString(); inputs.approvedBy = inputs.approverEmail; } else if (outputs.timeout === true) { console.log("Approval timeout - no response within " + inputs.timeoutDays + " days"); inputs.approvalStatus = "timeout"; } else { console.log("Request rejected by: " + inputs.approverEmail); inputs.approvalStatus = "rejected"; inputs.rejectedAt = new Date().toISOString(); inputs.rejectionReason = outputs.rejectionReason || "Not provided"; }

Connection Points

Output Ports:

  • Approved: Approval was granted
  • Rejected/Timeout: Approval was denied or timeout expired

Use Case Examples

Example 1: Purchase Order Approval

// First level approval Compliance Approval: Manager approval (timeout: 2 days) Approved ↓ Compliance Approval: Director approval (timeout: 3 days) Approved ↓ HTTP Request: Process order

Example 2: Budget Request

Subject: Budget Approval - $${inputs.requestedAmount} Body: Department: ${inputs.department} Purpose: ${inputs.purpose} Amount: $${inputs.requestedAmount} Please review and approve.

Example 3: Document Review

Subject: Document Review Required: ${inputs.documentName} Body: <p>Please review the attached document and provide approval.</p> <p>Document: ${inputs.documentName}</p> <p>Version: ${inputs.version}</p> <p>Submitted by: ${inputs.submitter}</p>

Best Practices

Do:

  • Set realistic timeout periods
  • Provide clear approval instructions
  • Include all necessary information in email
  • Handle timeout scenarios gracefully
  • Send reminders before timeout (in separate workflow)
  • Log approval decisions
  • Make approve/reject links clear

Don’t:

  • Set extremely short timeouts
  • Forget to handle timeout path
  • Include sensitive data in emails
  • Make approval process confusing
  • Forget to track who approved/rejected
  • Use Compliance Approval for non-approval workflows

7. External TC Execution

Purpose

Executes external test cases via webhook. Integrates with external testing systems or triggers remote processes.

When to Use

  • Integrating with external test systems
  • Triggering tests in other tools
  • Calling third-party validation services
  • Executing tests in other environments
  • Coordinating with CI/CD pipelines

Parameters Tab

Webhook CURL:

The complete cURL command for the webhook (optional if providing individual fields).

Example:

curl -X POST https://external-system.com/api/execute-test \ -H "Content-Type: application/json" \ -H "Authorization: Bearer token123" \ -d '{"testId": "TC-001", "environment": "staging"}'

Host:

Base URL of the external system.

Example:

https://external-test-system.com https://ci.company.com ${inputs.externalSystemUrl}

Method:

HTTP method for the webhook.

Options: GET, POST, PUT, PATCH, DELETE

Endpoint:

The webhook endpoint path.

Example:

/api/execute-test /webhooks/trigger-test /tests/${inputs.testId}/run

Authentication Type:

Same options as HTTP Request:

  • Predefined Auth
  • Header Auth
  • Query Auth
  • Bearer Token

Query Params:

URL parameters for the webhook.

Example:

testId: ${inputs.externalTestId} environment: staging async: true

Headers:

HTTP headers for the webhook.

Example:

Content-Type: application/json Authorization: Bearer ${inputs.externalApiToken} X-Callback-URL: ${inputs.callbackUrl}

Body:

Request payload for POST/PUT methods.

Example:

{ "testCaseId": "${inputs.testCaseId}", "environment": "${inputs.environment}", "parameters": { "userId": "${inputs.userId}", "scenario": "${inputs.scenario}" }, "callback": { "url": "${inputs.callbackUrl}", "method": "POST" } }

Pre-Script Tab

Example:

// Prepare webhook request inputs.callbackUrl = "https://e2e-automation.com/webhooks/test-complete?id=" + inputs.workflowId; inputs.externalTestId = "EXT-" + Date.now(); // Set timeout for external test inputs.externalTestTimeout = 300000; // 5 minutes console.log("Triggering external test: " + inputs.testCaseId); console.log("Callback URL: " + inputs.callbackUrl);

Post-Script Tab

Example:

// Process webhook response const response = JSON.parse(outputs.responseBody); if (outputs.statusCode === 200 || outputs.statusCode === 202) { inputs.externalTestTriggered = true; inputs.externalTestJobId = response.jobId; inputs.externalTestStatus = response.status || "pending"; console.log("External test triggered successfully"); console.log("Job ID: " + inputs.externalTestJobId); } else { console.error("Failed to trigger external test"); console.error("Status: " + outputs.statusCode); console.error("Response: " + outputs.responseBody); throw new Error("External test execution failed"); } // Extract callback data if needed if (response.estimatedDuration) { inputs.estimatedWaitTime = response.estimatedDuration; }

Use Case Examples

Example 1: Trigger Selenium Test

{ "testSuite": "regression", "browser": "chrome", "environment": "staging", "testCases": ["login", "checkout", "payment"], "callback": { "url": "${inputs.callbackUrl}", "on": ["complete", "failure"] } }

Example 2: Execute Performance Test

{ "testType": "load", "duration": 300, "virtualUsers": 100, "rampUp": 60, "targetUrl": "${inputs.targetUrl}", "scenarios": ["browse", "search", "purchase"] }

Example 3: Mobile App Test

{ "platform": "iOS", "device": "iPhone 14", "appVersion": "${inputs.appVersion}", "testSuite": "smoke", "notifyOnComplete": true }

Best Practices

Do:

  • Provide callback URLs for async operations
  • Set appropriate timeouts
  • Handle webhook failures gracefully
  • Log webhook triggers
  • Validate webhook responses
  • Document webhook contracts
  • Test webhook integration

Don’t:

  • Assume synchronous responses
  • Ignore webhook failures
  • Forget to handle timeouts
  • Hardcode credentials
  • Skip error handling
  • Use webhooks for simple operations

8. SES Email

Purpose

Sends emails using AWS Simple Email Service (SES). Useful for notifications, confirmations, and alerts in workflows.

When to Use

  • Order confirmations
  • Registration emails
  • Notification emails
  • Status updates
  • Error alerts
  • Reports and summaries

Parameters Tab

SES Email Node Notification:

AWS SES configuration (usually pre-configured in E2E Test Automation).

AWS Email Service:

AWS account credentials for SES.

Source Email:

From email address (must be verified in AWS SES).

Format:

noreply@example.com notifications@company.com support@example.com ${inputs.senderEmail}

To Email:

Recipient email address(es).

Single recipient:

user@example.com ${inputs.userEmail}

Multiple recipients (comma-separated):

user1@example.com,user2@example.com,user3@example.com ${inputs.userEmail},${inputs.managerEmail}

Subject:

Email subject line.

Example:

Order Confirmation - #${inputs.orderNumber} Welcome to ${inputs.companyName}! Password Reset Request Your Report is Ready

Body:

Email content (plain text or HTML).

Plain Text Example:

Hello ${inputs.userName}, Thank you for your order! Order Number: ${inputs.orderNumber} Order Date: ${inputs.orderDate} Total Amount: $${inputs.orderTotal} Your order will be shipped to: ${inputs.shippingAddress} Track your order: ${inputs.trackingUrl} Thank you for shopping with us! Best regards, The Team

HTML Example:

<!DOCTYPE html> <html> <head> <style> body { font-family: Arial, sans-serif; } .header { background-color: #4CAF50; color: white; padding: 20px; text-align: center; } .content { padding: 20px; } .footer { background-color: #f1f1f1; padding: 10px; text-align: center; font-size: 12px; } .button { background-color: #4CAF50; color: white; padding: 10px 20px; text-decoration: none; border-radius: 5px; } table { border-collapse: collapse; width: 100%; } th, td { border: 1px solid #ddd; padding: 8px; text-align: left; } </style> </head> <body> <div class="header"> <h1>Order Confirmation</h1> </div> <div class="content"> <p>Hello ${inputs.userName},</p> <p>Thank you for your order! Your purchase has been confirmed.</p> <h3>Order Details</h3> <table> <tr> <th>Order Number</th> <td>${inputs.orderNumber}</td> </tr> <tr> <th>Order Date</th> <td>${inputs.orderDate}</td> </tr> <tr> <th>Total Amount</th> <td>$${inputs.orderTotal}</td> </tr> </table> <h3>Items Ordered</h3> <ul> ${inputs.orderItems} </ul> <h3>Shipping Information</h3> <p>${inputs.shippingAddress}</p> <p>Estimated Delivery: ${inputs.estimatedDelivery}</p> <p style="text-align: center; margin-top: 30px;"> <a href="${inputs.trackingUrl}" class="button">Track Your Order</a> </p> </div> <div class="footer"> <p>Thank you for shopping with us!</p> <p>If you have any questions, contact us at support@example.com</p> </div> </body> </html>

Pre-Script Tab

Example:

// Build dynamic email content inputs.orderItems = inputs.cartItems.map(item => `<li>${item.name} - Quantity: ${item.quantity} - $${item.price}</li>` ).join(''); inputs.orderTotal = inputs.cartItems.reduce((sum, item) => sum + (item.price * item.quantity), 0 ).toFixed(2); inputs.orderDate = new Date().toLocaleDateString(); // Generate tracking URL inputs.trackingUrl = "https://example.com/track?order=" + inputs.orderNumber; console.log("Sending order confirmation email to: " + inputs.userEmail);

Post-Script Tab

Example:

// Log email sent if (outputs.emailSent === true) { console.log("Email sent successfully to: " + inputs.userEmail); inputs.emailSentAt = new Date().toISOString(); inputs.emailStatus = "sent"; } else { console.error("Failed to send email"); console.error("Error: " + outputs.error); inputs.emailStatus = "failed"; } // Track for future reference inputs.lastEmailType = "order_confirmation"; inputs.lastEmailRecipient = inputs.userEmail;

Email Templates

Welcome Email:

<h1>Welcome to ${inputs.companyName}!</h1> <p>Hi ${inputs.firstName},</p> <p>Thank you for joining us. We're excited to have you!</p> <p><a href="${inputs.verificationUrl}">Verify your email address</a></p>

Password Reset:

<h2>Password Reset Request</h2> <p>Hello ${inputs.userName},</p> <p>We received a request to reset your password.</p> <p><a href="${inputs.resetUrl}">Reset your password</a></p> <p>This link expires in 24 hours.</p> <p>If you didn't request this, please ignore this email.</p>

Order Shipped:

<h2>Your Order Has Shipped!</h2> <p>Hi ${inputs.userName},</p> <p>Good news! Your order #${inputs.orderNumber} has been shipped.</p> <p>Tracking Number: ${inputs.trackingNumber}</p> <p><a href="${inputs.trackingUrl}">Track your shipment</a></p> <p>Estimated Delivery: ${inputs.estimatedDelivery}</p>

Payment Confirmation:

<h2>Payment Received</h2> <p>Dear ${inputs.customerName},</p> <p>We have received your payment of $${inputs.paymentAmount}.</p> <p>Transaction ID: ${inputs.transactionId}</p> <p>Payment Method: ${inputs.paymentMethod}</p> <p>Date: ${inputs.paymentDate}</p>

Use Case Examples

Example 1: Order Workflow

HTTP Request: Create Order ↓ SES Email: Send order confirmation ↓ Wait Activity: 1 day ↓ SES Email: Send shipping update

Example 2: Registration Workflow

HTTP Request: Create user account ↓ SES Email: Send welcome email with verification link ↓ Event Conditional: Wait for email verification (24 hours) Verified ↓ SES Email: Send getting started guide

Example 3: Error Notification

HTTP Request: Critical operation ↓ Simple Conditional: Operation failed? True ↓ SES Email: Send error alert to admin

Best Practices

Do:

  • Use verified sender addresses
  • Test email templates before production
  • Include unsubscribe links if applicable
  • Use responsive HTML for mobile
  • Personalize with variables
  • Keep subject lines clear and concise
  • Provide plain text alternative
  • Log email sending for tracking

Don’t:

  • Send emails without user consent
  • Include sensitive data in plain text
  • Forget to test email rendering
  • Use all caps in subject lines
  • Send too many emails
  • Ignore email bounce notifications
  • Use generic “noreply” without alternative contact

9. UI Test

Purpose

Executes a UI automation test scenario within the workflow. Integrates UI testing with API and workflow testing.

When to Use

  • Testing complete user journeys
  • Validating UI after API changes
  • End-to-end business process testing
  • User acceptance testing
  • Integration testing with UI components

Parameters Tab

Test Suite:

Select the UI test suite containing your UI scenarios.

Dropdown Selection:

  • Lists all available UI test suites
  • Choose the suite containing the test you want to run

Test Scenario:

Select the specific UI test scenario to execute.

Dropdown Selection:

  • Lists scenarios in the selected test suite
  • Choose the specific test to run

Test Dataset:

Select dataset variables for the UI test (if needed).

Optional:

  • Provides variable values for the UI test
  • Allows parameterized testing
  • Can use different data sets for same scenario

Framework:

Testing framework used for UI tests.

Usually auto-selected:

  • Playwright
  • Selenium
  • Cypress
  • (Framework is typically configured at suite level)

Pre-Script Tab

Example:

// Prepare data for UI test inputs.testUsername = inputs.userEmail; inputs.testPassword = inputs.userPassword; inputs.testEnvironment = "staging"; // Set UI test specific variables inputs.browserType = "chrome"; inputs.headless = false; // Set to true for faster execution console.log("Starting UI test: " + inputs.scenarioName); console.log("Test user: " + inputs.testUsername);

Post-Script Tab

Example:

// Process UI test results if (outputs.testStatus === "passed") { console.log("UI test passed successfully"); inputs.uiTestPassed = true; // Extract data from UI test if (outputs.extractedData) { inputs.userId = outputs.extractedData.userId; inputs.sessionToken = outputs.extractedData.sessionToken; } } else { console.error("UI test failed"); console.error("Failure reason: " + outputs.failureReason); console.error("Screenshot: " + outputs.screenshotUrl); inputs.uiTestPassed = false; // Optionally stop workflow on UI test failure throw new Error("UI test failed: " + outputs.failureReason); } // Log test duration console.log("UI test duration: " + outputs.testDuration + "ms");

Available Outputs

outputs.testStatus:

  • Status of the test: “passed”, “failed”, “skipped”

outputs.testDuration:

  • Time taken to execute the test in milliseconds

outputs.failureReason:

  • Reason for failure if test failed

outputs.screenshotUrl:

  • URL to screenshot if test failed

outputs.extractedData:

  • Any data extracted during UI test execution

Use Case Examples

Example 1: Login and API Validation

UI Test: User login ↓ Post-Script: Extract session token ↓ HTTP Request: Validate session via API ↓ HTTP Request: Get user profile using extracted token

Example 2: Complete Purchase Flow

UI Test: Add product to cart ↓ HTTP Request: Verify cart via API ↓ UI Test: Proceed to checkout ↓ HTTP Request: Create order via API ↓ SES Email: Send order confirmation ↓ UI Test: Verify order confirmation page

Example 3: Registration with Backend Verification

UI Test: User registration form ↓ Post-Script: Extract registered email ↓ Database: Verify user created in DB ↓ HTTP Request: Check user status via API ↓ SES Email: Send welcome email ↓ UI Test: Verify welcome page

Example 4: Conditional UI Testing

HTTP Request: Get user role ↓ Simple Conditional: Is admin? ├─ True → UI Test: Admin dashboard test └─ False → UI Test: Regular user dashboard test

Integration Patterns

Pattern 1: UI → API

UI action creates data ↓ API verifies data was created correctly

Pattern 2: API → UI

API creates/updates data ↓ UI test verifies data appears correctly

Pattern 3: UI → API → UI

UI action ↓ API validates backend state ↓ UI verifies confirmation

Best Practices

Do:

  • Keep UI tests focused and specific
  • Extract data from UI tests for API calls
  • Verify UI changes with API calls
  • Handle UI test failures gracefully
  • Use appropriate wait times
  • Test realistic user scenarios
  • Combine with API testing for full coverage

Don’t:

  • Run long UI tests in tight loops
  • Ignore UI test failures
  • Forget to extract necessary data
  • Skip API validation after UI actions
  • Use UI tests for simple API validation
  • Create overly complex UI workflows
  • Forget to handle async operations

10. Database

Purpose

Executes MongoDB database queries directly in the workflow. Useful for data validation, setup, and teardown.

When to Use

  • Validating data was stored correctly
  • Setting up test data
  • Cleaning up after tests
  • Checking database state
  • Direct data manipulation
  • Complex queries not available via API

Parameters Tab

Query:

MongoDB query in standard MongoDB syntax.

Query Types:

Find (Read):

// Find single document db.users.findOne({ email: "${inputs.userEmail}" }) // Find multiple documents db.users.find({ status: "active" }) // Find with projection (specific fields) db.users.find( { role: "admin" }, { name: 1, email: 1, _id: 0 } ) // Find with sorting db.orders.find({ userId: "${inputs.userId}" }).sort({ createdAt: -1 }) // Find with limit db.products.find({ category: "electronics" }).limit(10)

Insert (Create):

// Insert single document db.users.insertOne({ email: "${inputs.userEmail}", name: "${inputs.userName}", status: "active", createdAt: new Date(), role: "user" }) // Insert multiple documents db.orders.insertMany([ { userId: "${inputs.userId}", total: ${inputs.orderTotal}, status: "pending" }, { userId: "${inputs.userId}", total: 50.00, status: "completed" } ])

Update (Modify):

// Update single document db.users.updateOne( { email: "${inputs.userEmail}" }, { $set: { status: "verified", verifiedAt: new Date() } } ) // Update multiple documents db.orders.updateMany( { status: "pending", createdAt: { $lt: new Date(Date.now() - 7*24*60*60*1000) } }, { $set: { status: "expired" } } ) // Increment value db.users.updateOne( { userId: "${inputs.userId}" }, { $inc: { loginCount: 1 } } ) // Push to array db.users.updateOne( { userId: "${inputs.userId}" }, { $push: { orders: "${inputs.orderId}" } } )

Delete (Remove):

// Delete single document db.users.deleteOne({ email: "${inputs.userEmail}" }) // Delete multiple documents db.orders.deleteMany({ status: "test", createdAt: { $lt: new Date(Date.now() - 30*24*60*60*1000) } })

Aggregate (Complex Queries):

// Group and count db.orders.aggregate([ { $match: { status: "completed" } }, { $group: { _id: "$userId", totalOrders: { $sum: 1 }, totalSpent: { $sum: "$total" } } } ]) // Lookup (join) db.orders.aggregate([ { $match: { orderId: "${inputs.orderId}" } }, { $lookup: { from: "users", localField: "userId", foreignField: "userId", as: "userDetails" } } ])

Pre-Script Tab

Example:

// Prepare query parameters inputs.queryEmail = inputs.userEmail.toLowerCase(); inputs.currentDate = new Date().toISOString(); // Dynamic query building if (inputs.includeInactive) { inputs.statusFilter = { $in: ["active", "inactive"] }; } else { inputs.statusFilter = "active"; } console.log("Executing database query"); console.log("Collection: users"); console.log("Filter email: " + inputs.queryEmail);

Post-Script Tab

Example:

// Process query results try { const result = JSON.parse(outputs.queryResult); if (Array.isArray(result)) { // Multiple documents console.log("Found " + result.length + " documents"); if (result.length > 0) { inputs.userExists = true; inputs.userId = result[0]._id || result[0].userId; inputs.userStatus = result[0].status; inputs.userRole = result[0].role; } else { inputs.userExists = false; } } else if (result && typeof result === 'object') { // Single document console.log("Found document"); inputs.userExists = true; inputs.userId = result._id || result.userId; inputs.userStatus = result.status; inputs.userRole = result.role; } else { // No results console.log("No documents found"); inputs.userExists = false; } } catch (error) { console.error("Error parsing database results: " + error); throw error; } // Validate data if (inputs.userExists && inputs.userStatus !== "active") { console.warn("User found but status is: " + inputs.userStatus); }

Use Case Examples

Example 1: Verify User Created

// After API call to create user Database: Find user Query: db.users.findOne({ email: "${inputs.userEmail}" }) Post-Script: if (result exists) { inputs.userCreated = true; inputs.dbUserId = result._id; } else { throw new Error("User not created in database"); }

Example 2: Clean Up Test Data

// Before starting test Database: Delete test users Query: db.users.deleteMany({ email: { $regex: "^test.*@example.com$" } }) Post-Script: console.log("Deleted " + outputs.deletedCount + " test users");

Example 3: Validate Order Data

// After order creation Database: Get order with items Query: db.orders.aggregate([ { $match: { orderId: "${inputs.orderId}" } }, { $lookup: { from: "orderItems", localField: "orderId", foreignField: "orderId", as: "items" } } ]) Post-Script: const order = result[0]; inputs.orderItemCount = order.items.length; inputs.orderTotalFromDB = order.total; if (inputs.orderTotalFromDB !== inputs.expectedTotal) { throw new Error("Order total mismatch"); }

Example 4: Setup Test Data

// Before test workflow Database: Create test user Query: db.users.insertOne({ email: "test.user@example.com", name: "Test User", status: "active", role: "user", createdAt: new Date() }) Post-Script: inputs.testUserId = outputs.insertedId; console.log("Test user created with ID: " + inputs.testUserId);

Best Practices

Do:

  • Use variables for dynamic values
  • Validate query results in post-script
  • Handle empty results gracefully
  • Use appropriate indexes for performance
  • Clean up test data after tests
  • Log query execution
  • Use specific queries (avoid find all)
  • Parse results safely with try-catch

Don’t:

  • Use database queries for simple API validations
  • Modify production data in tests
  • Create queries that return huge datasets
  • Forget to handle null/undefined results
  • Use database queries in tight loops
  • Skip connection error handling
  • Perform complex operations better suited for application code

11. Loop Over Items

Purpose

Repeats a set of actions multiple times. Useful for iteration, retries, and batch processing.

When to Use

  • Retry logic (attempt operation multiple times)
  • Batch processing (process multiple items)
  • Pagination (iterate through pages)
  • Rate limiting (controlled repetition)
  • Performance testing (repeat load)

Parameters Tab

Iteration Count:

Number of times to repeat the loop.

Format:

  • Integer value
  • Example: 3, 10, 100

Can use variable:

${inputs.maxRetries} ${inputs.pageCount} ${inputs.numberOfRecords}

How It Works

  1. Loop starts with index 0
  2. Executes all connected nodes inside loop
  3. Increments index
  4. Repeats until iteration count reached
  5. Proceeds to next node after loop

Loop Index:

  • Available as inputs.loopIndex
  • Starts at 0
  • Increments each iteration

Pre-Script Tab

Example:

// Setup before loop inputs.successCount = 0; inputs.failureCount = 0; inputs.results = []; console.log("Starting loop with " + inputs.iterationCount + " iterations");

Post-Script Tab

Example:

// After each iteration inputs.results.push({ iteration: inputs.loopIndex, success: inputs.lastOperationSuccess, timestamp: new Date().toISOString() }); if (inputs.lastOperationSuccess) { inputs.successCount++; } else { inputs.failureCount++; } console.log("Completed iteration " + (inputs.loopIndex + 1) + " of " + inputs.iterationCount);

Loop Control

Break Early (in node inside loop):

// In post-script of node inside loop if (inputs.desiredConditionMet) { inputs.breakLoop = true; // Signal to exit loop }

Skip Iteration:

// In post-script of node inside loop if (inputs.shouldSkip) { console.log("Skipping iteration " + inputs.loopIndex); return; // Continue to next iteration }

Use Case Examples

Example 1: Retry with Backoff

Loop Over Items: 3 iterations Inside loop: HTTP Request: Call flaky API Simple Conditional: Request successful? True → Break loop (success) False → Wait Activity: (iteration × 1000)ms → Continue

Example 2: Batch Processing

HTTP Request: Get total page count Post-Script: inputs.pageCount = response.totalPages Loop Over Items: ${inputs.pageCount} iterations Inside loop: HTTP Request: Get page ${inputs.loopIndex + 1} Post-Script: Process page data Database: Store processed data Wait Activity: 100ms (rate limiting)

Example 3: Load Testing

Loop Over Items: 100 iterations Inside loop: HTTP Request: Create order Wait Activity: Random delay (100-500ms) Post-Script: Track response time

Example 4: Multi-Item Processing

HTTP Request: Get items to process Post-Script: inputs.itemCount = response.items.length Loop Over Items: ${inputs.itemCount} iterations Inside loop: Pre-Script: inputs.currentItem = inputs.items[inputs.loopIndex] HTTP Request: Process item ${inputs.currentItem.id} Database: Update item status

Pre-Script Inside Loop

Example:

// Executed before each iteration console.log("=== Iteration " + (inputs.loopIndex + 1) + " ==="); // Access current item from array if (inputs.itemsToProcess && inputs.itemsToProcess.length > inputs.loopIndex) { inputs.currentItem = inputs.itemsToProcess[inputs.loopIndex]; console.log("Processing item: " + inputs.currentItem.id); } // Dynamic configuration based on iteration if (inputs.loopIndex === 0) { console.log("First iteration - using default settings"); } else { console.log("Retry attempt " + inputs.loopIndex); inputs.timeout = inputs.timeout * 2; // Exponential backoff }

Post-Script Inside Loop

Example:

// Executed after each iteration console.log("Iteration " + (inputs.loopIndex + 1) + " completed"); // Track iteration results if (!inputs.iterationResults) { inputs.iterationResults = []; } inputs.iterationResults.push({ index: inputs.loopIndex, success: inputs.operationSuccess, duration: inputs.operationDuration, data: inputs.operationData }); // Check if we should exit loop early if (inputs.operationSuccess && inputs.exitOnFirstSuccess) { console.log("Success achieved - exiting loop early"); inputs.breakLoop = true; } // Handle failures if (!inputs.operationSuccess) { inputs.consecutiveFailures = (inputs.consecutiveFailures || 0) + 1; if (inputs.consecutiveFailures >= 3) { console.log("Too many consecutive failures - exiting loop"); throw new Error("Loop failed after " + inputs.consecutiveFailures + " consecutive failures"); } } else { inputs.consecutiveFailures = 0; // Reset on success }

Advanced Loop Patterns

Pattern 1: Retry Until Success

Loop: 5 iterations HTTP Request: Operation Conditional: Success? True → Set breakLoop = true → Exit False → Wait → Continue

Pattern 2: Process with Batch Size

Pre-Script: inputs.batchSize = 10; inputs.totalItems = 100; inputs.batches = Math.ceil(inputs.totalItems / inputs.batchSize); Loop: ${inputs.batches} iterations Pre-Script: const start = inputs.loopIndex * inputs.batchSize; const end = start + inputs.batchSize; inputs.currentBatch = inputs.allItems.slice(start, end); Process current batch

Pattern 3: Rate-Limited API Calls

Loop: ${inputs.requestCount} iterations HTTP Request: Call API Wait Activity: 100ms (10 requests per second limit) Post-Script: if (outputs.statusCode === 429) { // Rate limited console.log("Rate limited - increasing delay"); inputs.delayBetweenRequests = inputs.delayBetweenRequests * 2; }

Best Practices

Do:

  • Set reasonable iteration counts
  • Add exit conditions for early termination
  • Log each iteration for debugging
  • Track results for later analysis
  • Handle failures gracefully
  • Use appropriate delays in loops
  • Consider memory for large loops

Don’t:

  • Create infinite or extremely long loops
  • Forget to add delays in API call loops
  • Ignore loop failures
  • Process huge datasets in memory
  • Use loops when better alternatives exist
  • Forget to clean up after loop
  • Skip error handling in loops

Summary

Business Workflow Test Automation provides 11 powerful node types:

  1. Simple Conditional - Basic branching logic
  2. Event Conditional - Time-based conditional logic
  3. Signal - Workflow coordination
  4. Wait Activity - Execution delays
  5. HTTP Request - API calls
  6. Compliance Approval - Approval emails with timeout
  7. External TC Execution - External test webhooks
  8. SES Email - Email notifications
  9. UI Test - UI automation integration
  10. Database - MongoDB queries
  11. Loop Over Items - Iteration and retries

Every node supports:

  • Parameters: Node-specific configuration
  • Pre-Script: Setup before execution
  • Post-Script: Processing after execution
  • Variables: Data flow between nodes

Master these nodes to create sophisticated, powerful business workflow tests that validate your complete end-to-end processes.