# E2E API Pilot Cases - Create-First Pattern

## Overview

This directory contains 10 pilot test cases that demonstrate the **Create-First** approach for E2E API testing. Unlike the original test cases that rely on preset seed data IDs (like `{seed_Account_0}`, `{seed_Lead_0}`), these cases:

1. **Create** the data they need via API in the `setup` section
2. **Verify** the created data using `query_after` assertions
3. **Teardown** (delete) the created data after the test

## Why Create-First?

- **No seed data dependency**: Tests can run against any fresh database
- **Isolation**: Each test creates and cleans up its own data
- **Reproducibility**: No conflicts from residual data
- **Production-safe**: Can run against production-like environments

## Test Cases

| Case ID | Scene | Object | Description |
|---------|-------|--------|-------------|
| LEAD-001 | lead | Lead | Create Lead with Status=OPEN, verify Date_Status_Changed__c is NULL |
| LEAD-002 | lead | Lead | Create Lead with Status=WORKING, verify Date_Status_Changed__c is NOT NULL |
| QUOTE-001 | quote | Quote | Create Quote, verify Status field has default value |
| QUOTE-002 | quote | Quote | Create Quote, verify NetFees and Discount auto-populate |
| OPP-001 | opportunity | Opportunity | Create Opportunity with AccountId, verify Amount and StageName |
| OPP-002 | opportunity | Opportunity | Create Opportunity, verify AccountId linkage |
| ACCT-001 | account | Account | Create Account, verify Name and Industry |
| ACCT-002 | account | Account | Create Account with Website, verify all fields |
| CONTACT-001 | contact | CampaignMember | Update CampaignMember Status=Responded, verify HasResponded=true |
| CONTACT-002 | contact | CampaignMember | Create CampaignMember, verify Contact name is displayed |

## Running the Pilot Cases

```bash
cd ~/github/bingwang-MetaDrivenPlatform4AI/MetaDrivenPlatform4AI/tests/e2e-api

# Run all pilot cases
python3 pilot_runner.py

# Run a specific case
python3 pilot_runner.py --case LEAD-001

# With custom environment
NEXUSCRM_URL=http://127.0.0.1:3001 \
NEXUSCRM_USERNAME=admin@test.com \
NEXUSCRM_PASSWORD=your_password \
python3 pilot_runner.py
```

## Case Structure

Each case follows this pattern:

```json
{
  "id": "LEAD-001",
  "name": "Create Lead Status=OPEN",
  "object": "Lead",
  "method": "POST",
  "endpoint": "/services/data/v63.0/sobjects/Lead",
  "payload": {
    "LastName": "LEAD001_E2E_{timestamp}",
    "Company": "Test Company LEAD001",
    "Status": "OPEN"
  },
  "expects": { "status_code": 201 },
  "extract": {
    "id": "{result_id}",
    "name": "{result_LastName}"
  },
  "query_after": {
    "object": "Lead",
    "id": "{result_id}",
    "assertions": [
      { "field": "Status", "operator": "eq", "value": "OPEN" },
      { "field": "Date_Status_Changed__c", "operator": "is_null", "value": true }
    ]
  },
  "teardown": {
    "method": "DELETE",
    "endpoint": "/services/data/v63.0/sobjects/Lead/{result_id}"
  },
  "setup": [...],  // For cases with dependencies
  "priority": "P0",
  "scene": "lead"
}
```

### Key Fields

| Field | Description |
|-------|-------------|
| `setup` | List of API calls to create prerequisite data (Account → Opportunity → Quote) |
| `extract` | Map response fields to variables for use in subsequent steps |
| `query_after` | Verify created record has expected field values |
| `teardown` | Delete created records (runs even if test fails) |

### Variable Substitution

- `{timestamp}` - Replaced with run timestamp (e.g., `20260416120000`)
- `{result_id}` - ID returned from the main API call
- `{result_FieldName}` - Field value from the API response
- `{variable_name}` - Runtime variable set via `id_var` in setup steps

## Assertion Operators

| Operator | Description |
|----------|-------------|
| `eq` | Equals |
| `ne` | Not equals |
| `contains` | String contains |
| `not_contains` | String does not contain |
| `is_null` | Is null/empty |
| `is_not_null` | Is not null/empty |
| `gt` | Greater than |

## Dependency Chains

Some cases have setup dependencies:

```
ACCOUNT → OPPORTUNITY → QUOTE
    ↓
OPPORTUNITY
```

- **QUOTE-001, QUOTE-002**: Need Account + Opportunity created first
- **OPP-001, OPP-002**: Need Account created first
- **CONTACT-001, CONTACT-002**: Need Campaign + Contact created first (via setup)

## Differences from Original Cases

| Original Pattern | Create-First Pattern |
|-----------------|---------------------|
| Relies on `{seed_Account_0}` | Uses `{timestamp}` for unique names |
| Seed data loaded via `_setup_seed_data()` | Each test creates its own data |
| Tests may conflict with each other | Each test is isolated |
| Cannot run on fresh database | Works on any environment |
| Hardcoded IDs | Dynamic ID extraction via `extract` |

## Report Output

Run results are saved to `pilot-report-{timestamp}.json`:

```json
{
  "timestamp": "20260416120000",
  "summary": {
    "total": 10,
    "passed": 8,
    "failed": 2,
    "errors": 0,
    "pass_rate": "80.0%"
  },
  "results": [...]
}
```
