Running Tests Through a Wrapper
You always run RobotCode the same way — robotcode … run, a debug session, the repl — and configure everything in robot.toml. The wrapper option doesn't change that: it tells RobotCode to run its actual command through a command of your choosing. The wrapper command goes first and the real robotcode command line is appended to it. That lets the wrapper prepare the test environment a run needs — start the services, servers, mocks or session the tests depend on, run the tests inside it, and tear it all down again — none of which is part of the tests themselves.
Who this is for:
- Bring up the services a run depends on — a database, a message broker, the application under test, a whole
docker composestack — and tear them down again when the run finishes. - Start mocks or stub servers the tests talk to — a fake API, a WireMock instance, a local web server, …
- Run UI tests inside a graphical session — a virtual X server (
xvfb-run) in CI, or a specific window manager / compositor.
Quick start
Section titled “Quick start”# A ready-made tool, for a single run (the value is split like a shell command)robotcode --wrapper "xvfb-run -a" run tests/
# Your own environment script, configured once in a profilerobotcode -p integration run tests/
# Ignore a configured wrapper for one runrobotcode -p integration --no-wrapper run tests/The same wrapper applies whether you run from the command line or from an editor — the editor integrations run robotcode for you. It takes effect only for commands that execute Robot Framework — run, robot, debug, repl, run-debug and repl-server. Commands that don't run tests (the language server, discover, libdoc, …) are never wrapped.
Configure it in robot.toml
Section titled “Configure it in robot.toml”# A ready-made tool — here a virtual X server for headless UI tests[profiles.headless]wrapper = ["xvfb-run", "-a"]
# Your own script — bring the test environment up, then tear it down again[profiles.integration]wrapper = ["./with-test-services.sh"]robotcode -p integration run tests/The profile's env is applied before the wrapper runs, so the wrapper can rely on it. Use extend-wrapper to append to an inherited wrapper. See the robot.toml reference.
On the command line
Section titled “On the command line”--wrapper sets (or overrides) the wrapper for a single run; --no-wrapper disables a configured one:
robotcode --wrapper "xvfb-run -a" run tests/ # split like a shell commandrobotcode -p integration --no-wrapper run tests/ # ignore the profile's wrapperIt can also be set via the ROBOTCODE_WRAPPER environment variable.
With --dry, RobotCode doesn't run the wrapper. It prints which wrapper it would use, followed by the usual dry-run output.
In VS Code
Section titled “In VS Code”As noted above, a wrapper in your selected profile already applies in the editor. If you want to override it for your editor alone — without touching robot.toml — set robotcode.debug.launchWrapper:
"robotcode.debug.launchWrapper": ["./with-test-services.sh"]This wraps tests you run or debug from the Test Explorer and takes precedence over the profile's wrapper. It is an IDE-only override — it has no effect on the command line.
How it runs on Linux/macOS vs. Windows
Section titled “How it runs on Linux/macOS vs. Windows”The wrapper contract is the same everywhere, but RobotCode hands the run to the wrapper differently depending on the operating system, and the resulting process tree differs:
- Linux / macOS — RobotCode replaces itself with the wrapper command (a POSIX
exec). No extra process is left behind: the wrapper inherits RobotCode's process ID, stdio and signals directly. A shell wrapper can end withexec "$@"to replace itself with the run in turn, so signals and the exit code flow through on their own. - Windows — Windows has no way to replace a running process the way POSIX
execdoes. So RobotCode starts the wrapper as a child process, waits for it, and forwards its exit code. One extra RobotCode process stays in the tree just to wait. There is noexechere — a PowerShell wrapper simply runs the command as a child (& $args[0] …) and waits, exactly as the example below does.
Either way the rules you write the script against don't change: run the command in the foreground, pass stdio through, and propagate the exit code.
If the wrapper can't be started at all, because the command doesn't exist or isn't executable, RobotCode reports it and exits with 252, Robot Framework's code for invalid data or command line options. So a CI job can tell a broken setup from failed tests.
Writing your own wrapper script
Section titled “Writing your own wrapper script”A wrapper is just a command. RobotCode runs it with the arguments you configured first, and then appends the actual robotcode command line that has to run:
<your-wrapper> [wrapper args you configured] <robotcode command line, appended by RobotCode>So inside the script, that appended command line is simply "$@" — the script sets up whatever the run needs, then executes "$@". The environment is already prepared for you: the selected profile's [env] is set, and the working directory is the one you started robotcode from.
The usual job is to start something, run the tests, then stop it again — a server, a mock, a database, a session. A trap guarantees teardown, "$@" runs in the foreground, and its exit code is forwarded:
#!/usr/bin/env bashset -euo pipefail
log() { printf '%s\n' "$*" >&2; } # diagnostics ALWAYS to stderr
service_pid=""cleanup() { # stop whatever you started — kill a PID, `docker compose down`, … [ -n "$service_pid" ] && kill "$service_pid" 2>/dev/null || true wait 2>/dev/null || true}trap cleanup EXIT INT TERM # runs on success, error and Ctrl-C
# --- bring the test environment up --------------------------------------log "starting the test environment"my-service & # a web server, a mock, docker compose, Xvfb, …service_pid=$!export SERVICE_URL="http://localhost:8080" # hand the address to the tests
# wait until it is actually ready (poll, don't just sleep blindly)for _ in $(seq 1 50); do is-ready && break kill -0 "$service_pid" 2>/dev/null || { log "service failed to start"; exit 1; } sleep 0.1done
# --- run the appended robotcode command, forward its exit code ----------set +e"$@"status=$?set -eexit "$status" # the trap tears the environment downThe same in PowerShell — configure it as wrapper = ["pwsh", "-File", "./with-test-services.ps1"]. The appended command arrives in $args — the script has no param block, so PowerShell doesn't bind options such as -p or -v to the script itself — and try/finally replaces the trap:
$service = $nulltry { [Console]::Error.WriteLine('starting the test environment') # diagnostics to stderr $service = Start-Process my-service -PassThru # web server, mock, docker compose, … $env:SERVICE_URL = 'http://localhost:8080' # hand the address to the tests
# wait until it is ready (poll, don't just sleep) for ($i = 0; $i -lt 50 -and -not (Test-Ready); $i++) { if ($service.HasExited) { throw 'service failed to start' } Start-Sleep -Milliseconds 100 }
& $args[0] @($args | Select-Object -Skip 1) # run the appended robotcode command $code = $LASTEXITCODE}finally { if ($service -and -not $service.HasExited) { $service | Stop-Process -Force }}exit $code # forward the robotcode exit codeReleased under the Apache-2.0. Copyright © 2022-present Daniel Biehl