Scenario Testing

Create reusable multi-endpoint test flows

Scenarios allow you to create reusable test workflows that execute multiple API endpoints in sequence or parallel. Perfect for testing complete user flows like registration, authentication, and data operations.

Availability

Scenario testing is currently available only in the Go implementation. Support for other languages is planned.

What are Scenarios?

A scenario is a collection of API requests that can be:

  • Sequential: Execute one after another
  • Parallel: Execute simultaneously (planned feature)
  • Dependent: Use data from previous requests
  • Reusable: Save and run anytime
  • Shareable: Export/import as JSON

Use Cases

1. User Registration Flow

{
  "name": "User Registration Flow",
  "description": "Complete user registration and verification",
  "execution_mode": "sequential",
  "requests": [
    {
      "name": "Register User",
      "method": "POST",
      "path": "/auth/register",
      "body": {
        "email": "test@example.com",
        "password": "secret123",
        "name": "Test User"
      },
      "extract": {
        "user_id": "$.data.id",
        "verification_token": "$.data.verification_token"
      }
    },
    {
      "name": "Verify Email",
      "method": "POST",
      "path": "/auth/verify",
      "body": {
        "token": "{{verification_token}}"
      }
    },
    {
      "name": "Get Profile",
      "method": "GET",
      "path": "/users/{{user_id}}"
    }
  ]
}

2. E-commerce Purchase Flow

{
  "name": "Purchase Flow",
  "execution_mode": "sequential",
  "requests": [
    {
      "name": "Login",
      "method": "POST",
      "path": "/auth/login",
      "extract": {
        "auth_token": "$.token"
      }
    },
    {
      "name": "Add to Cart",
      "method": "POST",
      "path": "/cart/items",
      "headers": {
        "Authorization": "Bearer {{auth_token}}"
      },
      "body": {
        "product_id": 123,
        "quantity": 2
      }
    },
    {
      "name": "Checkout",
      "method": "POST",
      "path": "/orders",
      "headers": {
        "Authorization": "Bearer {{auth_token}}"
      }
    }
  ]
}

3. CRUD Operations

{
  "name": "Post CRUD",
  "execution_mode": "sequential",
  "requests": [
    {
      "name": "Create Post",
      "method": "POST",
      "path": "/posts",
      "body": {
        "title": "Test Post",
        "content": "Content here"
      },
      "extract": {
        "post_id": "$.id"
      }
    },
    {
      "name": "Get Post",
      "method": "GET",
      "path": "/posts/{{post_id}}"
    },
    {
      "name": "Update Post",
      "method": "PUT",
      "path": "/posts/{{post_id}}",
      "body": {
        "title": "Updated Title"
      }
    },
    {
      "name": "Delete Post",
      "method": "DELETE",
      "path": "/posts/{{post_id}}"
    }
  ]
}

Creating Scenarios

Via UI

  1. Navigate to Scenarios in the Bytedocs UI
  2. Click "New Scenario"
  3. Add details:
    • Name
    • Description
    • Execution mode
  4. Add requests:
    • Select endpoint
    • Configure parameters
    • Set up variable extraction
  5. Save & Execute

Via API

curl -X POST http://localhost:8080/docs/scenarios \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My Scenario",
    "description": "Test scenario",
    "execution_mode": "sequential",
    "requests": [...]
  }'

Via JSON Import

# Export scenarios
curl http://localhost:8080/docs/scenarios/export > scenarios.json

# Import scenarios
curl -X POST http://localhost:8080/docs/scenarios/import \
  -H "Content-Type: application/json" \
  -d @scenarios.json

Scenario Configuration

Basic Structure

type Scenario struct {
    ID          string                 `json:"id"`
    Name        string                 `json:"name"`
    Description string                 `json:"description"`
    Requests    []ScenarioRequest      `json:"requests"`
    Config      ScenarioConfig         `json:"config"`
    CreatedAt   time.Time              `json:"created_at"`
    UpdatedAt   time.Time              `json:"updated_at"`
}

Scenario Config

type ScenarioConfig struct {
    ExecutionMode  string            `json:"execution_mode"`  // "sequential" or "parallel"
    ContinueOnFail bool              `json:"continue_on_fail"`
    Timeout        int               `json:"timeout"`         // seconds
    BaseURL        string            `json:"base_url"`
    Auth           AuthConfig        `json:"auth"`
    Environment    map[string]string `json:"environment"`     // Variables
}

Request Structure

type ScenarioRequest struct {
    Name       string            `json:"name"`
    Method     string            `json:"method"`
    Path       string            `json:"path"`
    Headers    map[string]string `json:"headers"`
    Body       interface{}       `json:"body"`
    Extract    map[string]string `json:"extract"`    // JSONPath → variable
    Assert     []Assertion       `json:"assert"`     // Response assertions
    DependsOn  []string          `json:"depends_on"` // Request dependencies
}

Variable Extraction

Extract values from responses to use in subsequent requests:

JSONPath Syntax

{
  "extract": {
    "user_id": "$.data.id",
    "email": "$.data.email",
    "token": "$.token",
    "first_item": "$.items[0].id",
    "all_ids": "$.items[*].id"
  }
}

Using Extracted Variables

Use {{variable_name}} syntax in subsequent requests:

{
  "path": "/users/{{user_id}}",
  "headers": {
    "Authorization": "Bearer {{token}}"
  },
  "body": {
    "email": "{{email}}"
  }
}

Assertions

Validate response data:

