jevtest
Plain-English end-to-end tests for Android and iOS apps.
Write what a user does and what they should see. Jev works out the taps. CI replays every run exactly.
Documentation · Getting started · Steps · CI
app: build/app-debug.apk
device: { android: emulator-5554 }
tests:
- name: Sign in
fresh: true
steps:
- do: Sign in with email "${DEMO_EMAIL}" and password "${DEMO_PASSWORD}"
expect: The home screen is showing
see: Welcome, ${DEMO_EMAIL}
$ jevtest run login.yaml --lock frozen --out results
jevtest 0.5.0 · android · emulator-5554 · dev.jevtest.jevtest_demo · typesafe/jev-1.13 · lockfile: frozen
▶ Sign in
✓ do: Sign in with email "${DEMO_EMAIL}" and password "${DEMO_PASSWORD}" (2.6s) — 3 action(s)
→ type "${DEMO_EMAIL}" into text_field 'Email' (confidence 0.83)
→ type "${DEMO_PASSWORD}" into password_field 'Password' (confidence 0.76)
→ tap button 'Sign in' (confidence 0.93)
→ done (confidence 0.96)
✓ expect: The home screen is showing — Jev 0.95
✓ see: Welcome, ${DEMO_EMAIL}
PASS Sign in (7.1s)
1/1 passed in 7s
Jev: 5 decisions, 5 from lockfile, 0 asked live in 0.0s (0% of run time), $0.0000
Why jevtest
- Tests read like the spec. One action, then what should be true.
do:takes a plain-English goal;tap:,type:,swipe:,scroll_to:and 20 more give exact control. - Deterministic. Every Jev decision is recorded in a lockfile. The same screen always gets the same answer;
--lock frozenreplays a run exactly, with no network and no API key. - Nothing assumed. No settings file, no default device, no guessing what a typo meant. The whole test file is checked before a device is touched, and every problem is reported at once with what to fix.
- Real apps, real phones. Android emulators and phones, iOS simulators and iPhones. Native, Flutter, React Native and in-app WebViews, driven the same way. Animations stay on, and anything a step changes on the device is put back.
- No sleeps. It waits for the screen to stop changing, reacting to the device rather than a timer.
- Built for scale and CI.
${SECRETS}from.envor CI, shared test libraries, whole folders in one command, several devices at once, JUnit XML, JSON reports and failure screenshots.
Install
pip install jevtest
You also need the platform tools for your apps: the Android SDK and a JDK, and/or Xcode. An OpenRouter key gives access to Jev. See Getting started.
Run
jevtest run tests.yaml --lock record --out results # asks Jev about new screens, records the answers
jevtest run tests/ --lock frozen --out results # a whole folder, replayed exactly from the lockfiles
How it works
A small agent on the device reads the accessibility tree in milliseconds. jevtest describes the screen as text and asks Jev, TypeSafe's decision model, to choose the next action and element from the options on screen. Jev never writes free text, so everything typed comes from your test file. Each decision is recorded, acted on, and the loop repeats until the goal is done. More.
Status
New, and tested end to end on a Flutter demo app with native and web screens: the Android emulator (API 37), a Pixel 4a (Android 13), iOS simulators (iOS 26) and an iPhone 17 (iOS 27).
Built to a high bar: a clean architecture whose layer rules are checked on every commit, mypy --strict with no exceptions, a docstring on every public object, and unit tests covering 100% of lines and branches. Issues and pull requests are welcome; see Contributing.
License
Release files for jevtest 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| jevtest-0.5.0.tar.gz | 82.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| jevtest-0.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 176.0 kB
Release files / jevtest-0.5.0.tar.gz
| Download URL | jevtest-0.5.0.tar.gz |
|---|---|
| Size | 82.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
615fad6e26fa398acfa57aa3bda8e78081a4c79bc4e78a7a6e2f517081c226b7
|
|
BLAKE2b-256 checksum How to use checksums |
1364ce23f9d7e44a75b673c522babb8cf1683236a1263e234d8b3ae77b278c7e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 26, 2026.
Transparency logRelease files / jevtest-0.5.0-py3-none-any.whl
| Download URL | jevtest-0.5.0-py3-none-any.whl |
|---|---|
| Size | 93.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
280c16d5766f2dbf2c94934c325d7196614ca98d7667814f2541e776c780e742
|
|
BLAKE2b-256 checksum How to use checksums |
6436bd7dac2c34af812858665de21087df037f4691b8a879efacce9aed8835a3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 26, 2026.
Transparency log