@testingbot/cli 1.0.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.
Files changed (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +375 -0
  3. package/dist/auth.d.ts +16 -0
  4. package/dist/auth.d.ts.map +1 -0
  5. package/dist/auth.js +47 -0
  6. package/dist/cli.d.ts +4 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +329 -0
  9. package/dist/index.d.ts +3 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +8 -0
  12. package/dist/logger.d.ts +4 -0
  13. package/dist/logger.d.ts.map +1 -0
  14. package/dist/logger.js +20 -0
  15. package/dist/models/credentials.d.ts +9 -0
  16. package/dist/models/credentials.d.ts.map +1 -0
  17. package/dist/models/credentials.js +20 -0
  18. package/dist/models/espresso_options.d.ts +116 -0
  19. package/dist/models/espresso_options.d.ts.map +1 -0
  20. package/dist/models/espresso_options.js +194 -0
  21. package/dist/models/maestro_options.d.ts +101 -0
  22. package/dist/models/maestro_options.d.ts.map +1 -0
  23. package/dist/models/maestro_options.js +176 -0
  24. package/dist/models/testingbot_error.d.ts +3 -0
  25. package/dist/models/testingbot_error.d.ts.map +1 -0
  26. package/dist/models/testingbot_error.js +5 -0
  27. package/dist/models/xcuitest_options.d.ts +88 -0
  28. package/dist/models/xcuitest_options.d.ts.map +1 -0
  29. package/dist/models/xcuitest_options.js +146 -0
  30. package/dist/providers/espresso.d.ts +67 -0
  31. package/dist/providers/espresso.d.ts.map +1 -0
  32. package/dist/providers/espresso.js +527 -0
  33. package/dist/providers/login.d.ts +18 -0
  34. package/dist/providers/login.d.ts.map +1 -0
  35. package/dist/providers/login.js +284 -0
  36. package/dist/providers/maestro.d.ts +92 -0
  37. package/dist/providers/maestro.d.ts.map +1 -0
  38. package/dist/providers/maestro.js +1010 -0
  39. package/dist/providers/xcuitest.d.ts +67 -0
  40. package/dist/providers/xcuitest.d.ts.map +1 -0
  41. package/dist/providers/xcuitest.js +529 -0
  42. package/dist/upload.d.ts +21 -0
  43. package/dist/upload.d.ts.map +1 -0
  44. package/dist/upload.js +94 -0
  45. package/dist/utils/file-type-detector.d.ts +15 -0
  46. package/dist/utils/file-type-detector.d.ts.map +1 -0
  47. package/dist/utils/file-type-detector.js +38 -0
  48. package/dist/utils/platform.d.ts +26 -0
  49. package/dist/utils/platform.d.ts.map +1 -0
  50. package/dist/utils/platform.js +58 -0
  51. package/dist/utils.d.ts +15 -0
  52. package/dist/utils.d.ts.map +1 -0
  53. package/dist/utils.js +48 -0
  54. package/package.json +78 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) TestingBot
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,375 @@
1
+ [![Run Tests](https://github.com/testingbot/testingbotctl/actions/workflows/test.yml/badge.svg)](https://github.com/testingbot/testingbotctl/actions/workflows/test.yml)
2
+
3
+ # TestingBot CLI
4
+
5
+ CLI tool to run Espresso, XCUITest and Maestro tests on [TestingBot's](https://testingbot.com) cloud infrastructure.
6
+
7
+ ## Installation
8
+
9
+ ```sh
10
+ npm install -g @testingbot/cli
11
+ ```
12
+
13
+ **Requirements:** NodeJS 20 or higher
14
+
15
+ ## Authentication
16
+
17
+ The CLI requires TestingBot API credentials. You can authenticate in several ways:
18
+
19
+ ### Browser Login (Recommended)
20
+
21
+ ```sh
22
+ testingbot login
23
+ ```
24
+
25
+ This opens your browser for authentication. After logging in, your credentials are saved to `~/.testingbot`.
26
+
27
+ ### Other Methods
28
+
29
+ - **Command-line options**: `--api-key` and `--api-secret`
30
+ - **Environment variables**: `TB_KEY` and `TB_SECRET`
31
+ - **Config file**: Create `~/.testingbot` with content `key:secret`
32
+
33
+ ## Commands
34
+
35
+ ### Maestro
36
+
37
+ Run Maestro UI tests on real devices and emulators/simulators.
38
+
39
+ ```sh
40
+ testingbot maestro <app> <flows...> [options]
41
+ ```
42
+
43
+ **Arguments:**
44
+ - `app` - Path to your app file (.apk, .ipa, .app, or .zip)
45
+ - `flows` - One or more paths to flow files (.yaml/.yml), directories, .zip files, or glob patterns
46
+
47
+ **Device Options:**
48
+
49
+ | Option | Description |
50
+ |--------|-------------|
51
+ | `--device <name>` | Device name (e.g., "Pixel 9", "iPhone 16") |
52
+ | `--platform <name>` | Platform: Android or iOS |
53
+ | `--deviceVersion <version>` | OS version (e.g., "14", "17.2") |
54
+ | `--real-device` | Use a real device instead of emulator/simulator |
55
+ | `--orientation <orientation>` | Screen orientation: PORTRAIT or LANDSCAPE |
56
+ | `--device-locale <locale>` | Device locale (e.g., "en_US", "de_DE") |
57
+ | `--timezone <timezone>` | Timezone (e.g., "America/New_York", "Europe/London") |
58
+
59
+ **Test Configuration:**
60
+
61
+ | Option | Description |
62
+ |--------|-------------|
63
+ | `--name <name>` | Test name for dashboard identification |
64
+ | `--build <build>` | Build identifier for grouping test runs |
65
+ | `--include-tags <tags>` | Only run flows with these tags (comma-separated) |
66
+ | `--exclude-tags <tags>` | Exclude flows with these tags (comma-separated) |
67
+ | `-e, --env <KEY=VALUE>` | Environment variable for flows (can be repeated) |
68
+ | `--maestro-version <version>` | Maestro version to use (e.g., "2.0.10") |
69
+
70
+ **Network & Location:**
71
+
72
+ | Option | Description |
73
+ |--------|-------------|
74
+ | `--throttle-network <speed>` | Network throttling: 4G, 3G, Edge, airplane, or disable |
75
+ | `--geo-country-code <code>` | Geographic IP location (ISO country code, e.g., "US", "DE") |
76
+
77
+ **Output Options:**
78
+
79
+ | Option | Description |
80
+ |--------|-------------|
81
+ | `--async` | Start tests and exit without waiting for results |
82
+ | `-q, --quiet` | Suppress progress output |
83
+ | `--report <format>` | Download report after completion: html or junit |
84
+ | `--report-output-dir <path>` | Directory to save reports (required with --report) |
85
+ | `--download-artifacts` | Download test artifacts (logs, screenshots, video) |
86
+ | `--artifacts-output-dir <path>` | Directory to save artifacts zip (defaults to current directory) |
87
+
88
+ **Examples:**
89
+
90
+ ```sh
91
+ # Basic usage
92
+ testingbot maestro app.apk ./flows
93
+
94
+ # Multiple flow directories
95
+ testingbot maestro app.apk ./flows/smoke ./flows/regression ./flows/e2e
96
+
97
+ # With device selection
98
+ testingbot maestro app.apk ./flows --device "Pixel 8" --deviceVersion "14"
99
+
100
+ # iOS app on real device with tags
101
+ testingbot maestro app.ipa ./flows --platform iOS --real-device --include-tags "smoke,regression"
102
+
103
+ # With environment variables
104
+ testingbot maestro app.apk ./flows -e API_URL=https://staging.example.com -e API_KEY=secret
105
+
106
+ # Download JUnit report
107
+ testingbot maestro app.apk ./flows --report junit --report-output-dir ./reports
108
+
109
+ # Download all artifacts (logs, screenshots, video)
110
+ testingbot maestro app.apk ./flows --download-artifacts --build "build-123"
111
+
112
+ # Run in background (async)
113
+ testingbot maestro app.apk ./flows --async
114
+ ```
115
+
116
+ ---
117
+
118
+ ### Espresso
119
+
120
+ Run Android Espresso tests on real devices and emulators.
121
+
122
+ ```sh
123
+ testingbot espresso [appFile] [testAppFile] [options]
124
+ ```
125
+
126
+ **Arguments:**
127
+ - `appFile` - Path to application APK file
128
+ - `testAppFile` - Path to test APK file containing Espresso tests
129
+
130
+ **Device Options:**
131
+
132
+ | Option | Description |
133
+ |--------|-------------|
134
+ | `--app <path>` | Path to application APK file |
135
+ | `--test-app <path>` | Path to test APK file |
136
+ | `--device <name>` | Device name (e.g., "Pixel 6", "Samsung.*") |
137
+ | `--platform-version <version>` | Android OS version (e.g., "12", "13", "14") |
138
+ | `--real-device` | Use a real device instead of an emulator |
139
+ | `--tablet-only` | Only allocate tablet devices |
140
+ | `--phone-only` | Only allocate phone devices |
141
+ | `--locale <locale>` | Device locale (e.g., "en_US", "de_DE") |
142
+ | `--timezone <timezone>` | Timezone (e.g., "America/New_York", "Europe/London") |
143
+
144
+ **Test Configuration:**
145
+
146
+ | Option | Description |
147
+ |--------|-------------|
148
+ | `--name <name>` | Test name for dashboard identification |
149
+ | `--build <build>` | Build identifier for grouping test runs |
150
+ | `--test-runner <runner>` | Custom test instrumentation runner |
151
+ | `--language <lang>` | App language (ISO 639-1 code, e.g., "en", "fr", "de") |
152
+
153
+ **Test Filtering:**
154
+
155
+ | Option | Description |
156
+ |--------|-------------|
157
+ | `--class <classes>` | Run tests in specific classes (comma-separated fully qualified names) |
158
+ | `--not-class <classes>` | Exclude tests in specific classes |
159
+ | `--package <packages>` | Run tests in specific packages (comma-separated) |
160
+ | `--not-package <packages>` | Exclude tests in specific packages |
161
+ | `--annotation <annotations>` | Run tests with specific annotations (comma-separated) |
162
+ | `--not-annotation <annotations>` | Exclude tests with specific annotations |
163
+ | `--size <sizes>` | Run tests by size: small, medium, large (comma-separated) |
164
+
165
+ **Network & Location:**
166
+
167
+ | Option | Description |
168
+ |--------|-------------|
169
+ | `--throttle-network <speed>` | Network throttling: 4G, 3G, Edge, or airplane |
170
+ | `--geo-location <code>` | Geographic IP location (ISO country code, e.g., "US", "DE") |
171
+
172
+ **Output Options:**
173
+
174
+ | Option | Description |
175
+ |--------|-------------|
176
+ | `--async` | Start tests and exit without waiting for results |
177
+ | `-q, --quiet` | Suppress progress output |
178
+ | `--report <format>` | Download report after completion: html or junit |
179
+ | `--report-output-dir <path>` | Directory to save reports (required with --report) |
180
+
181
+ **Examples:**
182
+
183
+ ```sh
184
+ # Basic usage with positional arguments
185
+ testingbot espresso app.apk app-test.apk --device "Pixel 8"
186
+
187
+ # Using named options
188
+ testingbot espresso --app app.apk --test-app app-test.apk --device "Pixel 8"
189
+
190
+ # Real device with specific Android version
191
+ testingbot espresso app.apk app-test.apk \
192
+ --device "Samsung Galaxy S24" \
193
+ --platform-version "14" \
194
+ --real-device
195
+
196
+ # Run specific test classes
197
+ testingbot espresso app.apk app-test.apk \
198
+ --device "Pixel 8" \
199
+ --class "com.example.LoginTest,com.example.HomeTest"
200
+
201
+ # Run tests with annotations
202
+ testingbot espresso app.apk app-test.apk \
203
+ --device "Pixel 8" \
204
+ --annotation "com.example.SmokeTest" \
205
+ --size "small,medium"
206
+
207
+ # With network throttling and geolocation
208
+ testingbot espresso app.apk app-test.apk \
209
+ --device "Pixel 8" \
210
+ --throttle-network "3G" \
211
+ --geo-location "DE" \
212
+ --language "de"
213
+
214
+ # Download JUnit report
215
+ testingbot espresso app.apk app-test.apk \
216
+ --device "Pixel 8" \
217
+ --report junit \
218
+ --report-output-dir ./reports
219
+ ```
220
+
221
+ ---
222
+
223
+ ### XCUITest
224
+
225
+ Run iOS XCUITest tests on real devices and simulators.
226
+
227
+ ```sh
228
+ testingbot xcuitest [appFile] [testAppFile] [options]
229
+ ```
230
+
231
+ **Arguments:**
232
+ - `appFile` - Path to application IPA file
233
+ - `testAppFile` - Path to test ZIP file containing XCUITests
234
+
235
+ **Device Options:**
236
+
237
+ | Option | Description |
238
+ |--------|-------------|
239
+ | `--app <path>` | Path to application IPA file |
240
+ | `--test-app <path>` | Path to test ZIP file |
241
+ | `--device <name>` | Device name (e.g., "iPhone 15", "iPad.*") |
242
+ | `--platform-version <version>` | iOS version (e.g., "17.0", "18.2") |
243
+ | `--real-device` | Use a real device instead of a simulator |
244
+ | `--tablet-only` | Only allocate tablet devices |
245
+ | `--phone-only` | Only allocate phone devices |
246
+ | `--orientation <orientation>` | Screen orientation: PORTRAIT or LANDSCAPE |
247
+ | `--locale <locale>` | Device locale (e.g., "DE", "US") |
248
+ | `--timezone <timezone>` | Timezone (e.g., "America/New_York", "Europe/London") |
249
+
250
+ **Test Configuration:**
251
+
252
+ | Option | Description |
253
+ |--------|-------------|
254
+ | `--name <name>` | Test name for dashboard identification |
255
+ | `--build <build>` | Build identifier for grouping test runs |
256
+ | `--language <lang>` | App language (ISO 639-1 code, e.g., "en", "fr", "de") |
257
+
258
+ **Network & Location:**
259
+
260
+ | Option | Description |
261
+ |--------|-------------|
262
+ | `--throttle-network <speed>` | Network throttling: 4G, 3G, Edge, or airplane |
263
+ | `--geo-location <code>` | Geographic IP location (ISO country code, e.g., "US", "DE") |
264
+
265
+ **Output Options:**
266
+
267
+ | Option | Description |
268
+ |--------|-------------|
269
+ | `--async` | Start tests and exit without waiting for results |
270
+ | `-q, --quiet` | Suppress progress output |
271
+ | `--report <format>` | Download report after completion: html or junit |
272
+ | `--report-output-dir <path>` | Directory to save reports (required with --report) |
273
+
274
+ **Examples:**
275
+
276
+ ```sh
277
+ # Basic usage with positional arguments
278
+ testingbot xcuitest app.ipa app-test.zip --device "iPhone 16"
279
+
280
+ # Using named options
281
+ testingbot xcuitest --app app.ipa --test-app app-test.zip --device "iPhone 16"
282
+
283
+ # Real device with specific iOS version
284
+ testingbot xcuitest app.ipa app-test.zip \
285
+ --device "iPhone 15 Pro" \
286
+ --platform-version "17.2" \
287
+ --real-device
288
+
289
+ # iPad in landscape mode
290
+ testingbot xcuitest app.ipa app-test.zip \
291
+ --device "iPad Pro" \
292
+ --tablet-only \
293
+ --orientation LANDSCAPE
294
+
295
+ # With localization settings
296
+ testingbot xcuitest app.ipa app-test.zip \
297
+ --device "iPhone 16" \
298
+ --locale "DE" \
299
+ --language "de" \
300
+ --timezone "Europe/Berlin"
301
+
302
+ # With network throttling and geolocation
303
+ testingbot xcuitest app.ipa app-test.zip \
304
+ --device "iPhone 16" \
305
+ --throttle-network "3G" \
306
+ --geo-location "DE"
307
+
308
+ # Download HTML report
309
+ testingbot xcuitest app.ipa app-test.zip \
310
+ --device "iPhone 16" \
311
+ --report html \
312
+ --report-output-dir ./reports
313
+
314
+ # Run in background
315
+ testingbot xcuitest app.ipa app-test.zip \
316
+ --device "iPhone 16" \
317
+ --async
318
+ ```
319
+
320
+ ---
321
+
322
+ ## Common Features
323
+
324
+ ### Real-time Progress
325
+
326
+ By default, the CLI shows real-time progress updates including:
327
+ - Test status updates
328
+ - Device allocation status
329
+ - Live output from Maestro flows
330
+
331
+ Use `--quiet` to suppress progress output.
332
+
333
+ ### Graceful Shutdown
334
+
335
+ Press `Ctrl+C` to gracefully stop running tests. The CLI will:
336
+ 1. Stop all active test runs on TestingBot
337
+ 2. Clean up resources
338
+ 3. Exit with appropriate status code
339
+
340
+ Press `Ctrl+C` twice to force exit immediately.
341
+
342
+ ### Report Downloads
343
+
344
+ All test frameworks support downloading reports after completion:
345
+
346
+ ```sh
347
+ # JUnit XML format (for CI integration)
348
+ --report junit --report-output-dir ./reports
349
+
350
+ # HTML format (for human viewing)
351
+ --report html --report-output-dir ./reports
352
+ ```
353
+
354
+ ### Artifact Downloads (Maestro only)
355
+
356
+ Download all test artifacts including logs, screenshots, and video recordings:
357
+
358
+ ```sh
359
+ testingbot maestro app.apk ./flows --download-artifacts --build "my-build"
360
+ ```
361
+
362
+ Artifacts are saved as a zip file named after the `--build` value (or with a timestamp if not provided).
363
+
364
+ ## Exit Codes
365
+
366
+ - `0` - All tests passed
367
+ - `1` - One or more tests failed or an error occurred
368
+
369
+ ## Documentation
370
+
371
+ For more information, visit [TestingBot Documentation](https://testingbot.com/support).
372
+
373
+ ## License
374
+
375
+ MIT
package/dist/auth.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ import Credentials from './models/credentials';
2
+ export interface AuthOptions {
3
+ apiKey?: string;
4
+ apiSecret?: string;
5
+ }
6
+ export default class Auth {
7
+ /**
8
+ * Get credentials from multiple sources in order of precedence:
9
+ * 1. CLI options (--api-key, --api-secret)
10
+ * 2. Environment variables (TB_KEY, TB_SECRET)
11
+ * 3. ~/.testingbot file
12
+ */
13
+ static getCredentials(options?: AuthOptions): Promise<Credentials | null>;
14
+ private static getCredentialsFromFile;
15
+ }
16
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAGA,OAAO,WAAW,MAAM,sBAAsB,CAAC;AAE/C,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,CAAC,OAAO,OAAO,IAAI;IACvB;;;;;OAKG;WACiB,cAAc,CAChC,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;mBAiBT,sBAAsB;CAgB5C"}
package/dist/auth.js ADDED
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const node_fs_1 = __importDefault(require("node:fs"));
7
+ const node_os_1 = __importDefault(require("node:os"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const credentials_1 = __importDefault(require("./models/credentials"));
10
+ class Auth {
11
+ /**
12
+ * Get credentials from multiple sources in order of precedence:
13
+ * 1. CLI options (--api-key, --api-secret)
14
+ * 2. Environment variables (TB_KEY, TB_SECRET)
15
+ * 3. ~/.testingbot file
16
+ */
17
+ static async getCredentials(options) {
18
+ // 1. Check CLI options first (highest precedence)
19
+ if (options?.apiKey && options?.apiSecret) {
20
+ return new credentials_1.default(options.apiKey, options.apiSecret);
21
+ }
22
+ // 2. Check environment variables
23
+ const envKey = process.env.TB_KEY;
24
+ const envSecret = process.env.TB_SECRET;
25
+ if (envKey && envSecret) {
26
+ return new credentials_1.default(envKey, envSecret);
27
+ }
28
+ // 3. Fall back to ~/.testingbot file
29
+ return this.getCredentialsFromFile();
30
+ }
31
+ static async getCredentialsFromFile() {
32
+ try {
33
+ const savedCredentials = (await node_fs_1.default.promises.readFile(node_path_1.default.join(node_os_1.default.homedir(), '.testingbot'))).toString();
34
+ if (savedCredentials.length > 0) {
35
+ const [userName, accessKey] = savedCredentials.trim().split(':');
36
+ if (userName && accessKey) {
37
+ return new credentials_1.default(userName, accessKey);
38
+ }
39
+ }
40
+ return null;
41
+ }
42
+ catch {
43
+ return null;
44
+ }
45
+ }
46
+ }
47
+ exports.default = Auth;
package/dist/cli.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { Command } from 'commander';
2
+ declare const program: Command;
3
+ export default program;
4
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwBpC,QAAA,MAAM,OAAO,SAAgB,CAAC;AA6e9B,eAAe,OAAO,CAAC"}