Skip to main content

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.

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.

Starting a Run

1

Long-press a collection or folder

In the workspace explorer, long-press any collection or folder node. A context menu appears with collection actions.
2

Tap Run

Tap Run from the context menu. A bottom sheet slides up showing run configuration options.
3

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.
4

Tap Run to start

Confirm to start. The app navigates to CollectionRunScreen, which displays a live progress bar and a scrolling list of step results as each request completes.

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:
  1. Fetch all direct requests in the current collection node (in their saved order).
  2. Emit each request as a RunPlanItem with a monotonically increasing stepIndex.
  3. Fetch all sub-collections (folders) of the current node.
  4. Recursively walk each sub-collection using the same logic.
This means requests at the top level of a folder always execute before any nested sub-folder’s requests. The flattened result is a deterministic, zero-indexed list:
/// A single request step in a collection run plan.
class RunPlanItem {
  final int stepIndex;          // 0-based position in the run
  final SavedRequestEntity request;
  final int? collectionId;
}
RunPlanBuilder.build(collectionId) is the single public entry point — it returns the complete List<RunPlanItem> ready for CollectionRunnerService.execute().

Execution Flow

1

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.
2

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.
3

Pre-scripts → auth resolution → HTTP send

For each RunPlanItem, the runner:
  1. Calls ScriptExecutor.executePreScripts(req.preScriptsJson, workingVars) and merges the results into workingVars.
  2. Resolves authentication via AuthResolverService (inheriting collection-level auth if the request has none).
  3. Passes the request to RequestPipeline.send() — the same HTTP execution path used by the interactive composer — with workingVars as the variable context for URL, headers, params, and body resolution.
4

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.
5

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().
6

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.
7

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.
8

Persist run summary

After all steps complete (or after abortion/cancellation), XoloRepository.finishCollectionRun() writes the final RunStatus, pass/fail/skip counts, and a JSON snapshot of workingVars to the CollectionRuns table. The app then navigates automatically to RunReportScreen.

Run States

CollectionRunNotifier exposes run lifecycle through CollectionRunUiState:
StateMeaning
idleNo run has been started yet (initial state)
runningA run is actively executing steps
completedAll steps finished; check failedSteps for assertion failures
cancelledThe user tapped Cancel, or a CancelToken was cancelled programmatically
errorThe run could not start (e.g., empty collection) or threw an unexpected exception
The 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 of CollectionRunScreen 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 to completed or cancelled, the app navigates to RunReportScreen (route /runs/:runId). The report shows:
  • Overall scorepassedSteps / totalSteps displayed 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() with fromStepIndex set 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.

Build docs developers (and LLMs) love