The collection runner executes every request in a collection (or a single folder) in sequence, automatically resolving variables, running pre/post scripts, evaluating assertions, and streaming live progress to the UI. When the run finishes — whether by completion, failure, or cancellation — the results are persisted to SQLite and the app navigates to a detailed run report. This makes it straightforward to automate multi-step workflows such as authentication flows, CRUD test suites, or smoke tests against a staging environment.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/JonathanHerSa/xolo-api-hub/llms.txt
Use this file to discover all available pages before exploring further.
Starting a Run
Long-press a collection or folder
In the workspace explorer, long-press any collection or folder node. A context menu appears with collection actions.
Configure run options
The sheet exposes two main controls:
- Scope — choose to run the currently selected folder only, or the full collection from the root.
- Stop on Failure — when enabled (the default), the runner aborts all remaining steps as soon as one step fails an assertion or encounters an HTTP error. Disable this to collect results for every step regardless of failures.
Run Plan
Before any HTTP request is sent,RunPlanBuilder flattens the entire collection tree into an ordered List<RunPlanItem> using a depth-first traversal. The algorithm walks each level of the hierarchy as follows:
- Fetch all direct requests in the current collection node (in their saved order).
- Emit each request as a
RunPlanItemwith a monotonically increasingstepIndex. - Fetch all sub-collections (folders) of the current node.
- Recursively walk each sub-collection using the same logic.
RunPlanBuilder.build(collectionId) is the single public entry point — it returns the complete List<RunPlanItem> ready for CollectionRunnerService.execute().
Execution Flow
Build run plan
CollectionRunNotifier.startRun() calls RunPlanBuilder.build(collectionId) to produce the ordered step list. If the plan is empty, the run transitions to the error state immediately.Resolve base variables
The currently active environment’s variables are read via
resolvedVariablesProvider and copied into a mutable workingVars map. This map is shared across all steps and accumulates extracted values as the run progresses.Pre-scripts → auth resolution → HTTP send
For each
RunPlanItem, the runner:- Calls
ScriptExecutor.executePreScripts(req.preScriptsJson, workingVars)and merges the results intoworkingVars. - Resolves authentication via
AuthResolverService(inheriting collection-level auth if the request has none). - Passes the request to
RequestPipeline.send()— the same HTTP execution path used by the interactive composer — withworkingVarsas the variable context for URL, headers, params, and body resolution.
Evaluate assertions
AssertionEvaluator.evaluate() receives the HTTP response (statusCode, durationMs, responseData) plus the request’s List<AssertionRuleEntity>. It returns a List<AssertionResultEntity>, each with a passed flag and a human-readable message.Post-scripts → variable extraction
_applyPostScripts() runs JSONPath extraction rules against the response body, updates workingVars for subsequent steps, and persists each matched value to the active environment via XoloRepository.upsertVariable().Emit step result
A
RunStepResultEntity is emitted via the onStep callback. CollectionRunNotifier appends it to the steps list and updates currentStepIndex, causing CollectionRunScreen to re-render the progress bar and step list in real time.Stop-on-failure check
If
options.stopOnFailure is true and the step did not pass (either an assertion failed or output.error != null), an aborted flag is set. The main loop checks this flag at the top of each iteration and breaks before starting the next step.Run States
CollectionRunNotifier exposes run lifecycle through CollectionRunUiState:
| State | Meaning |
|---|---|
idle | No run has been started yet (initial state) |
running | A run is actively executing steps |
completed | All steps finished; check failedSteps for assertion failures |
cancelled | The user tapped Cancel, or a CancelToken was cancelled programmatically |
error | The run could not start (e.g., empty collection) or threw an unexpected exception |
CollectionRunState object always carries the latest List<RunStepResultEntity> so the UI can render partial results even while the run is in progress.
Cancellation
Tap the Cancel button in the app bar ofCollectionRunScreen while a run is active. This calls CollectionRunNotifier.cancelRun(), which invokes _cancelToken?.cancel('User cancelled') on the Dio CancelToken that was passed into CollectionRunnerService.execute().
Cancellation propagates immediately: if an HTTP request is in-flight, Dio cancels the underlying connection. RequestPipeline detects the DioException with CancelToken.isCancel(e) and returns a RequestOutput with cancelled: true. The runner loop breaks, sets runStatus to RunStatus.cancelled, and the partial run is persisted and reported.
Run Report
After the run transitions tocompleted or cancelled, the app navigates to RunReportScreen (route /runs/:runId). The report shows:
- Overall score —
passedSteps / totalStepsdisplayed as a large headline (e.g.,8 / 10 passed) - Failed and skipped counts — shown as a subtitle line
- Run timestamp — formatted start time
- Per-step cards — one expandable card per step, showing:
- ✅ / ❌ pass/fail icon
- Request name, HTTP method, resolved URL
- HTTP status code and response duration in milliseconds
- Per-assertion results with pass/fail icon and message
- Response body snippet (up to 500 characters)
- Re-run from failure — if any step failed, a Re-run from failure button appears at the bottom. It calls
CollectionRunNotifier.resumeRun()withfromStepIndexset to the first failed step’s index, re-using the current environment variables.
Persisted Runs
Every run and its step results are written to two SQLite tables managed by Drift:CollectionRuns — one row per run, including collectionId, environmentId, workspaceId, status, totalSteps, passedSteps, failedSteps, skippedSteps, startedAt, finishedAt, stopOnFailure, and variablesSnapshotJson.
RunStepResults — one row per step, including runId, stepIndex, name, method, url, statusCode, durationMs, passed, assertionResultsJson, errorMessage, and responseBodySnippet.
Past runs are accessible via collectionRunsHistoryProvider (a Riverpod StreamProvider) and individual run detail via runDetailProvider(runId).
Variable extraction (post-scripts) from one step flows into the next, enabling token-chaining across a full authentication + resource workflow. For example: step 1 POSTs to
/auth/login and extracts $.access_token → {{authToken}}; step 2 uses Authorization: Bearer {{authToken}} to create a resource and extracts $.id → {{resourceId}}; step 3 GETs /resources/{{resourceId}} and asserts the response matches the created data.