@testingbot/cli 1.0.7 → 1.0.9
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/README.md +29 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +79 -46
- package/dist/config/constants.d.ts +15 -0
- package/dist/config/constants.d.ts.map +1 -0
- package/dist/config/constants.js +17 -0
- package/dist/index.js +2 -0
- package/dist/models/espresso_options.d.ts +7 -0
- package/dist/models/espresso_options.d.ts.map +1 -1
- package/dist/models/espresso_options.js +18 -0
- package/dist/models/maestro_options.d.ts +20 -2
- package/dist/models/maestro_options.d.ts.map +1 -1
- package/dist/models/maestro_options.js +38 -1
- package/dist/models/xcuitest_options.d.ts +7 -0
- package/dist/models/xcuitest_options.d.ts.map +1 -1
- package/dist/models/xcuitest_options.js +18 -0
- package/dist/providers/base_provider.d.ts +28 -2
- package/dist/providers/base_provider.d.ts.map +1 -1
- package/dist/providers/base_provider.js +70 -2
- package/dist/providers/espresso.d.ts +1 -0
- package/dist/providers/espresso.d.ts.map +1 -1
- package/dist/providers/espresso.js +82 -35
- package/dist/providers/maestro.d.ts +31 -0
- package/dist/providers/maestro.d.ts.map +1 -1
- package/dist/providers/maestro.js +399 -149
- package/dist/providers/xcuitest.d.ts +1 -0
- package/dist/providers/xcuitest.d.ts.map +1 -1
- package/dist/providers/xcuitest.js +79 -35
- package/dist/ui/banner.d.ts +3 -0
- package/dist/ui/banner.d.ts.map +1 -0
- package/dist/ui/banner.js +82 -0
- package/dist/ui/spinner.d.ts +32 -0
- package/dist/ui/spinner.d.ts.map +1 -0
- package/dist/ui/spinner.js +92 -0
- package/dist/ui/terminal-title.d.ts +8 -0
- package/dist/ui/terminal-title.d.ts.map +1 -0
- package/dist/ui/terminal-title.js +57 -0
- package/dist/upload.d.ts +4 -0
- package/dist/upload.d.ts.map +1 -1
- package/dist/upload.js +70 -12
- package/dist/utils/connectivity.js +5 -3
- package/dist/utils.d.ts +6 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +10 -0
- package/package.json +5 -3
|
@@ -7,15 +7,19 @@ const logger_1 = __importDefault(require("../logger"));
|
|
|
7
7
|
const axios_1 = __importDefault(require("axios"));
|
|
8
8
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
9
|
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
10
11
|
const socket_io_client_1 = require("socket.io-client");
|
|
11
12
|
const testingbot_error_1 = __importDefault(require("../models/testingbot_error"));
|
|
12
13
|
const utils_1 = __importDefault(require("../utils"));
|
|
13
14
|
const base_provider_1 = __importDefault(require("./base_provider"));
|
|
15
|
+
const terminal_title_1 = require("../ui/terminal-title");
|
|
16
|
+
const constants_1 = require("../config/constants");
|
|
14
17
|
class Espresso extends base_provider_1.default {
|
|
15
18
|
URL = 'https://api.testingbot.com/v1/app-automate/espresso';
|
|
16
19
|
socket = null;
|
|
17
20
|
updateServer = null;
|
|
18
21
|
updateKey = null;
|
|
22
|
+
socketFallbackWarned = false;
|
|
19
23
|
constructor(credentials, options) {
|
|
20
24
|
super(credentials, options);
|
|
21
25
|
}
|
|
@@ -77,19 +81,27 @@ class Espresso extends base_provider_1.default {
|
|
|
77
81
|
return { success: true, runs: [] };
|
|
78
82
|
}
|
|
79
83
|
try {
|
|
84
|
+
(0, terminal_title_1.setTitle)('espresso');
|
|
80
85
|
// Quick connectivity check before starting uploads
|
|
81
86
|
await this.ensureConnectivity();
|
|
82
87
|
if (!this.options.quiet) {
|
|
83
88
|
logger_1.default.info('Uploading Espresso App');
|
|
84
89
|
}
|
|
90
|
+
(0, terminal_title_1.setTitle)('espresso · uploading app');
|
|
85
91
|
await this.uploadApp();
|
|
86
92
|
if (!this.options.quiet) {
|
|
87
93
|
logger_1.default.info('Uploading Espresso Test App');
|
|
88
94
|
}
|
|
95
|
+
(0, terminal_title_1.setTitle)('espresso · uploading test app');
|
|
89
96
|
await this.uploadTestApp();
|
|
97
|
+
if (this.options.tunnel && this.options.async) {
|
|
98
|
+
throw new testingbot_error_1.default('Cannot use --tunnel with --async mode. The tunnel would close when the CLI exits. Use a standalone tunnel instead.');
|
|
99
|
+
}
|
|
100
|
+
await this.startTunnel();
|
|
90
101
|
if (!this.options.quiet) {
|
|
91
102
|
logger_1.default.info('Running Espresso Tests');
|
|
92
103
|
}
|
|
104
|
+
(0, terminal_title_1.setTitle)('espresso · queued');
|
|
93
105
|
await this.runTests();
|
|
94
106
|
if (this.options.async) {
|
|
95
107
|
if (!this.options.quiet) {
|
|
@@ -108,12 +120,16 @@ class Espresso extends base_provider_1.default {
|
|
|
108
120
|
// Clean up
|
|
109
121
|
this.disconnectFromUpdateServer();
|
|
110
122
|
this.removeSignalHandlers();
|
|
123
|
+
await this.stopTunnel();
|
|
111
124
|
return result;
|
|
112
125
|
}
|
|
113
126
|
catch (error) {
|
|
114
127
|
// Clean up on error
|
|
128
|
+
this.spinner.stop();
|
|
115
129
|
this.disconnectFromUpdateServer();
|
|
116
130
|
this.removeSignalHandlers();
|
|
131
|
+
await this.stopTunnel();
|
|
132
|
+
(0, terminal_title_1.setTitle)('espresso · ✘ error');
|
|
117
133
|
logger_1.default.error(error instanceof Error ? error.message : error);
|
|
118
134
|
if (error instanceof Error && error.cause) {
|
|
119
135
|
const causeMessage = this.extractErrorMessage(error.cause);
|
|
@@ -165,7 +181,7 @@ class Espresso extends base_provider_1.default {
|
|
|
165
181
|
username: this.credentials.userName,
|
|
166
182
|
password: this.credentials.accessKey,
|
|
167
183
|
},
|
|
168
|
-
timeout:
|
|
184
|
+
timeout: constants_1.HTTP.TIMEOUT_MS,
|
|
169
185
|
});
|
|
170
186
|
// Check for version update notification
|
|
171
187
|
const latestVersion = response.headers?.['x-testingbotctl-version'];
|
|
@@ -202,7 +218,7 @@ class Espresso extends base_provider_1.default {
|
|
|
202
218
|
username: this.credentials.userName,
|
|
203
219
|
password: this.credentials.accessKey,
|
|
204
220
|
},
|
|
205
|
-
timeout:
|
|
221
|
+
timeout: constants_1.HTTP.TIMEOUT_MS,
|
|
206
222
|
});
|
|
207
223
|
// Check for version update notification
|
|
208
224
|
const latestVersion = response.headers?.['x-testingbotctl-version'];
|
|
@@ -215,10 +231,11 @@ class Espresso extends base_provider_1.default {
|
|
|
215
231
|
}
|
|
216
232
|
}
|
|
217
233
|
async waitForCompletion() {
|
|
218
|
-
let attempts = 0;
|
|
219
234
|
const startTime = Date.now();
|
|
220
235
|
const previousStatus = new Map();
|
|
221
|
-
|
|
236
|
+
let pollInterval = this.MIN_POLL_INTERVAL_MS;
|
|
237
|
+
let previousSignature = null;
|
|
238
|
+
while (true) {
|
|
222
239
|
if (this.isShuttingDown) {
|
|
223
240
|
throw new testingbot_error_1.default('Test run cancelled by user');
|
|
224
241
|
}
|
|
@@ -231,24 +248,35 @@ class Espresso extends base_provider_1.default {
|
|
|
231
248
|
if (!this.options.quiet) {
|
|
232
249
|
this.displayRunStatus(status.runs, startTime, previousStatus);
|
|
233
250
|
}
|
|
251
|
+
// Terminal-tab title reflects the coarse phase, regardless of quiet.
|
|
252
|
+
const running = status.runs.find((r) => r.status === 'READY');
|
|
253
|
+
if (running) {
|
|
254
|
+
const device = running.environment?.name || running.capabilities.deviceName;
|
|
255
|
+
(0, terminal_title_1.setTitle)(`espresso · running · ${device}`);
|
|
256
|
+
}
|
|
234
257
|
if (status.completed) {
|
|
235
|
-
//
|
|
258
|
+
// Stop the spinner and print final status
|
|
236
259
|
if (!this.options.quiet) {
|
|
237
|
-
this.
|
|
260
|
+
this.spinner.stop();
|
|
238
261
|
for (const run of status.runs) {
|
|
239
|
-
const
|
|
240
|
-
const
|
|
241
|
-
|
|
262
|
+
const passed = run.success === 1;
|
|
263
|
+
const symbol = passed ? picocolors_1.default.green('✔') : picocolors_1.default.red('✘');
|
|
264
|
+
const statusText = passed
|
|
265
|
+
? picocolors_1.default.green('Test completed successfully')
|
|
266
|
+
: picocolors_1.default.red('Test failed');
|
|
267
|
+
console.log(` ${symbol} Run ${run.id} ${picocolors_1.default.dim(`(${this.getRunDisplayName(run)})`)}: ${statusText}`);
|
|
242
268
|
}
|
|
243
269
|
}
|
|
244
270
|
const allSucceeded = status.runs.every((run) => run.success === 1);
|
|
245
271
|
if (allSucceeded) {
|
|
272
|
+
(0, terminal_title_1.setTitle)('espresso · ✔ passed');
|
|
246
273
|
if (!this.options.quiet) {
|
|
247
274
|
logger_1.default.info('All tests completed successfully!');
|
|
248
275
|
}
|
|
249
276
|
}
|
|
250
277
|
else {
|
|
251
278
|
const failedRuns = status.runs.filter((run) => run.success !== 1);
|
|
279
|
+
(0, terminal_title_1.setTitle)(`espresso · ✘ ${failedRuns.length} failed`);
|
|
252
280
|
logger_1.default.error(`${failedRuns.length} test run(s) failed:`);
|
|
253
281
|
for (const run of failedRuns) {
|
|
254
282
|
logger_1.default.error(` - Run ${run.id} (${this.getRunDisplayName(run)}): ${run.report || 'No report available'}`);
|
|
@@ -263,32 +291,47 @@ class Espresso extends base_provider_1.default {
|
|
|
263
291
|
runs: status.runs,
|
|
264
292
|
};
|
|
265
293
|
}
|
|
266
|
-
|
|
267
|
-
|
|
294
|
+
// Checked after getStatus() so a run that completes during the final
|
|
295
|
+
// sleep is returned as success on the next iteration instead of being
|
|
296
|
+
// misreported as a timeout.
|
|
297
|
+
if (Date.now() - startTime >= this.MAX_POLL_DURATION_MS) {
|
|
298
|
+
throw new testingbot_error_1.default(`Test timed out after ${this.MAX_POLL_DURATION_MS / 1000 / 60} minutes`);
|
|
299
|
+
}
|
|
300
|
+
const signature = JSON.stringify(status.runs.map((r) => [r.id, r.status, r.success]));
|
|
301
|
+
const changed = signature !== previousSignature;
|
|
302
|
+
previousSignature = signature;
|
|
303
|
+
pollInterval = this.computeNextPollInterval(pollInterval, changed);
|
|
304
|
+
await this.sleep(pollInterval);
|
|
268
305
|
}
|
|
269
|
-
throw new testingbot_error_1.default(`Test timed out after ${(this.MAX_POLL_ATTEMPTS * this.POLL_INTERVAL_MS) / 1000 / 60} minutes`);
|
|
270
306
|
}
|
|
271
307
|
displayRunStatus(runs, startTime, previousStatus) {
|
|
272
308
|
const elapsedSeconds = Math.floor((Date.now() - startTime) / 1000);
|
|
273
309
|
const elapsedStr = this.formatElapsedTime(elapsedSeconds);
|
|
310
|
+
const activeMessages = [];
|
|
274
311
|
for (const run of runs) {
|
|
275
312
|
const prevStatus = previousStatus.get(run.id);
|
|
276
313
|
const statusChanged = prevStatus !== run.status;
|
|
277
|
-
if (statusChanged &&
|
|
278
|
-
prevStatus &&
|
|
279
|
-
(prevStatus === 'WAITING' || prevStatus === 'READY')) {
|
|
280
|
-
this.clearLine();
|
|
281
|
-
}
|
|
282
314
|
previousStatus.set(run.id, run.status);
|
|
283
315
|
const statusInfo = this.getStatusInfo(run.status);
|
|
284
316
|
if (run.status === 'WAITING' || run.status === 'READY') {
|
|
285
|
-
const
|
|
286
|
-
|
|
317
|
+
const label = run.status === 'WAITING'
|
|
318
|
+
? picocolors_1.default.yellow(statusInfo.text)
|
|
319
|
+
: picocolors_1.default.cyan(statusInfo.text);
|
|
320
|
+
activeMessages.push(`${label} ${picocolors_1.default.dim(`• Run ${run.id} (${this.getRunDisplayName(run)}) • ${elapsedStr}`)}`);
|
|
287
321
|
}
|
|
288
322
|
else if (statusChanged) {
|
|
289
|
-
|
|
323
|
+
// Transitioned to a terminal state — print a permanent line above the
|
|
324
|
+
// spinner without disturbing its animation below.
|
|
325
|
+
this.spinner.clearLine();
|
|
326
|
+
console.log(` ${statusInfo.symbol} Run ${run.id} ${picocolors_1.default.dim(`(${this.getRunDisplayName(run)})`)}: ${statusInfo.text}`);
|
|
290
327
|
}
|
|
291
328
|
}
|
|
329
|
+
if (activeMessages.length > 0) {
|
|
330
|
+
this.spinner.setMessage(activeMessages.join(picocolors_1.default.dim(' ┊ ')));
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
this.spinner.stop();
|
|
334
|
+
}
|
|
292
335
|
}
|
|
293
336
|
/**
|
|
294
337
|
* Get the display name for a run, preferring environment.name over capabilities.deviceName
|
|
@@ -300,15 +343,15 @@ class Espresso extends base_provider_1.default {
|
|
|
300
343
|
getStatusInfo(status) {
|
|
301
344
|
switch (status) {
|
|
302
345
|
case 'WAITING':
|
|
303
|
-
return {
|
|
346
|
+
return { symbol: picocolors_1.default.yellow('◐'), text: 'Waiting for test to start' };
|
|
304
347
|
case 'READY':
|
|
305
|
-
return {
|
|
348
|
+
return { symbol: picocolors_1.default.cyan('◑'), text: 'Running test' };
|
|
306
349
|
case 'DONE':
|
|
307
|
-
return {
|
|
350
|
+
return { symbol: picocolors_1.default.green('✔'), text: 'Test has finished running' };
|
|
308
351
|
case 'FAILED':
|
|
309
|
-
return {
|
|
352
|
+
return { symbol: picocolors_1.default.red('✘'), text: 'Test failed' };
|
|
310
353
|
default:
|
|
311
|
-
return {
|
|
354
|
+
return { symbol: picocolors_1.default.dim('?'), text: status };
|
|
312
355
|
}
|
|
313
356
|
}
|
|
314
357
|
async fetchReports() {
|
|
@@ -334,7 +377,7 @@ class Espresso extends base_provider_1.default {
|
|
|
334
377
|
username: this.credentials.userName,
|
|
335
378
|
password: this.credentials.accessKey,
|
|
336
379
|
},
|
|
337
|
-
timeout:
|
|
380
|
+
timeout: constants_1.HTTP.TIMEOUT_MS,
|
|
338
381
|
});
|
|
339
382
|
// Check for version update notification
|
|
340
383
|
const latestVersion = response.headers?.['x-testingbotctl-version'];
|
|
@@ -363,9 +406,9 @@ class Espresso extends base_provider_1.default {
|
|
|
363
406
|
this.socket = (0, socket_io_client_1.io)(this.updateServer, {
|
|
364
407
|
transports: ['websocket'],
|
|
365
408
|
reconnection: true,
|
|
366
|
-
reconnectionAttempts:
|
|
367
|
-
reconnectionDelay:
|
|
368
|
-
timeout:
|
|
409
|
+
reconnectionAttempts: constants_1.SOCKET.RECONNECTION_ATTEMPTS,
|
|
410
|
+
reconnectionDelay: constants_1.SOCKET.RECONNECTION_DELAY_MS,
|
|
411
|
+
timeout: constants_1.SOCKET.TIMEOUT_MS,
|
|
369
412
|
});
|
|
370
413
|
this.socket.on('connect', () => {
|
|
371
414
|
// Join the room for this test run
|
|
@@ -377,8 +420,12 @@ class Espresso extends base_provider_1.default {
|
|
|
377
420
|
this.socket.on('espresso_error', (data) => {
|
|
378
421
|
this.handleEspressoError(data);
|
|
379
422
|
});
|
|
380
|
-
this.socket.on('connect_error', () => {
|
|
381
|
-
|
|
423
|
+
this.socket.on('connect_error', (err) => {
|
|
424
|
+
if (!this.socketFallbackWarned) {
|
|
425
|
+
this.socketFallbackWarned = true;
|
|
426
|
+
logger_1.default.warn('Real-time log stream unavailable, falling back to polling.');
|
|
427
|
+
logger_1.default.debug(`Socket connect_error: ${err?.message ?? 'unknown error'}`);
|
|
428
|
+
}
|
|
382
429
|
this.disconnectFromUpdateServer();
|
|
383
430
|
});
|
|
384
431
|
}
|
|
@@ -397,8 +444,8 @@ class Espresso extends base_provider_1.default {
|
|
|
397
444
|
try {
|
|
398
445
|
const message = JSON.parse(data);
|
|
399
446
|
if (message.payload) {
|
|
400
|
-
// Clear the
|
|
401
|
-
this.clearLine();
|
|
447
|
+
// Clear the spinner line before printing output
|
|
448
|
+
this.spinner.clearLine();
|
|
402
449
|
// Print the Espresso output
|
|
403
450
|
process.stdout.write(message.payload);
|
|
404
451
|
}
|
|
@@ -411,8 +458,8 @@ class Espresso extends base_provider_1.default {
|
|
|
411
458
|
try {
|
|
412
459
|
const message = JSON.parse(data);
|
|
413
460
|
if (message.payload) {
|
|
414
|
-
// Clear the
|
|
415
|
-
this.clearLine();
|
|
461
|
+
// Clear the spinner line before printing error
|
|
462
|
+
this.spinner.clearLine();
|
|
416
463
|
// Print the error output
|
|
417
464
|
process.stderr.write(message.payload);
|
|
418
465
|
}
|
|
@@ -17,6 +17,7 @@ export interface MaestroFlowInfo {
|
|
|
17
17
|
success?: number;
|
|
18
18
|
test_case_id?: number;
|
|
19
19
|
error_messages?: string[];
|
|
20
|
+
assets?: MaestroRunAssets;
|
|
20
21
|
}
|
|
21
22
|
export interface MaestroRunEnvironment {
|
|
22
23
|
device?: string;
|
|
@@ -67,6 +68,11 @@ export default class Maestro extends BaseProvider<MaestroOptions> {
|
|
|
67
68
|
private socket;
|
|
68
69
|
private updateServer;
|
|
69
70
|
private updateKey;
|
|
71
|
+
private socketFallbackWarned;
|
|
72
|
+
private flowAnimationFrame;
|
|
73
|
+
private flowAnimationTimer;
|
|
74
|
+
private latestFlows;
|
|
75
|
+
private latestDisplayedLineCount;
|
|
70
76
|
constructor(credentials: Credentials, options: MaestroOptions);
|
|
71
77
|
private static readonly SUPPORTED_APP_EXTENSIONS;
|
|
72
78
|
private validate;
|
|
@@ -160,17 +166,42 @@ export default class Maestro extends BaseProvider<MaestroOptions> {
|
|
|
160
166
|
private calculateFlowDuration;
|
|
161
167
|
private getTerminalHeight;
|
|
162
168
|
private getMaxDisplayableFlows;
|
|
169
|
+
private getTerminalWidth;
|
|
170
|
+
/**
|
|
171
|
+
* Returns the maximum length of `flow.name` that keeps the rendered row
|
|
172
|
+
* within the current terminal width, so the row does not visually wrap.
|
|
173
|
+
* Wrapped rows break the `\x1b[NA` cursor-up math used by in-place updates,
|
|
174
|
+
* which is what causes the table to repeat instead of refresh in place
|
|
175
|
+
* (e.g. with --shard-split where the API returns long comma-joined names).
|
|
176
|
+
*
|
|
177
|
+
* Row layout is: " {duration:10} {status:10} {name}[ {error}]" — overhead
|
|
178
|
+
* is 23 plain-width chars before `name`. `extra` reserves room for trailing
|
|
179
|
+
* content like a fail-reason suffix.
|
|
180
|
+
*/
|
|
181
|
+
private getMaxNameLength;
|
|
182
|
+
private truncateForRow;
|
|
163
183
|
private getRemainingSummary;
|
|
164
184
|
private displayFlowsWithLimit;
|
|
165
185
|
private displayFlowsTableHeader;
|
|
166
186
|
private displayFlowRow;
|
|
167
187
|
private displayFlowsTable;
|
|
188
|
+
/**
|
|
189
|
+
* Starts the flow-table animation loop. Re-renders the cached flow rows at
|
|
190
|
+
* `FLOW_ANIMATION_MS` so WAITING/RUNNING spinner frames advance between
|
|
191
|
+
* (much slower) polls. Calling while already running is a no-op.
|
|
192
|
+
*/
|
|
193
|
+
private startFlowAnimation;
|
|
194
|
+
private stopFlowAnimation;
|
|
195
|
+
protected stopAnimations(): void;
|
|
168
196
|
private updateFlowsInPlace;
|
|
169
197
|
private fetchReports;
|
|
170
198
|
private getRunDetails;
|
|
171
199
|
private waitForArtifactsSync;
|
|
172
200
|
private downloadFile;
|
|
173
201
|
private generateArtifactZipName;
|
|
202
|
+
private sanitizeFlowDirName;
|
|
203
|
+
private buildFlowDirNames;
|
|
204
|
+
private downloadAssetBundle;
|
|
174
205
|
private downloadArtifacts;
|
|
175
206
|
private createZipFromDirectory;
|
|
176
207
|
private connectToUpdateServer;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"maestro.d.ts","sourceRoot":"","sources":["../../src/providers/maestro.ts"],"names":[],"mappings":"AAAA,OAAO,cAAiC,MAAM,2BAA2B,CAAC;AAE1E,OAAO,WAAW,MAAM,uBAAuB,CAAC;AAahD,OAAO,YAAY,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"maestro.d.ts","sourceRoot":"","sources":["../../src/providers/maestro.ts"],"names":[],"mappings":"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"}
|