Source: https://mokxi.com/docs/account/ci
Updated: 2026-10-12

Getting started The editor Boards Parts Accounts and plans Signing in Your account page Free, Hobby, Pro, Pro for work and school plans Billing The student discount Invites The Mokxi API The mokxi command line Simulation tests in CI The newsletter Live collaboration Classrooms Lessons and the learning game Hobby builds Troubleshooting Reference

Docs / Accounts and plans / Simulation tests in CI

# Simulation tests in CI

Run your Arduino, ESP32 or Pico sketch in the simulator on every push, and fail the build when its output, a pin or an LED is wrong. Part of Pro for work.

Mokxi's command line tool compiles the sketch with the same compiler the editor uses and runs it on the same simulator, headlessly, on the CI machine itself. It needs no server time: the compiler is downloaded once from mokxi.com and cached, and everything else happens on your runner. In CI it needs a CI token from a Pro for work account in MOKXI_TOKEN (see which plan CI needs); on your own computer it needs no account at all. It reads Wokwi projects and Wokwi scenario files as they are, so moving from Wokwi CI is a one-line change.

## Quick start

In a folder with a sketch (and, if it has more than a bare board, a diagram.json from Mokxi or Wokwi):

That compiles the sketch, runs it, prints the serial output as it comes, and exits as soon as Ready appears (exit code 0). It fails with exit code 1 the moment the sketch prints panic, when 10 seconds of simulated time go by without Ready, or when the sketch does not compile. Node.js 18 or newer is all it needs.

For more than one line of output, write a scenario. Put this in mokxi.test.yaml next to the sketch:

and run every test in it, with a JUnit report for your CI dashboard:

Each test is a fresh run of the sketch, and each one is a test case in the report.

### On GitHub Actions

The action runs mokxi.test.yaml when the folder has one, and otherwise checks the sketch boots and prints the expected text. It keeps the compiler in the Actions cache, so it is downloaded once, writes mokxi-junit.xml, puts a table of the results in the job summary, and annotates the run with each failure, a compile error on its own line. Every input is listed in the action's action.yml: path, scenario, timeout, expect-serial, fail-on, board, firmware, junit, serial-log, screenshot, args and version.

### On any other CI

The command line is the whole product, so anything that runs Node works the same way. GitLab CI, for example:

Keep the cache folder between jobs (MOKXI_CACHE_DIR, or ~/.cache/mokxi by default). Without it every job downloads the compiler again, and mokxi.com limits how often one address may do that.

## What it runs

mokxi run and mokxi test take a folder, a file or a link:

What
How it is read

A folder from mokxi pull or Save to GitHub
diagram.mokxi.json and the sketch folder beside it

A Wokwi project folder
diagram.json, the sketch and its tabs, libraries.txt, and wokwi.toml

A plain Arduino sketch folder
a bare board for the sketch: an Uno, or say which with --board esp32

A .mokxi.json file
the file the editor's Download JSON writes

https://mokxi.com/p/<id>
a public project, or your own with mokxi login or MOKXI_TOKEN

https://wokwi.com/projects/<id>
a public Wokwi project, fetched from Wokwi

The sketch is compiled for the board in the diagram, with the project's own libraries and the common Arduino libraries Mokxi carries. To run a build of your own instead (PlatformIO's or arduino-cli's), pass it: --firmware build/sketch.ino.elf, or --firmware uno1=build/a.elf for one board of several. When a Wokwi project's wokwi.toml names a firmware file that exists, that build is run, as Wokwi does; --compile builds the sketch instead.

Every board Mokxi simulates runs here: the Uno, Nano, Mega, Leonardo, Pro Mini and ATtiny85, the ESP32, ESP32-S3, ESP32-C3, ESP32-C6 and ESP8266, the Pico and Pico W, the UNO R4, the STM32 boards, the XIAO and the micro:bit. mokxi boards lists them.

## Command reference

Option
What it does

--timeout 10s
simulated time the run (or each scenario) may take. A bare number is milliseconds, as in Wokwi's CLI

