jevtest 0.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. jevtest-0.5.0/LICENSE +21 -0
  2. jevtest-0.5.0/PKG-INFO +135 -0
  3. jevtest-0.5.0/README.md +89 -0
  4. jevtest-0.5.0/jevtest/__init__.py +3 -0
  5. jevtest-0.5.0/jevtest/__main__.py +7 -0
  6. jevtest-0.5.0/jevtest/adapters/__init__.py +4 -0
  7. jevtest-0.5.0/jevtest/adapters/clock.py +17 -0
  8. jevtest-0.5.0/jevtest/adapters/devices/__init__.py +1 -0
  9. jevtest-0.5.0/jevtest/adapters/devices/android.py +556 -0
  10. jevtest-0.5.0/jevtest/adapters/devices/android_agent/AndroidManifest.xml +14 -0
  11. jevtest-0.5.0/jevtest/adapters/devices/android_agent/src/dev/jevtest/agent/Agent.java +305 -0
  12. jevtest-0.5.0/jevtest/adapters/devices/common.py +174 -0
  13. jevtest-0.5.0/jevtest/adapters/devices/ios.py +569 -0
  14. jevtest-0.5.0/jevtest/adapters/devices/ios_agent/AgentHost/AppDelegate.swift +18 -0
  15. jevtest-0.5.0/jevtest/adapters/devices/ios_agent/AgentUITests/JevAgentUITests.swift +346 -0
  16. jevtest-0.5.0/jevtest/adapters/devices/ios_agent/JevAgent.xcodeproj/project.pbxproj +443 -0
  17. jevtest-0.5.0/jevtest/adapters/devices/ios_agent/JevAgent.xcodeproj/xcshareddata/xcschemes/JevAgent.xcscheme +111 -0
  18. jevtest-0.5.0/jevtest/adapters/jev/__init__.py +1 -0
  19. jevtest-0.5.0/jevtest/adapters/jev/client.py +138 -0
  20. jevtest-0.5.0/jevtest/adapters/jev/lockfile.py +161 -0
  21. jevtest-0.5.0/jevtest/adapters/jev/wire.py +63 -0
  22. jevtest-0.5.0/jevtest/adapters/reports/__init__.py +1 -0
  23. jevtest-0.5.0/jevtest/adapters/reports/json_report.py +70 -0
  24. jevtest-0.5.0/jevtest/adapters/reports/junit.py +44 -0
  25. jevtest-0.5.0/jevtest/adapters/testfile/__init__.py +1 -0
  26. jevtest-0.5.0/jevtest/adapters/testfile/discovery.py +35 -0
  27. jevtest-0.5.0/jevtest/adapters/testfile/env.py +43 -0
  28. jevtest-0.5.0/jevtest/adapters/testfile/loader.py +511 -0
  29. jevtest-0.5.0/jevtest/application/__init__.py +1 -0
  30. jevtest-0.5.0/jevtest/application/brain.py +236 -0
  31. jevtest-0.5.0/jevtest/application/planning.py +25 -0
  32. jevtest-0.5.0/jevtest/application/runner.py +459 -0
  33. jevtest-0.5.0/jevtest/cli/__init__.py +1 -0
  34. jevtest-0.5.0/jevtest/cli/console.py +201 -0
  35. jevtest-0.5.0/jevtest/cli/main.py +83 -0
  36. jevtest-0.5.0/jevtest/cli/run.py +270 -0
  37. jevtest-0.5.0/jevtest/domain/__init__.py +4 -0
  38. jevtest-0.5.0/jevtest/domain/decisions.py +148 -0
  39. jevtest-0.5.0/jevtest/domain/failures.py +29 -0
  40. jevtest-0.5.0/jevtest/domain/kinds.py +53 -0
  41. jevtest-0.5.0/jevtest/domain/model.py +76 -0
  42. jevtest-0.5.0/jevtest/domain/ports.py +208 -0
  43. jevtest-0.5.0/jevtest/domain/results.py +122 -0
  44. jevtest-0.5.0/jevtest/domain/rules.py +28 -0
  45. jevtest-0.5.0/jevtest/domain/screen.py +128 -0
  46. jevtest-0.5.0/jevtest/domain/steps.py +283 -0
  47. jevtest-0.5.0/jevtest/domain/variables.py +26 -0
  48. jevtest-0.5.0/jevtest/py.typed +0 -0
  49. jevtest-0.5.0/jevtest.egg-info/PKG-INFO +135 -0
  50. jevtest-0.5.0/jevtest.egg-info/SOURCES.txt +54 -0
  51. jevtest-0.5.0/jevtest.egg-info/dependency_links.txt +1 -0
  52. jevtest-0.5.0/jevtest.egg-info/entry_points.txt +2 -0
  53. jevtest-0.5.0/jevtest.egg-info/requires.txt +16 -0
  54. jevtest-0.5.0/jevtest.egg-info/top_level.txt +1 -0
  55. jevtest-0.5.0/pyproject.toml +118 -0
  56. jevtest-0.5.0/setup.cfg +4 -0