{
  "assert": [
    {
      "type": "status",
      "expected": 200
    },
    {
      "type": "json_path",
      "path": "$.data.id",
      "operator": "exists"
    },
    {
      "type": "json_path",
      "path": "$.data.email",
      "operator": "equals",
      "expected": "test@example.com"
    },
    {
      "type": "json_path",
      "path": "$.items.length",
      "operator": "greater_than",
      "expected": 0
    },
    {
      "type": "response_time",
      "operator": "less_than",
      "expected": 500
    }
  ]
}

Assertion Types

TypeDescriptionExample
statusHTTP status code{"type": "status", "expected": 200}
json_pathJSONPath expression{"type": "json_path", "path": "$.id"}
headerResponse header{"type": "header", "name": "Content-Type"}
response_timeResponse duration{"type": "response_time", "operator": "less_than", "expected": 500}
body_containsBody contains text{"type": "body_contains", "expected": "success"}

Operators

  • equals
  • not_equals
  • greater_than
  • less_than
  • contains
  • not_contains
  • exists
  • not_exists
  • matches (regex)

Execution Modes

Sequential (Default)

Requests execute one after another:

Request 1 → Request 2 → Request 3 → Complete

Use when:

  • Requests depend on each other
  • Order matters
  • Need to extract data between requests

Parallel (Coming Soon)

Requests execute simultaneously:

Request 1 ↘
Request 2 → Complete
Request 3 ↗

Use when:

  • Requests are independent
  • Want faster execution
  • Testing concurrent load

Error Handling

Continue on Failure

{
  "config": {
    "continue_on_fail": true
  }
}
  • true: Continue executing remaining requests
  • false: Stop on first failure (default)

Timeout

{
  "config": {
    "timeout": 30
  }
}

Set maximum execution time in seconds.

Authentication

Bearer Token

{
  "config": {
    "auth": {
      "type": "bearer",
      "token": "your-token-here"
    }
  }
}

Basic Auth

{
  "config": {
    "auth": {
      "type": "basic",
      "username": "admin",
      "password": "secret"
    }
  }
}

API Key

{
  "config": {
    "auth": {
      "type": "api_key",
      "key": "your-key",
      "header": "X-API-Key"
    }
  }
}

Dynamic (from previous request)

{
  "requests": [
    {
      "name": "Login",
      "method": "POST",
      "path": "/auth/login",
      "extract": {
        "auth_token": "$.token"
      }
    },
    {
      "name": "Protected Endpoint",
      "headers": {
        "Authorization": "Bearer {{auth_token}}"
      }
    }
  ]
}

Environment Variables

Set reusable variables:

{
  "config": {
    "environment": {
      "BASE_URL": "https://api.example.com",
      "API_VERSION": "v1",
      "TEST_USER_ID": "123"
    }
  },
  "requests": [
    {
      "path": "/{{API_VERSION}}/users/{{TEST_USER_ID}}"
    }
  ]
}

API Endpoints

List Scenarios

GET /docs/scenarios

Get Scenario

GET /docs/scenarios/:id

Create Scenario

POST /docs/scenarios
Content-Type: application/json

{
  "name": "My Scenario",
  "requests": [...]
}

Update Scenario

PUT /docs/scenarios/:id
Content-Type: application/json

{
  "name": "Updated Name",
  "requests": [...]
}

Delete Scenario

DELETE /docs/scenarios/:id

Execute Scenario

POST /docs/scenarios/:id/execute

Response:

{
  "scenario_id": "abc123",
  "status": "success",
  "total_requests": 3,
  "successful": 3,
  "failed": 0,
  "duration_ms": 1234,
  "results": [
    {
      "request_name": "Create User",
      "status": 201,
      "duration_ms": 234,
      "success": true,
      "extracted_vars": {
        "user_id": "123"
      }
    }
  ]
}

Export Scenarios

GET /docs/scenarios/export

Returns all scenarios as JSON.

Import Scenarios

POST /docs/scenarios/import
Content-Type: application/json

[
  {"name": "Scenario 1", ...},
  {"name": "Scenario 2", ...}
]

Best Practices

1. Descriptive Names

{
  "name": "User Registration and Email Verification",
  "description": "Tests the complete user onboarding flow including email verification and profile setup"
}

2. Meaningful Request Names

{
  "requests": [
    {"name": "Create User Account"},
    {"name": "Send Verification Email"},
    {"name": "Verify Email Token"},
    {"name": "Complete Profile Setup"}
  ]
}

3. Use Assertions

{
  "assert": [
    {"type": "status", "expected": 201},
    {"type": "json_path", "path": "$.id", "operator": "exists"},
    {"type": "response_time", "operator": "less_than", "expected": 1000}
  ]
}

4. Extract Reusable Data

{
  "extract": {
    "user_id": "$.data.id",
    "auth_token": "$.token",
    "refresh_token": "$.refresh_token"
  }
}

5. Handle Errors Gracefully

{
  "config": {
    "continue_on_fail": false,
    "timeout": 30
  }
}

Troubleshooting

Scenario Execution Fails

Check:

  1. Base URL is correct
  2. Authentication is valid
  3. Variable extraction paths are correct
  4. Request bodies are valid JSON

Variables Not Resolved

Ensure:

  1. Variable was extracted in previous request
  2. JSONPath expression is correct
  3. Response actually contains the data
  4. Using correct syntax: {{variable_name}}

Timeout Errors

Solutions:

  1. Increase timeout in config
  2. Check endpoint performance
  3. Verify network connectivity
  4. Run requests individually to identify slow endpoint

What's Next?