--expect-serial TEXT
pass as soon as every such text has been printed. Repeat it for several. --expect-text is the same

--fail-on TEXT
fail the moment this text is printed. --fail-text is the same

--scenario FILE
run this scenario file (mokxi run --scenario is mokxi test)

--junit FILE
write a JUnit XML report

--serial-log-file FILE
write everything the boards printed

--screenshot FILE.svg
for mokxi run: a picture of the circuit when the run ends; --screenshot-part led1 for one part. --screenshot-file is the same

--firmware [board=]FILE, --elf FILE
run this build instead of compiling

--board TYPE
the board for a sketch with no diagram

--diagram-file FILE
read this diagram instead of the folder's diagram.json

--compile
build the sketch even when wokwi.toml names a firmware file

--timeout-exit-code N
the exit code for a timeout (default 1; Wokwi's CLI uses 42)

--offline
never reach the network; fail if the compiler is not cached

--quiet
do not print the serial output (mokxi run)

--verbose
print the serial output and every step (mokxi test)

Exit codes: 0 when everything passed, 1 when something failed (a check, a timeout, a --fail-on line, a compile error), 2 for a mistake in the command or the scenario file, and 3 when a download failed.

Time in a run is simulated time, not wall-clock time, so a test behaves the same on a fast laptop and a slow CI machine. A run that takes far longer in real time than it should (30 times its timeout, or at least two minutes) is stopped as stuck.

## Scenario reference

A scenario file is YAML. It holds one scenario (steps: at the top) or several (tests:, a list of name and steps):

Key
What it is

name
the file's name in the report

project
the project to run, relative to the file: a folder, a file or a link. Default: the file's own folder

board
the board for a sketch with no diagram

firmware
a build to run instead of compiling: a path, or { board: path }

timeout
simulated time each scenario may take (default 30 s for mokxi test)

fail-on
text that fails the scenario the moment it is printed: one, or a list

steps
one scenario's steps

tests
several scenarios, each { name, steps, timeout?, fail-on? }

Steps run in order, and a scenario stops at the first one that fails. Any step can carry a name: for the report.

Step
What it does

wait-serial: Ready
run until this text is printed after what earlier waits matched. /pattern/ is a regular expression. { text, timeout, board } limits how long it waits, and on which board

expect-serial: Ready
check the text has been printed by now, without waiting

expect-no-serial: error
check it has not

write-serial: "hello\n"
type into the serial monitor (exactly this text: add \n for Enter)

delay: 500ms
let the simulation run this long

press: btn1 / release: btn1
hold a button down, or let it go

click: btn1
press, hold 100 ms ({ part, hold } to change it), release

set: { part: dht1, temperature: 30 }
set a sensor or a control; see the table below

expect-pin: { pin: uno:13, level: high }
check a pin's level now. uno:13=high is the same. A bare 13 is the only board's pin

wait-pin: { pin: uno:2, level: low, timeout: 1s }
run until the pin reaches that level

expect-toggles: { pin: uno:13, during: 1s, min: 3, max: 5 }
run for during and count the pin's changes: count, min and max. This is how timing is checked: a 2 Hz blink is four changes a second

expect-led: led1
check an LED is lit; expect-led-off: led1 that it is dark

expect-probe: { part: servo1, min: 85, max: 95 }
check any part's reading (a servo's angle, a display's lit segments, a motor's speed)

screenshot: build/circuit.svg
save a picture of the circuit, every part drawn as it is right now. { part: led1, file } draws one part

poke: { part, code }
send a part a raw stimulus code, for anything the table below does not name

An LED's brightness in the simulator is what the eye sees: it fades over a few milliseconds, as on the bench. So expect-led gives the LED up to 50 ms of simulated time to get there before it fails.

Pins are named as in the editor (uno1:13, esp1:D2, pico1:GP15); 13, D13, GP13 and GPIO13 are each tried. Parts are named by their id in the diagram, or by their Wokwi id when the project came from Wokwi.

### Sensors and controls

Part
Controls (set: { part, <control>: <value> })