jevtest-0.5.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Bret Hagen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
jevtest-0.5.0/PKG-INFO ADDED
@@ -0,0 +1,135 @@
1
+ Metadata-Version: 2.4
2
+ Name: jevtest
3
+ Version: 0.5.0
4
+ Summary: Plain-English end-to-end tests for Android and iOS apps, driven by TypeSafe's Jev model
5
+ Author: Bret Hagen
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://just-betr.github.io/jevtest/
8
+ Project-URL: Documentation, https://just-betr.github.io/jevtest/
9
+ Project-URL: Source, https://github.com/Just-Betr/jevtest
10
+ Project-URL: Issues, https://github.com/Just-Betr/jevtest/issues
11
+ Project-URL: Changelog, https://github.com/Just-Betr/jevtest/blob/main/CHANGELOG.md
12
+ Keywords: testing,e2e,mobile,android,ios,flutter,react-native,webview,ai,jev,xcuitest,uiautomator
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Typing :: Typed
15
+ Classifier: Environment :: Console
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: Operating System :: MacOS
18
+ Classifier: Operating System :: POSIX :: Linux
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3 :: Only
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Programming Language :: Python :: 3.14
25
+ Classifier: Topic :: Software Development :: Quality Assurance
26
+ Classifier: Topic :: Software Development :: Testing
27
+ Classifier: Topic :: Software Development :: Testing :: Acceptance
28
+ Requires-Python: >=3.11
29
+ Description-Content-Type: text/markdown
30
+ License-File: LICENSE
31
+ Requires-Dist: pyyaml>=6
32
+ Provides-Extra: dev
33
+ Requires-Dist: pytest>=8; extra == "dev"
34
+ Requires-Dist: pytest-cov>=5; extra == "dev"
35
+ Requires-Dist: ruff>=0.6; extra == "dev"
36
+ Requires-Dist: mypy>=1.11; extra == "dev"
37
+ Requires-Dist: types-PyYAML; extra == "dev"
38
+ Requires-Dist: import-linter>=2.1; extra == "dev"
39
+ Requires-Dist: build; extra == "dev"
40
+ Requires-Dist: pre-commit; extra == "dev"
41
+ Provides-Extra: docs
42
+ Requires-Dist: mkdocs<2,>=1.6; extra == "docs"
43
+ Requires-Dist: mkdocs-material>=9.5; extra == "docs"
44
+ Requires-Dist: mkdocstrings[python]>=0.26; extra == "docs"
45
+ Dynamic: license-file
46
+
47
+ <h1 align="center">jevtest</h1>
48
+
49
+ <p align="center"><b>Plain-English end-to-end tests for Android and iOS apps.</b><br>
50
+ Write what a user does and what they should see. Jev works out the taps. CI replays every run exactly.</p>
51
+
52
+ <p align="center">
53
+ <a href="https://github.com/Just-Betr/jevtest/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/Just-Betr/jevtest/actions/workflows/ci.yml/badge.svg"></a>
54
+ <a href="https://just-betr.github.io/jevtest/contributing/"><img alt="Coverage" src="https://img.shields.io/endpoint?url=https%3A%2F%2Fjust-betr.github.io%2Fjevtest%2Fbadges%2Fcoverage.json"></a>
55
+ <a href="https://pypi.org/project/jevtest/"><img alt="PyPI" src="https://img.shields.io/pypi/v/jevtest"></a>
56
+ <a href="https://pypi.org/project/jevtest/"><img alt="Python" src="https://img.shields.io/pypi/pyversions/jevtest"></a>
57
+ <a href="https://just-betr.github.io/jevtest/"><img alt="Docs" src="https://img.shields.io/badge/docs-just--betr.github.io%2Fjevtest-5e35b1"></a>
58
+ <a href="https://github.com/Just-Betr/jevtest/blob/main/LICENSE"><img alt="MIT license" src="https://img.shields.io/badge/license-MIT-blue"></a>
59
+ </p>
60
+
61
+ <p align="center"><a href="https://just-betr.github.io/jevtest/"><b>Documentation</b></a> ·
62
+ <a href="https://just-betr.github.io/jevtest/getting-started/">Getting started</a> ·
63
+ <a href="https://just-betr.github.io/jevtest/reference/steps/">Steps</a> ·
64
+ <a href="https://just-betr.github.io/jevtest/guides/ci/">CI</a></p>
65
+
66
+ ---
67
+
68
+ ```yaml
69
+ app: build/app-debug.apk
70
+ device: { android: emulator-5554 }
71
+
72
+ tests:
73
+ - name: Sign in
74
+ fresh: true
75
+ steps:
76
+ - do: Sign in with email "${DEMO_EMAIL}" and password "${DEMO_PASSWORD}"
77
+ expect: The home screen is showing
78
+ see: Welcome, ${DEMO_EMAIL}
79
+ ```
80
+
81
+ ```console
82
+ $ jevtest run login.yaml --lock frozen --out results
83
+ jevtest 0.5.0 · android · emulator-5554 · dev.jevtest.jevtest_demo · typesafe/jev-1.13 · lockfile: frozen
84
+
85
+ ▶ Sign in
86
+ ✓ do: Sign in with email "${DEMO_EMAIL}" and password "${DEMO_PASSWORD}" (2.6s) — 3 action(s)
87
+ → type "${DEMO_EMAIL}" into text_field 'Email' (confidence 0.83)
88
+ → type "${DEMO_PASSWORD}" into password_field 'Password' (confidence 0.76)
89
+ → tap button 'Sign in' (confidence 0.93)
90
+ → done (confidence 0.96)
91
+ ✓ expect: The home screen is showing — Jev 0.95
92
+ ✓ see: Welcome, ${DEMO_EMAIL}
93
+ PASS Sign in (7.1s)
94
+
95
+ 1/1 passed in 7s
96
+ Jev: 5 decisions, 5 from lockfile, 0 asked live in 0.0s (0% of run time), $0.0000
97
+ ```
98
+
99
+ ## Why jevtest
100
+
101
+ - **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.
102
+ - **Deterministic.** Every Jev decision is recorded in a lockfile. The same screen always gets the same answer; `--lock frozen` replays a run exactly, with no network and no API key.
103
+ - **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.
104
+ - **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.
105
+ - **No sleeps.** It waits for the screen to stop changing, reacting to the device rather than a timer.
106
+ - **Built for scale and CI.** `${SECRETS}` from `.env` or CI, shared test libraries, whole folders in one command, several devices at once, JUnit XML, JSON reports and failure screenshots.
107
+
108
+ ## Install
109
+
110
+ ```bash
111
+ pip install jevtest
112
+ ```
113
+
114
+ You also need the platform tools for your apps: the Android SDK and a JDK, and/or Xcode. An [OpenRouter key](https://openrouter.ai/keys) gives access to Jev. See [Getting started](https://just-betr.github.io/jevtest/getting-started/).
115
+
116
+ ## Run
117
+
118
+ ```bash
119
+ jevtest run tests.yaml --lock record --out results # asks Jev about new screens, records the answers
120
+ jevtest run tests/ --lock frozen --out results # a whole folder, replayed exactly from the lockfiles
121
+ ```
122
+
123
+ ## How it works
124
+
125
+ A small agent on the device reads the accessibility tree in milliseconds. jevtest describes the screen as text and asks [Jev](https://openrouter.ai), 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](https://just-betr.github.io/jevtest/how-it-works/).
126
+
127
+ ## Status
128
+
129
+ 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).
130
+
131
+ Built to a high bar: a [clean architecture](https://just-betr.github.io/jevtest/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](https://just-betr.github.io/jevtest/contributing/).
132
+
133
+ ## License
134
+
135
+ [MIT](https://github.com/Just-Betr/jevtest/blob/main/LICENSE)
@@ -0,0 +1,89 @@
1
+ <h1 align="center">jevtest</h1>
2
+
3
+ <p align="center"><b>Plain-English end-to-end tests for Android and iOS apps.</b><br>
4
+ Write what a user does and what they should see. Jev works out the taps. CI replays every run exactly.</p>
5
+
6
+ <p align="center">
7
+ <a href="https://github.com/Just-Betr/jevtest/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/Just-Betr/jevtest/actions/workflows/ci.yml/badge.svg"></a>
8
+ <a href="https://just-betr.github.io/jevtest/contributing/"><img alt="Coverage" src="https://img.shields.io/endpoint?url=https%3A%2F%2Fjust-betr.github.io%2Fjevtest%2Fbadges%2Fcoverage.json"></a>
9
+ <a href="https://pypi.org/project/jevtest/"><img alt="PyPI" src="https://img.shields.io/pypi/v/jevtest"></a>
10
+ <a href="https://pypi.org/project/jevtest/"><img alt="Python" src="https://img.shields.io/pypi/pyversions/jevtest"></a>
11
+ <a href="https://just-betr.github.io/jevtest/"><img alt="Docs" src="https://img.shields.io/badge/docs-just--betr.github.io%2Fjevtest-5e35b1"></a>
12
+ <a href="https://github.com/Just-Betr/jevtest/blob/main/LICENSE"><img alt="MIT license" src="https://img.shields.io/badge/license-MIT-blue"></a>
13
+ </p>
14
+
15
+ <p align="center"><a href="https://just-betr.github.io/jevtest/"><b>Documentation</b></a> ·
16
+ <a href="https://just-betr.github.io/jevtest/getting-started/">Getting started</a> ·
17
+ <a href="https://just-betr.github.io/jevtest/reference/steps/">Steps</a> ·
18
+ <a href="https://just-betr.github.io/jevtest/guides/ci/">CI</a></p>
19
+
20
+ ---
21
+
22
+ ```yaml
23
+ app: build/app-debug.apk
24
+ device: { android: emulator-5554 }
25
+
26
+ tests:
27
+ - name: Sign in
28
+ fresh: true
29
+ steps:
30
+ - do: Sign in with email "${DEMO_EMAIL}" and password "${DEMO_PASSWORD}"
31
+ expect: The home screen is showing
32
+ see: Welcome, ${DEMO_EMAIL}
33
+ ```
34
+
35
+ ```console
36
+ $ jevtest run login.yaml --lock frozen --out results
37
+ jevtest 0.5.0 · android · emulator-5554 · dev.jevtest.jevtest_demo · typesafe/jev-1.13 · lockfile: frozen
38
+
39
+ ▶ Sign in
40
+ ✓ do: Sign in with email "${DEMO_EMAIL}" and password "${DEMO_PASSWORD}" (2.6s) — 3 action(s)
41
+ → type "${DEMO_EMAIL}" into text_field 'Email' (confidence 0.83)
42
+ → type "${DEMO_PASSWORD}" into password_field 'Password' (confidence 0.76)
43
+ → tap button 'Sign in' (confidence 0.93)
44
+ → done (confidence 0.96)
45
+ ✓ expect: The home screen is showing — Jev 0.95
46
+ ✓ see: Welcome, ${DEMO_EMAIL}
47
+ PASS Sign in (7.1s)
48
+
49
+ 1/1 passed in 7s
50
+ Jev: 5 decisions, 5 from lockfile, 0 asked live in 0.0s (0% of run time), $0.0000
51
+ ```
52
+
53
+ ## Why jevtest
54
+
55
+ - **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.
56
+ - **Deterministic.** Every Jev decision is recorded in a lockfile. The same screen always gets the same answer; `--lock frozen` replays a run exactly, with no network and no API key.
57
+ - **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.
58
+ - **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.
59
+ - **No sleeps.** It waits for the screen to stop changing, reacting to the device rather than a timer.
60
+ - **Built for scale and CI.** `${SECRETS}` from `.env` or CI, shared test libraries, whole folders in one command, several devices at once, JUnit XML, JSON reports and failure screenshots.
61
+
62
+ ## Install
63
+
64
+ ```bash
65
+ pip install jevtest
66
+ ```
67
+
68
+ You also need the platform tools for your apps: the Android SDK and a JDK, and/or Xcode. An [OpenRouter key](https://openrouter.ai/keys) gives access to Jev. See [Getting started](https://just-betr.github.io/jevtest/getting-started/).
69
+
70
+ ## Run
71
+
72
+ ```bash
73
+ jevtest run tests.yaml --lock record --out results # asks Jev about new screens, records the answers
74
+ jevtest run tests/ --lock frozen --out results # a whole folder, replayed exactly from the lockfiles
75
+ ```
76
+
77
+ ## How it works
78
+
79
+ A small agent on the device reads the accessibility tree in milliseconds. jevtest describes the screen as text and asks [Jev](https://openrouter.ai), 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](https://just-betr.github.io/jevtest/how-it-works/).
80
+
81
+ ## Status
82
+
83
+ 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).
84
+
85
+ Built to a high bar: a [clean architecture](https://just-betr.github.io/jevtest/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](https://just-betr.github.io/jevtest/contributing/).
86
+
87
+ ## License
88
+
89
+ [MIT](https://github.com/Just-Betr/jevtest/blob/main/LICENSE)
@@ -0,0 +1,3 @@
1
+ """jevtest: plain-English end-to-end tests for Android and iOS apps, driven by TypeSafe's Jev."""
2
+
3
+ __version__ = "0.5.0"
@@ -0,0 +1,7 @@
1
+ """``python -m jevtest``: the same as the ``jevtest`` command."""
2
+
3
+ import sys
4
+
5
+ from .cli.main import main
6
+
7
+ sys.exit(main())
@@ -0,0 +1,4 @@
1
+ """Everything outside jevtest: devices, Jev, files.
2
+
3
+ Each adapter implements a domain port and turns its tools' exceptions into the domain's failures.
4
+ """
@@ -0,0 +1,17 @@
1
+ """Real time, for the runner's `Clock` port."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import time
6
+
7
+
8
+ class SystemClock:
9
+ """The system's monotonic clock."""
10
+
11
+ def now(self) -> float:
12
+ """Seconds on a monotonic clock."""
13
+ return time.monotonic()
14
+
15
+ def sleep(self, seconds: float) -> None:
16
+ """Wait."""
17
+ time.sleep(seconds)
@@ -0,0 +1 @@
1
+ """The device adapters: Android (adb + an on-device agent) and iOS (Xcode tools + an XCUITest agent)."""