A step-by-step guide to testing your Electron apps with desktest.
- Docker installed and running
- desktest binary (install or build from source)
- Your Electron app source code
Download the latest release:
curl -fsSL https://raw.githubusercontent.com/Edison-Watch/desktest/master/install.sh | bashOr build from source:
git clone https://github.com/Edison-Watch/desktest.git
cd desktest
cargo build --release
# Binary at target/release/desktestYour app needs a startup script that installs dependencies and launches Electron with the right flags.
Create start.sh in your app directory:
#!/bin/bash
set -e
cd /home/tester/your-app-name
npx electron . --no-sandbox --disable-gpu --force-renderer-accessibility 2>&1Key flags:
--no-sandboxβ required for running inside Docker containers--disable-gpuβ no GPU available in the virtual desktop--force-renderer-accessibilityβ enables the accessibility tree for better agent navigation
Important: Do NOT put
npm installinstart.sh. The entrypoint runs after the app window detection timer starts, andnpm installfor Electron downloads a ~180MB binary that will exceed the 30-second timeout. Instead, use aconfigstep in your task JSON to install dependencies before the app launches (see Step 3).
Package your app as an AppImage using electron-builder:
{
"build": {
"linux": {
"target": "AppImage"
}
}
}Then use app.type = "appimage" with "electron": true in your task JSON. This ensures --no-sandbox, --disable-gpu, and --force-renderer-accessibility are passed to the binary, and the desktest-desktop:electron image is used.
For complex setups, extend the electron base image:
FROM desktest-desktop:electron
COPY my-app /home/tester/my-app
RUN cd /home/tester/my-app && npm install --production
# IMPORTANT: PyAutoGUI requires ~/.Xauthority to connect to the X display.
# Always ensure this file exists after switching users.
USER tester
RUN touch /home/tester/.XauthorityThe electron image adds Node.js and Electron dependencies to the base image:
# Build the base image first (if not already built)
docker build -t desktest-desktop:latest docker/
# Build the electron image
docker build -f docker/Dockerfile.electron -t desktest-desktop:electron docker/Create my-test.json:
{
"schema_version": "1.0",
"id": "my-electron-test",
"instruction": "Click the 'New File' button and type 'Hello World' in the editor",
"app": {
"type": "folder",
"dir": "./my-electron-app",
"entrypoint": "start.sh",
"electron": true
},
"config": [
{
"type": "execute",
"command": "cd /home/tester/my-electron-app && npm install --production"
}
],
"evaluator": {
"mode": "hybrid",
"metrics": [
{
"type": "command_output",
"command": "cat /home/tester/.config/my-app/state.json",
"expected": "Hello World",
"match_mode": "contains"
}
]
},
"timeout": 120,
"max_steps": 10
}The config step runs npm install after the app folder is deployed but before the app is launched, so it doesn't count against the window detection timeout.
The "electron": true flag tells desktest to:
- Use the
desktest-desktop:electronDocker image (which has Node.js and Electron runtime dependencies) - For AppImage deploys, pass
--no-sandbox --disable-gpu --force-renderer-accessibilityflags directly to the binary
Important for folder deploys: Since start.sh is a shell script (not the Electron binary), you must include all Electron flags in your script directly: npx electron . --no-sandbox --disable-gpu --force-renderer-accessibility. Electron does not support env vars for these options β they must be CLI flags.
# Validate the task file first
desktest validate my-test.json
# Run with VNC enabled so you can watch
desktest run my-test.json --config config.json
# Or interactively for debugging
desktest interactive my-test.jsonAfter a test run, review what the agent did:
desktest review desktest_artifacts/This generates an interactive HTML viewer showing each step's screenshot, the agent's reasoning, and the action code.
Convert a successful trajectory into a deterministic replay script:
# Generate replay script from all successful steps
desktest codify test-results/trajectory.jsonl --output test_replay.py
# Or select specific steps (supports ranges)
desktest codify test-results/trajectory.jsonl --steps 1,2,5,6 --output test_replay.py
desktest codify test-results/trajectory.jsonl --steps 1-3,5-8 --output test_replay.pyCreate a task that uses the replay script instead of the LLM:
{
"schema_version": "1.0",
"id": "my-electron-test-replay",
"instruction": "Run the codified test (no LLM needed)",
"app": {
"type": "folder",
"dir": "./my-electron-app",
"entrypoint": "start.sh",
"electron": true
},
"evaluator": {
"mode": "programmatic",
"metrics": [
{
"type": "script_replay",
"script_path": "./test_replay.py"
}
]
},
"timeout": 60,
"max_steps": 1
}Add to your GitHub Actions workflow:
- name: Run desktest
run: |
desktest run my-test-replay.jsonSince codified tests are deterministic (no LLM calls), they're fast, reliable, and free.
- Start with interactive mode (
desktest interactive) to understand how your app looks in the virtual desktop - Use VNC to watch tests live: add
"vnc_port": 5900to your config - Accessibility matters: Electron's
--force-renderer-accessibilityflag helps the agent read your UI. Use semantic HTML and ARIA labels for best results - npm install is slow: Use a
configstep in your task JSON to runnpm installbefore the app launches, or use a custom Docker image with dependencies pre-installed for faster test runs. Never putnpm installin yourstart.shβ it will exceed the window detection timeout - File paths: In the container, your app folder is at
/home/tester/<dir-name>/
See examples/electron-todo-app/ for a complete working example:
desktest run examples/electron-todo.json