Every step in this walkthrough was generated by describing the scenario in plain English to AutomationCodeless's AI Test Step Assistant — not written by hand. The AI drafted the seven steps, chained the references between them, and picked reasonable field values; from there it was just a matter of reviewing the output and adjusting the parameter IDs and bucket names to match a real environment. Want to see it for yourself? Sign in at automationcodeless.com and you can execute these exact steps.
Most integration bugs live at the boundary between two systems — the place where a unit test can't see, because unit tests mock the boundary away instead of testing it. Add an AI step into the pipeline and you get a second kind of boundary: not just "did the two systems talk to each other correctly," but "did the model's output actually make sense, in a form the rest of the pipeline can use." This walkthrough builds one test case that exercises both — REST, AI classification, and AWS — end-to-end, using Parameters and a Variable to keep it from turning into a hardcoded mess.
The scenario
A support ticket comes in through a REST API. An OpenAI step classifies its severity. If the classification is critical, a downstream Lambda (outside the test — already deployed) writes an alert record to S3. We'll test that this entire chain actually works, not just that each piece works in isolation.
Step 1 — fetch a stored credential instead of hardcoding it
The ticketing API needs a bearer token. Rather than pasting it into every step that needs it, it's stored once as a Parameter and pulled in at runtime:
{
"step_id": 1,
"description": "Fetch the internal service token stored as a Parameter",
"step_type": "core",
"step_name": "get_parameter",
"parameter_id": 21
}
Step 2 — create the ticket
{
"step_id": 2,
"description": "Create a new support ticket",
"step_type": "rest",
"step_name": "post",
"value": {
"url": "https://api.example.com/tickets",
"headers": {
"Content-Type": "application/json",
"Authorization": "Bearer ${step[1].result_value}"
},
"requestBody": {
"customerId": 8842,
"subject": "Payment charged twice for order #5521",
"description": "I was charged $129.00 twice for the same order. Please refund the duplicate charge immediately, this is affecting my business."
}
}
}
Typical response:
{
"id": "TCK-90142",
"status": "open",
"createdAt": "2026-08-02T10:12:04Z"
}
Step 3 — store the ticket ID as a variable
The ticket ID gets referenced by several later steps. Rather than repeating ${step[2].result_value.id} everywhere, save it once as a named Variable:
{
"step_id": 3,
"description": "Store the new ticket ID for reuse in later steps",
"step_type": "core",
"step_name": "set_variable",
"variable_name": "ticket_id",
"value": "${step[2].result_value.id}",
"data_type": "string"
}
Step 4 — classify severity with OpenAI
{
"step_id": 4,
"description": "Classify the ticket's severity from its description",
"step_type": "open_ai",
"step_name": "gpt-4-turbo",
"parameter_id": 22,
"value": "Classify this support ticket's severity as exactly one word — low, medium, high, or critical: ${step[2].result_value.description}"
}
For this ticket, the model returns critical.
Step 5 — assert the AI actually returned something usable
AI output isn't strongly typed the way a database column is. Before anything downstream trusts it, assert it's actually one of the values the rest of the pipeline knows how to handle:
{
"step_id": 5,
"description": "Assert the AI returned a recognized severity level",
"step_type": "assert",
"step_name": "oneOf",
"value": "${step[4].result_value}",
"expected_value": ["low", "medium", "high", "critical"]
}
Step 6 — confirm the downstream alert actually fired
A critical classification should trigger a Lambda (already deployed, outside this test) that writes an alert record to S3. Check that it actually did:
{
"step_id": 6,
"description": "Confirm a critical-alert record was written for this ticket",
"step_type": "aws",
"step_name": "s3_get_object",
"value": {
"bucket": "support-critical-alerts",
"key": "${ticket_id}.json",
"region": "us-east-1",
"wait_for_seconds": 10
}
}
Step 7 — assert the alert points back to the right ticket
{
"step_id": 7,
"description": "Assert the alert record references the same ticket we created",
"step_type": "assert",
"step_name": "equal",
"value": "${step[6].result_value.ticketId}",
"expected_value": "${ticket_id}"
}
Why chain all of this into one test case
Each of these pieces could be tested in isolation — REST endpoint returns 200, OpenAI returns a string, S3 object exists. None of that proves the pipeline works. The bugs that actually reach production live in the connections: the Lambda trigger that silently stopped firing after a permissions change, the AI prompt that used to return "Critical" (capitalized) until a model update changed its formatting and broke every downstream string match, the ticket ID that gets truncated somewhere between systems. A single chained test case is what catches those — each step only passes if the step before it actually produced something usable.
Common pitfalls
- Don't skip validating AI output. Treat a model's response as untrusted input, the same as anything from the network — assert its shape and allowed values before anything downstream depends on it.
-
Use variables for anything referenced more than twice.
${step[2].result_value.id}works fine once; repeating it across five steps makes the test fragile to reorder and harder to read. Save it once as a variable instead. - Add a wait for asynchronous side effects. The S3 alert in step 6 is written by a Lambda triggered asynchronously — checking too early is a false failure, not a real one.
- Never hardcode credentials into a step. Pull them from Parameters, the same way step 1 does — it's the difference between updating one value when a token rotates and hunting through every test case that uses it.
Top comments (0)