@tai2/aco 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +203 -0
- package/dist/cli.js +6022 -0
- package/dist/cli.js.map +1 -0
- package/package.json +84 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Taiju Muto
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# aco -- Appium Command-line Operator
|
|
2
|
+
|
|
3
|
+
[](https://github.com/tai2/aco/actions/workflows/ci.yml)
|
|
4
|
+

|
|
5
|
+
|
|
6
|
+
Drive an Appium session from the shell. Start a session against an app, then
|
|
7
|
+
send each Appium command as a single shell invocation -- no client-script
|
|
8
|
+
scaffolding required.
|
|
9
|
+
|
|
10
|
+
## Prerequisites
|
|
11
|
+
|
|
12
|
+
Install Appium and at least one driver first; `aco` spawns the `appium` binary
|
|
13
|
+
from your `PATH`. See the [Appium install guide](https://appium.io/docs/en/latest/quickstart/install/)
|
|
14
|
+
for details.
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
npm i -g appium # needs Node.js LTS and npm >=10
|
|
18
|
+
which appium # confirm it's on PATH
|
|
19
|
+
|
|
20
|
+
appium driver install xcuitest # iOS (requires Xcode + command line tools)
|
|
21
|
+
appium driver install uiautomator2 # Android (requires Android SDK + JDK)
|
|
22
|
+
|
|
23
|
+
appium driver doctor xcuitest # verify a driver's toolchain
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
npm i -g @tai2/aco
|
|
30
|
+
# or run without installing:
|
|
31
|
+
npx @tai2/aco --help
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
### Discover devices
|
|
37
|
+
|
|
38
|
+
List iOS Simulators, Android AVDs, and connected real devices. Pass a row's
|
|
39
|
+
`NAME` to `--device-name` (iOS) / `--avd` (Android emulator), or its `ID` to
|
|
40
|
+
`--udid` (real device or simulator).
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
aco device list # both platforms, only "available" rows
|
|
44
|
+
aco device list --platform ios # iOS Simulators + connected iPhones/iPads
|
|
45
|
+
aco device list --state all --json # everything, machine-readable
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Start a session
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
# iOS simulator (foreground; Ctrl-C tears it down)
|
|
52
|
+
aco session start --platform ios --app /tmp/MyApp.app --device-name "iPhone 15"
|
|
53
|
+
|
|
54
|
+
# Android emulator
|
|
55
|
+
aco session start --platform android --app com.example.app --app-activity .MainActivity --avd Pixel_8_API_34
|
|
56
|
+
|
|
57
|
+
# iOS real device (requires code signing for the on-device WebDriverAgent build)
|
|
58
|
+
aco session start --platform ios --udid <40-char-udid> \
|
|
59
|
+
--app /tmp/MyApp.ipa --xcode-org-id ABCDE12345
|
|
60
|
+
|
|
61
|
+
# Android real device (auto-selected when one is plugged in and no --avd given)
|
|
62
|
+
aco session start --platform android --app com.example.app --app-activity .MainActivity
|
|
63
|
+
|
|
64
|
+
# Background instead of foreground
|
|
65
|
+
aco session start --detach --platform ios --app /tmp/MyApp.app
|
|
66
|
+
|
|
67
|
+
# Forward extra Appium server flags
|
|
68
|
+
aco session start --platform android --log-level debug --use-plugins images
|
|
69
|
+
|
|
70
|
+
# Remote server / device farm: --server-url attaches to a running Appium
|
|
71
|
+
# instead of spawning one. --auth sends BASIC auth (only on session creation;
|
|
72
|
+
# or via ACO_REMOTE_USERNAME / ACO_REMOTE_PASSWORD).
|
|
73
|
+
aco session start --platform android --server-url https://grid.example.com/wd/hub \
|
|
74
|
+
--auth user:accessKey --cap deviceName="Pixel 8"
|
|
75
|
+
|
|
76
|
+
# Device farm with vendor-specific nested caps (LambdaTest's "lt:options",
|
|
77
|
+
# BrowserStack's "bstack:options", ...): pass the whole W3C caps object with
|
|
78
|
+
# --caps-json (or --caps-json @file). Replaces the aco-built caps; --platform
|
|
79
|
+
# is still required.
|
|
80
|
+
aco session start --platform android \
|
|
81
|
+
--server-url https://mobile-hub.lambdatest.com/wd/hub --auth user:accessKey \
|
|
82
|
+
--caps-json '{"platformName":"android","lt:options":{"isRealMobile":true,"platformVersion":"13","deviceName":"Pixel 8","app":"lt://APP_ID"}}'
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
- With neither `--udid` nor `--avd`, a connected real device wins; otherwise the
|
|
86
|
+
first Android AVD is auto-booted. Explicit `--udid`/`--avd` always win.
|
|
87
|
+
- iOS real devices need `--xcode-org-id` (plus optional `--xcode-signing-id`,
|
|
88
|
+
`--allow-provisioning-device-registration`, `--updated-wda-bundle-id`).
|
|
89
|
+
- `--log` streams the Appium log to stdout. `aco session start --help` lists the
|
|
90
|
+
forwarded server flags (`--log-level`, `--relaxed-security`, the `*-timeout`
|
|
91
|
+
knobs, ...).
|
|
92
|
+
|
|
93
|
+
### Drive the session
|
|
94
|
+
|
|
95
|
+
`--session`, `--server-url`, and `--platform` are optional with a live local
|
|
96
|
+
session; pass them explicitly for remote/grid sessions.
|
|
97
|
+
|
|
98
|
+
```sh
|
|
99
|
+
aco source # full page source
|
|
100
|
+
aco source --xpath '//XCUIElementTypeButton[@name="Login"]' # filter locally
|
|
101
|
+
aco elements # labelled elements + tap selectors
|
|
102
|
+
aco elements --json | jq -r '.[].selector' # just the selectors
|
|
103
|
+
aco screenshot --out ./shot.png
|
|
104
|
+
aco tap --x 100 --y 200
|
|
105
|
+
aco tap --selector 'accessibility id:login.button'
|
|
106
|
+
aco swipe --direction up # within the default scroll view
|
|
107
|
+
aco swipe --direction left --label home.carousel # within a labelled element
|
|
108
|
+
aco send-keys --selector 'accessibility id:login.username' --text 'alice' # clears, then types
|
|
109
|
+
aco send-keys --label login.username --text '!' --no-clear # append instead
|
|
110
|
+
aco scroll-into-view "accessibility id:gestures.row.29" --direction up # swipe until visible
|
|
111
|
+
aco actions --gesture "move 200 600 0, down, move 200 200 300, up" # raw W3C pointer
|
|
112
|
+
aco actions --type "hello" # raw W3C key
|
|
113
|
+
aco element find --using "accessibility id" --value "Login"
|
|
114
|
+
aco element click --element <element-id>
|
|
115
|
+
aco context list
|
|
116
|
+
aco context switch --name WEBVIEW_com.example # enter the web context, then:
|
|
117
|
+
aco web url https://example.com # navigate the active WebView
|
|
118
|
+
|
|
119
|
+
# Explicit targeting (remote/grid):
|
|
120
|
+
aco source --session <sid> --server-url http://10.0.0.5:4799 --platform ios
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Platform `mobile:` extensions
|
|
124
|
+
|
|
125
|
+
Every `mobile:` extension the drivers advertise is a first-class command under a
|
|
126
|
+
platform namespace. Flags map 1:1 to the driver's params and coerce to the
|
|
127
|
+
declared type.
|
|
128
|
+
|
|
129
|
+
```sh
|
|
130
|
+
aco ios --help # all XCUITest mobile: extensions
|
|
131
|
+
aco android --help # all UiAutomator2 / Android extensions
|
|
132
|
+
aco ios swipe --direction up
|
|
133
|
+
aco ios scroll --toVisible true --distance 0.5
|
|
134
|
+
aco android shell --command "getprop ro.product.model"
|
|
135
|
+
aco ios <cmd> --help # see each param's type
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
`mobile:` names are snake-cased to subcommands (`mobile: doubleTap` →
|
|
139
|
+
`aco ios double-tap`); `--<param>` flags keep the driver's camelCase names.
|
|
140
|
+
|
|
141
|
+
```sh
|
|
142
|
+
aco mobile list # what the connected driver actually advertises
|
|
143
|
+
aco mobile call --name "mobile: swipe" --args '{"direction":"up"}' # unvalidated escape hatch
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Inspect / stop sessions
|
|
147
|
+
|
|
148
|
+
```sh
|
|
149
|
+
aco session list # startedAt, platform, pid, alive, url, sessionId
|
|
150
|
+
aco session list --json
|
|
151
|
+
aco session list --prune # delete records for dead servers / crashed children
|
|
152
|
+
|
|
153
|
+
aco session stop # stop the latest live session
|
|
154
|
+
aco session stop --session <sid> # stop a specific one
|
|
155
|
+
aco session stop --all # stop every stored session
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Troubleshooting
|
|
159
|
+
|
|
160
|
+
- **`Insecure feature 'adb_shell' not enabled`** when calling `mobile: shell` on
|
|
161
|
+
Android: start the session with `--cap appium:allowInsecure='["adb_shell"]'`.
|
|
162
|
+
- **`appium not found on PATH`** when running `aco session start`: install Appium
|
|
163
|
+
(`npm i -g appium`) and verify `which appium` resolves.
|
|
164
|
+
- **`unknown command (script)`** from `aco mobile call` or a generated
|
|
165
|
+
`aco ios`/`aco android` command: the connected server runs a driver version
|
|
166
|
+
that does not expose that extension. Run `aco mobile list` to see what it
|
|
167
|
+
advertises.
|
|
168
|
+
|
|
169
|
+
## Development
|
|
170
|
+
|
|
171
|
+
Tool versions are pinned in `mise.toml` -- install [mise](https://mise.jdx.dev)
|
|
172
|
+
and run `mise install` to match.
|
|
173
|
+
|
|
174
|
+
```sh
|
|
175
|
+
pnpm install
|
|
176
|
+
pnpm dev --help # one-shot run via tsx
|
|
177
|
+
pnpm dev:watch --help # rerun on file changes
|
|
178
|
+
pnpm typecheck # tsc --noEmit
|
|
179
|
+
pnpm test # vitest run
|
|
180
|
+
pnpm gen:extensions # regenerate src/data/extensions-*.json from driver source
|
|
181
|
+
pnpm build # produce dist/cli.js via tsup
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
See `CLAUDE.md` for the driver-snapshot workflow and the rules for adding new
|
|
185
|
+
`mobile:` wrappers.
|
|
186
|
+
|
|
187
|
+
## Testing
|
|
188
|
+
|
|
189
|
+
An example Expo-based AUT (App Under Test) lives under [`aut/`](./aut/), with one
|
|
190
|
+
screen per `aco` command family.
|
|
191
|
+
|
|
192
|
+
```sh
|
|
193
|
+
pnpm aut:install # install AUT deps (~200MB, one-time)
|
|
194
|
+
pnpm aut:prebuild # generate aut/ios and aut/android
|
|
195
|
+
pnpm aut:build:ios # build .app for the iOS Simulator
|
|
196
|
+
pnpm aut:build:android # build .apk for an Android emulator
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
See [`aut/README.md`](./aut/README.md) for the screen-to-command map.
|
|
200
|
+
|
|
201
|
+
## License
|
|
202
|
+
|
|
203
|
+
MIT
|