Pushbutton, arcade button, microswitch
pressed: 1 or 0

Slide switch
value: 0 or 1

Potentiometer, slide potentiometer
position: 0 to 1 (or 0 to 1023)

DHT11, DHT22, AHT20
temperature in C, humidity in %

DS18B20, LM35, TMP36, NTC module
temperature in C

BMP180, BMP280, BME280
temperature in C, pressure in hPa, humidity in % (BME280)

HC-SR04
distance in cm

FC-51 obstacle sensor
distance in cm

LDR, LDR module, phototransistor, BH1750
lux

PIR
motion: 1 or 0

Soil moisture
moisture in %

MQ-2
gas in ppm

DIP switches, keypads
value or keys: a bitmask

## Switching from Wokwi CI

Your Wokwi project folder runs as it is. diagram.json, wokwi.toml, the sketch, libraries.txt and your scenario files are read unchanged. Set the token input to your Mokxi CI token.

On GitHub Actions, change the uses: line. The action takes Wokwi's input names too (expect_text, fail_text, serial_log_file, elf, diagram_file, timeout_exit_code), and accepts and ignores token, so the rest of the step can stay as it is. You can delete the WOKWI_CLI_TOKEN secret.

From a shell, wokwi-cli options map one to one:

wokwi-cli
mokxi

wokwi-cli .
mokxi run .

--timeout 10000
--timeout 10000 (or 10s)

--expect-text "Ready"
--expect-text "Ready"

--fail-text "panic"
--fail-text "panic"

--scenario test.yaml
--scenario test.yaml

--serial-log-file log.txt
--serial-log-file log.txt

--elf build/app.elf
--elf build/app.elf

--diagram-file other.json
--diagram-file other.json

--timeout-exit-code 42
--timeout-exit-code 42

--screenshot-part lcd1 --screenshot-file lcd.png
--screenshot-part lcd1 --screenshot-file lcd.svg (taken when the run ends)

In scenario files, wait-serial, write-serial, delay, set-control (part-id, control, value), expect-pin (part-id, pin, value) and take-screenshot (part-id, save-to) work as written. Two differences to know:

- A screenshot is an SVG drawn from the circuit, so save-to: shot.png is saved as shot.svg, and compare-with is not checked.

- A Wokwi part with no Mokxi equivalent is left out and named in the log, the same as when you import the project into the editor. Importing from other tools lists what comes across.

## Which plan CI needs

CI runs are part of Pro for work since October 12, 2026: $20 a seat a month,
with 5,000 CI minutes a seat each month. In CI mode (CI=true,
GITHUB_ACTIONS=true, or --ci), mokxi run, mokxi test and mokxi simulate check your plan with the token in MOKXI_TOKEN; make a CI token from
Settings, Developer, on a Pro for work account, and keep it in a repository
secret. The license is cached for seven days, so a runner without network inside
that week still runs.

Running a sketch on your own computer with mokxi run stays free, with no
account.

If you used CI in the 60 days before the change, you keep it until December 11,
2026, and each run prints: "Mokxi CI is moving to Pro for work on December 11,
2026." An account that was paying for a plan then keeps CI while it keeps
paying.

## Caching and offline use

The compiler (about 80 MB), each board family's runtime and its compiled objects are kept in ~/.cache/mokxi (or MOKXI_CACHE_DIR, or $XDG_CACHE_HOME/mokxi). The first build of a board family takes 10 to 20 seconds; later builds take a few. The ESP32, ESP32-S3 and ESP8266 compile with a second toolchain of the same size, downloaded the first time one of them is built. The compiler is checked against the published build's SHA-256 before it is used. mokxi cache shows the folder and its size, and mokxi cache clear empties it.

On a machine with no network, copy a warm cache folder there and pass --offline (or set MOKXI_OFFLINE=1): nothing is fetched, and a missing file is an error rather than a download.

### On this page

Quick start On GitHub Actions On any other CI What it runs Command reference Scenario reference Sensors and controls Switching from Wokwi CI Which plan CI needs Caching and offline use
