@testingbot/cli 1.0.3 → 1.0.5

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/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0BpC,QAAA,MAAM,OAAO,SAAgB,CAAC;AAwkB9B,eAAe,OAAO,CAAC"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0BpC,QAAA,MAAM,OAAO,SAAgB,CAAC;AA6kB9B,eAAe,OAAO,CAAC"}
package/dist/cli.js CHANGED
@@ -1,10 +1,43 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
37
  };
5
38
  Object.defineProperty(exports, "__esModule", { value: true });
6
39
  const commander_1 = require("commander");
7
- const logger_1 = __importDefault(require("./logger"));
40
+ const logger_1 = __importStar(require("./logger"));
8
41
  const auth_1 = __importDefault(require("./auth"));
9
42
  const espresso_1 = __importDefault(require("./providers/espresso"));
10
43
  const espresso_options_1 = __importDefault(require("./models/espresso_options"));
@@ -183,6 +216,7 @@ const maestroCommand = program
183
216
  // Authentication
184
217
  .option('--api-key <key>', 'TestingBot API key.')
185
218
  .option('--api-secret <secret>', 'TestingBot API secret.')
219
+ .option('--debug', 'Enable debug logging of API responses.')
186
220
  .action(async (appFileArg, flowsArgs, args) => {
187
221
  try {
188
222
  let app;
@@ -245,6 +279,7 @@ const maestroCommand = program
245
279
  artifactsOutputDir: args.artifactsOutputDir,
246
280
  ignoreChecksumCheck: args.ignoreChecksumCheck,
247
281
  shardSplit: args.shardSplit,
282
+ debug: args.debug,
248
283
  metadata,
249
284
  });
250
285
  const credentials = await auth_1.default.getCredentials({
@@ -258,6 +293,9 @@ const maestroCommand = program
258
293
  ' 3. Set TB_KEY and TB_SECRET environment variables\n' +
259
294
  ' 4. Create ~/.testingbot file with content: key:secret');
260
295
  }
296
+ if (args.debug) {
297
+ (0, logger_1.enableDebugLogging)();
298
+ }
261
299
  const maestro = new maestro_1.default(credentials, options);
262
300
  const result = await maestro.run();
263
301
  if (!result.success) {
package/dist/logger.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import tracer from 'tracer';
2
2
  declare const logger: tracer.Tracer.Logger<string>;
3
+ export declare function enableDebugLogging(): void;
3
4
  export default logger;
4
5
  //# sourceMappingURL=logger.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,QAAA,MAAM,MAAM,8BAWV,CAAC;AAEH,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,QAAA,MAAM,MAAM,8BAWV,CAAC;AAEH,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED,eAAe,MAAM,CAAC"}
package/dist/logger.js CHANGED
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.enableDebugLogging = enableDebugLogging;
6
7
  const picocolors_1 = __importDefault(require("picocolors"));
7
8
  const tracer_1 = __importDefault(require("tracer"));
8
9
  const logger = tracer_1.default.colorConsole({
@@ -17,4 +18,7 @@ const logger = tracer_1.default.colorConsole({
17
18
  },
18
19
  ],
19
20
  });
21
+ function enableDebugLogging() {
22
+ tracer_1.default.setLevel('debug');
23
+ }
20
24
  exports.default = logger;
@@ -58,6 +58,7 @@ export default class MaestroOptions {
58
58
  private _artifactsOutputDir?;
59
59
  private _ignoreChecksumCheck;
60
60
  private _shardSplit?;
61
+ private _debug;
61
62
  private _metadata?;
62
63
  constructor(app: string, flows: string | string[], device?: string, options?: {
63
64
  includeTags?: string[];
@@ -81,6 +82,7 @@ export default class MaestroOptions {
81
82
  artifactsOutputDir?: string;
82
83
  ignoreChecksumCheck?: boolean;
83
84
  shardSplit?: number;
85
+ debug?: boolean;
84
86
  metadata?: RunMetadata;
85
87
  });
86
88
  get app(): string;
@@ -107,6 +109,7 @@ export default class MaestroOptions {
107
109
  get artifactsOutputDir(): string | undefined;
108
110
  get ignoreChecksumCheck(): boolean;
109
111
  get shardSplit(): number | undefined;
112
+ get debug(): boolean;
110
113
  get metadata(): RunMetadata | undefined;
111
114
  getMaestroOptions(): MaestroRunOptions | undefined;
112
115
  getCapabilities(detectedPlatform?: 'Android' | 'iOS'): MaestroCapabilities;
@@ -1 +1 @@
1
- {"version":3,"file":"maestro_options.d.ts","sourceRoot":"","sources":["../../src/models/maestro_options.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"maestro_options.d.ts","sourceRoot":"","sources":["../../src/models/maestro_options.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;CACtC;AAED,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,WAAW,CAAC;AACnD,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;AAC5E,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,OAAO,CAAC;AAC5C,MAAM,MAAM,oBAAoB,GAAG,KAAK,GAAG,QAAQ,CAAC;AAEpD,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,YAAY,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,CAAC,OAAO,OAAO,cAAc;IACjC,OAAO,CAAC,MAAM,CAAC,SAAS;IAIxB,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,OAAO,CAAC,CAAS;IACzB,OAAO,CAAC,YAAY,CAAC,CAAW;IAChC,OAAO,CAAC,YAAY,CAAC,CAAW;IAChC,OAAO,CAAC,aAAa,CAAC,CAAoB;IAC1C,OAAO,CAAC,QAAQ,CAAC,CAAS;IAC1B,OAAO,CAAC,KAAK,CAAC,CAAS;IACvB,OAAO,CAAC,YAAY,CAAC,CAAc;IACnC,OAAO,CAAC,OAAO,CAAC,CAAS;IACzB,OAAO,CAAC,SAAS,CAAC,CAAS;IAC3B,OAAO,CAAC,gBAAgB,CAAC,CAAkB;IAC3C,OAAO,CAAC,eAAe,CAAC,CAAS;IACjC,OAAO,CAAC,IAAI,CAAC,CAAyB;IACtC,OAAO,CAAC,eAAe,CAAC,CAAS;IACjC,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,OAAO,CAAC,CAAe;IAC/B,OAAO,CAAC,gBAAgB,CAAC,CAAS;IAClC,OAAO,CAAC,WAAW,CAAU;IAC7B,OAAO,CAAC,kBAAkB,CAAC,CAAuB;IAClD,OAAO,CAAC,mBAAmB,CAAC,CAAS;IACrC,OAAO,CAAC,oBAAoB,CAAU;IACtC,OAAO,CAAC,WAAW,CAAC,CAAS;IAC7B,OAAO,CAAC,MAAM,CAAU;IAExB,OAAO,CAAC,SAAS,CAAC,CAAc;gBAG9B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,EACxB,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QACR,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;QACvB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;QACvB,YAAY,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC;QACjC,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,WAAW,CAAC;QAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,eAAe,CAAC,EAAE,eAAe,CAAC;QAClC,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,MAAM,CAAC,EAAE,YAAY,CAAC;QACtB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,iBAAiB,CAAC,EAAE,oBAAoB,CAAC;QACzC,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAC5B,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,QAAQ,CAAC,EAAE,WAAW,CAAC;KACxB;IAgCH,IAAW,GAAG,IAAI,MAAM,CAEvB;IAED,IAAW,KAAK,IAAI,MAAM,EAAE,CAE3B;IAED,IAAW,MAAM,IAAI,MAAM,GAAG,SAAS,CAEtC;IAED,IAAW,WAAW,IAAI,MAAM,EAAE,GAAG,SAAS,CAE7C;IAED,IAAW,WAAW,IAAI,MAAM,EAAE,GAAG,SAAS,CAE7C;IAED,IAAW,YAAY,IAAI,SAAS,GAAG,KAAK,GAAG,SAAS,CAEvD;IAED,IAAW,OAAO,IAAI,MAAM,GAAG,SAAS,CAEvC;IAED,IAAW,IAAI,IAAI,MAAM,GAAG,SAAS,CAEpC;IAED,IAAW,WAAW,IAAI,WAAW,GAAG,SAAS,CAEhD;IAED,IAAW,MAAM,IAAI,MAAM,GAAG,SAAS,CAEtC;IAED,IAAW,QAAQ,IAAI,MAAM,GAAG,SAAS,CAExC;IAED,IAAW,eAAe,IAAI,eAAe,GAAG,SAAS,CAExD;IAED,IAAW,cAAc,IAAI,MAAM,GAAG,SAAS,CAE9C;IAED,IAAW,GAAG,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAEnD;IAED,IAAW,cAAc,IAAI,MAAM,GAAG,SAAS,CAE9C;IAED,IAAW,KAAK,IAAI,OAAO,CAE1B;IAED,IAAW,KAAK,IAAI,OAAO,CAE1B;IAED,IAAW,MAAM,IAAI,YAAY,GAAG,SAAS,CAE5C;IAED,IAAW,eAAe,IAAI,MAAM,GAAG,SAAS,CAE/C;IAED,IAAW,UAAU,IAAI,OAAO,CAE/B;IAED,IAAW,iBAAiB,IAAI,oBAAoB,GAAG,SAAS,CAE/D;IAED,IAAW,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAElD;IAED,IAAW,mBAAmB,IAAI,OAAO,CAExC;IAED,IAAW,UAAU,IAAI,MAAM,GAAG,SAAS,CAE1C;IAED,IAAW,KAAK,IAAI,OAAO,CAE1B;IAED,IAAW,QAAQ,IAAI,WAAW,GAAG,SAAS,CAE7C;IAEM,iBAAiB,IAAI,iBAAiB,GAAG,SAAS;IAmBlD,eAAe,CACpB,gBAAgB,CAAC,EAAE,SAAS,GAAG,KAAK,GACnC,mBAAmB;CAiCvB"}
@@ -28,6 +28,7 @@ class MaestroOptions {
28
28
  _artifactsOutputDir;
29
29
  _ignoreChecksumCheck;
30
30
  _shardSplit;
31
+ _debug;
31
32
  // Metadata
32
33
  _metadata;
33
34
  constructor(app, flows, device, options) {
@@ -51,11 +52,13 @@ class MaestroOptions {
51
52
  this._report = options?.report;
52
53
  this._reportOutputDir = options?.reportOutputDir;
53
54
  // IPA files can only be tested on real iOS devices, so automatically enable realDevice
54
- this._realDevice = MaestroOptions.isIpaFile(app) || (options?.realDevice ?? false);
55
+ this._realDevice =
56
+ MaestroOptions.isIpaFile(app) || (options?.realDevice ?? false);
55
57
  this._downloadArtifacts = options?.downloadArtifacts;
56
58
  this._artifactsOutputDir = options?.artifactsOutputDir;
57
59
  this._ignoreChecksumCheck = options?.ignoreChecksumCheck ?? false;
58
60
  this._shardSplit = options?.shardSplit;
61
+ this._debug = options?.debug ?? false;
59
62
  this._metadata = options?.metadata;
60
63
  }
61
64
  get app() {
@@ -130,6 +133,9 @@ class MaestroOptions {
130
133
  get shardSplit() {
131
134
  return this._shardSplit;
132
135
  }
136
+ get debug() {
137
+ return this._debug;
138
+ }
133
139
  get metadata() {
134
140
  return this._metadata;
135
141
  }
@@ -1 +1 @@
1
- {"version":3,"file":"espresso.d.ts","sourceRoot":"","sources":["../../src/providers/espresso.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,MAAM,4BAA4B,CAAC;AAEzD,OAAO,WAAW,MAAM,uBAAuB,CAAC;AAOhD,OAAO,YAAY,MAAM,iBAAiB,CAAC;AAE3C,MAAM,WAAW,sBAAsB;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;IAChD,YAAY,EAAE;QACZ,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;QACrB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,WAAW,CAAC,EAAE,sBAAsB,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,eAAe,EAAE,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,eAAe,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,CAAC,OAAO,OAAO,QAAS,SAAQ,YAAY,CAAC,eAAe,CAAC;IACjE,SAAS,CAAC,QAAQ,CAAC,GAAG,yDACkC;IAExD,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,SAAS,CAAuB;gBAErB,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe;YAIvD,QAAQ;IAuCT,GAAG,IAAI,OAAO,CAAC,cAAc,CAAC;YA+D7B,SAAS;YAaT,aAAa;YAYb,QAAQ;YA0DR,SAAS;YA4BT,iBAAiB;IAwE/B,OAAO,CAAC,gBAAgB;IAmCxB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,aAAa;YAkBP,YAAY;IAwD1B,OAAO,CAAC,qBAAqB;IAqC7B,OAAO,CAAC,0BAA0B;IAOlC,OAAO,CAAC,kBAAkB;IAc1B,OAAO,CAAC,mBAAmB;CAa5B"}
1
+ {"version":3,"file":"espresso.d.ts","sourceRoot":"","sources":["../../src/providers/espresso.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,MAAM,4BAA4B,CAAC;AAEzD,OAAO,WAAW,MAAM,uBAAuB,CAAC;AAOhD,OAAO,YAAY,MAAM,iBAAiB,CAAC;AAE3C,MAAM,WAAW,sBAAsB;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;IAChD,YAAY,EAAE;QACZ,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;QACrB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,WAAW,CAAC,EAAE,sBAAsB,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,eAAe,EAAE,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,eAAe,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,CAAC,OAAO,OAAO,QAAS,SAAQ,YAAY,CAAC,eAAe,CAAC;IACjE,SAAS,CAAC,QAAQ,CAAC,GAAG,yDACkC;IAExD,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,SAAS,CAAuB;gBAErB,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe;YAIvD,QAAQ;IAuCT,GAAG,IAAI,OAAO,CAAC,cAAc,CAAC;YA+D7B,SAAS;YAcT,aAAa;YAab,QAAQ;YA0DR,SAAS;YA4BT,iBAAiB;IAwE/B,OAAO,CAAC,gBAAgB;IAmCxB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,aAAa;YAkBP,YAAY;IAwD1B,OAAO,CAAC,qBAAqB;IAqC7B,OAAO,CAAC,0BAA0B;IAOlC,OAAO,CAAC,kBAAkB;IAc1B,OAAO,CAAC,mBAAmB;CAa5B"}
@@ -104,6 +104,7 @@ class Espresso extends base_provider_1.default {
104
104
  credentials: this.credentials,
105
105
  contentType: 'application/vnd.android.package-archive',
106
106
  showProgress: !this.options.quiet,
107
+ validateZipFormat: true,
107
108
  });
108
109
  this.appId = result.id;
109
110
  return true;
@@ -115,6 +116,7 @@ class Espresso extends base_provider_1.default {
115
116
  credentials: this.credentials,
116
117
  contentType: 'application/vnd.android.package-archive',
117
118
  showProgress: !this.options.quiet,
119
+ validateZipFormat: true,
118
120
  });
119
121
  return true;
120
122
  }
@@ -76,10 +76,18 @@ export default class Maestro extends BaseProvider<MaestroOptions> {
76
76
  private detectPlatform;
77
77
  run(): Promise<MaestroResult>;
78
78
  private uploadApp;
79
+ /**
80
+ * Zip a .app bundle directory into a temporary zip file
81
+ */
82
+ private zipAppBundle;
79
83
  private checkAppChecksum;
80
84
  private uploadFlows;
81
85
  private discoverFlows;
82
86
  private discoverDependencies;
87
+ /**
88
+ * Check if a file path is a Maestro config file (config.yaml or config.yml)
89
+ */
90
+ private isConfigFile;
83
91
  /**
84
92
  * Check if a string looks like a file path (relative path with extension)
85
93
  */
@@ -97,7 +105,7 @@ export default class Maestro extends BaseProvider<MaestroOptions> {
97
105
  * This validates that all referenced files (runScript, runFlow, addMedia, etc.)
98
106
  * will be included in the zip.
99
107
  */
100
- findMissingReferences(flowFiles: string[], allIncludedFiles: string[], baseDir?: string): Promise<MissingFileReference[]>;
108
+ findMissingReferences(flowFiles: string[], allIncludedFiles: string[]): Promise<MissingFileReference[]>;
101
109
  /**
102
110
  * Recursively find missing file references in a YAML value
103
111
  */
@@ -108,6 +116,10 @@ export default class Maestro extends BaseProvider<MaestroOptions> {
108
116
  private logMissingReferences;
109
117
  private logIncludedFiles;
110
118
  private createFlowsZip;
119
+ /**
120
+ * Compute the common parent directory of all files
121
+ */
122
+ private computeCommonDirectory;
111
123
  private runTests;
112
124
  private getStatus;
113
125
  private waitForCompletion;
@@ -1 +1 @@
1
- {"version":3,"file":"maestro.d.ts","sourceRoot":"","sources":["../../src/providers/maestro.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"maestro.d.ts","sourceRoot":"","sources":["../../src/providers/maestro.ts"],"names":[],"mappings":"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"}
@@ -172,44 +172,84 @@ class Maestro extends base_provider_1.default {
172
172
  }
173
173
  }
174
174
  async uploadApp() {
175
- const appPath = this.options.app;
175
+ let appPath = this.options.app;
176
176
  const ext = node_path_1.default.extname(appPath).toLowerCase();
177
- let contentType;
178
- if (ext === '.apk') {
179
- contentType = 'application/vnd.android.package-archive';
180
- }
181
- else if (ext === '.ipa' || ext === '.app') {
182
- contentType = 'application/octet-stream';
183
- }
184
- else if (ext === '.zip') {
185
- contentType = 'application/zip';
186
- }
187
- else {
188
- contentType = 'application/octet-stream';
189
- }
190
- if (!this.options.ignoreChecksumCheck) {
191
- const checksum = await this.upload.calculateChecksum(appPath);
192
- const existingApp = await this.checkAppChecksum(checksum);
193
- if (existingApp) {
194
- this.appId = existingApp.id;
177
+ let tempZipPath = null;
178
+ // If .app bundle (directory), zip it first
179
+ if (ext === '.app') {
180
+ const stat = await node_fs_1.default.promises.stat(appPath);
181
+ if (stat.isDirectory()) {
195
182
  if (!this.options.quiet) {
196
- logger_1.default.info(' App already uploaded, skipping upload');
183
+ logger_1.default.info('Zipping .app bundle for upload');
197
184
  }
198
- return true;
185
+ tempZipPath = await this.zipAppBundle(appPath);
186
+ appPath = tempZipPath;
199
187
  }
200
188
  }
201
- if (!this.options.quiet) {
202
- logger_1.default.info('Uploading Maestro App');
203
- }
204
- const result = await this.upload.upload({
205
- filePath: appPath,
206
- url: `${this.URL}/app`,
207
- credentials: this.credentials,
208
- contentType,
209
- showProgress: !this.options.quiet,
189
+ try {
190
+ let contentType;
191
+ if (ext === '.apk') {
192
+ contentType = 'application/vnd.android.package-archive';
193
+ }
194
+ else if (ext === '.ipa') {
195
+ contentType = 'application/octet-stream';
196
+ }
197
+ else if (ext === '.zip' || ext === '.app') {
198
+ // .app bundles are zipped, so use application/zip
199
+ contentType = 'application/zip';
200
+ }
201
+ else {
202
+ contentType = 'application/octet-stream';
203
+ }
204
+ if (!this.options.ignoreChecksumCheck) {
205
+ const checksum = await this.upload.calculateChecksum(appPath);
206
+ const existingApp = await this.checkAppChecksum(checksum);
207
+ if (existingApp) {
208
+ this.appId = existingApp.id;
209
+ if (!this.options.quiet) {
210
+ logger_1.default.info(' App already uploaded, skipping upload');
211
+ }
212
+ return true;
213
+ }
214
+ }
215
+ if (!this.options.quiet) {
216
+ logger_1.default.info('Uploading Maestro App');
217
+ }
218
+ const result = await this.upload.upload({
219
+ filePath: appPath,
220
+ url: `${this.URL}/app`,
221
+ credentials: this.credentials,
222
+ contentType,
223
+ showProgress: !this.options.quiet,
224
+ validateZipFormat: true,
225
+ });
226
+ this.appId = result.id;
227
+ return true;
228
+ }
229
+ finally {
230
+ // Clean up temporary zip file
231
+ if (tempZipPath) {
232
+ await node_fs_1.default.promises.unlink(tempZipPath).catch(() => { });
233
+ }
234
+ }
235
+ }
236
+ /**
237
+ * Zip a .app bundle directory into a temporary zip file
238
+ */
239
+ async zipAppBundle(appPath) {
240
+ const appName = node_path_1.default.basename(appPath);
241
+ const tmpDir = await node_fs_1.default.promises.mkdtemp(node_path_1.default.join(node_os_1.default.tmpdir(), 'testingbot-app-'));
242
+ const zipPath = node_path_1.default.join(tmpDir, `${appName}.zip`);
243
+ return new Promise((resolve, reject) => {
244
+ const output = node_fs_1.default.createWriteStream(zipPath);
245
+ const archive = (0, archiver_1.default)('zip', { zlib: { level: 9 } });
246
+ output.on('close', () => resolve(zipPath));
247
+ archive.on('error', (err) => reject(err));
248
+ archive.pipe(output);
249
+ // Add the .app directory with its name preserved
250
+ archive.directory(appPath, appName);
251
+ archive.finalize();
210
252
  });
211
- this.appId = result.id;
212
- return true;
213
253
  }
214
254
  async checkAppChecksum(checksum) {
215
255
  try {
@@ -239,7 +279,6 @@ class Maestro extends base_provider_1.default {
239
279
  async uploadFlows() {
240
280
  const flowsPaths = this.options.flows;
241
281
  let zipPath;
242
- let shouldCleanup = false;
243
282
  // Special case: single zip file - upload directly
244
283
  if (flowsPaths.length === 1) {
245
284
  const singlePath = flowsPaths[0];
@@ -252,6 +291,7 @@ class Maestro extends base_provider_1.default {
252
291
  credentials: this.credentials,
253
292
  contentType: 'application/zip',
254
293
  showProgress: !this.options.quiet,
294
+ validateZipFormat: true,
255
295
  });
256
296
  return true;
257
297
  }
@@ -301,16 +341,41 @@ class Maestro extends base_provider_1.default {
301
341
  // Determine base directory for zip structure
302
342
  // If we have a single directory, use it as base; otherwise use common ancestor or flatten
303
343
  const baseDir = baseDirs.length === 1 ? baseDirs[0] : undefined;
344
+ // Discover dependencies (addMedia, runScript, runFlow, etc.) for all flow files
345
+ // This ensures referenced files are included even when individual YAML files are passed
346
+ const allFilesSet = new Set(allFlowFiles.map((f) => node_path_1.default.resolve(f)));
347
+ for (const flowFile of [...allFlowFiles]) {
348
+ const ext = node_path_1.default.extname(flowFile).toLowerCase();
349
+ if (ext === '.yaml' || ext === '.yml') {
350
+ const deps = await this.discoverDependencies(flowFile, baseDir || node_path_1.default.dirname(flowFile));
351
+ for (const dep of deps) {
352
+ const resolved = node_path_1.default.resolve(dep);
353
+ if (!allFilesSet.has(resolved)) {
354
+ allFilesSet.add(resolved);
355
+ allFlowFiles.push(dep);
356
+ }
357
+ }
358
+ }
359
+ }
304
360
  if (!this.options.quiet) {
305
361
  this.logIncludedFiles(allFlowFiles, baseDir);
362
+ // Show info about potential slow execution on specific real devices
363
+ utils_1.default.showRealDeviceFlowsInfo({
364
+ realDevice: this.options.realDevice,
365
+ device: this.options.device,
366
+ version: this.options.version,
367
+ flowCount: allFlowFiles
368
+ .filter((f) => f.endsWith('.yaml') || f.endsWith('.yml'))
369
+ .filter((f) => !this.isConfigFile(f)).length,
370
+ shardSplit: this.options.shardSplit,
371
+ });
306
372
  }
307
373
  // Check for missing file references and warn the user
308
- const missingReferences = await this.findMissingReferences(allFlowFiles, allFlowFiles, baseDir);
374
+ const missingReferences = await this.findMissingReferences(allFlowFiles, allFlowFiles);
309
375
  if (!this.options.quiet && missingReferences.length > 0) {
310
376
  this.logMissingReferences(missingReferences, baseDir);
311
377
  }
312
378
  zipPath = await this.createFlowsZip(allFlowFiles, baseDir);
313
- shouldCleanup = true;
314
379
  try {
315
380
  await this.upload.upload({
316
381
  filePath: zipPath,
@@ -321,9 +386,7 @@ class Maestro extends base_provider_1.default {
321
386
  });
322
387
  }
323
388
  finally {
324
- if (shouldCleanup) {
325
- await node_fs_1.default.promises.unlink(zipPath).catch(() => { });
326
- }
389
+ await node_fs_1.default.promises.unlink(zipPath).catch(() => { });
327
390
  }
328
391
  return true;
329
392
  }
@@ -332,15 +395,20 @@ class Maestro extends base_provider_1.default {
332
395
  withFileTypes: true,
333
396
  });
334
397
  const flowFiles = [];
335
- const configPath = node_path_1.default.join(directory, 'config.yaml');
398
+ let configPath = null;
336
399
  let config = null;
337
- // Check for config.yaml
338
- try {
339
- const configContent = await node_fs_1.default.promises.readFile(configPath, 'utf-8');
340
- config = yaml.load(configContent);
341
- }
342
- catch {
343
- // No config.yaml, that's fine
400
+ // Check for config.yaml or config.yml
401
+ for (const configName of ['config.yaml', 'config.yml']) {
402
+ const candidatePath = node_path_1.default.join(directory, configName);
403
+ try {
404
+ const configContent = await node_fs_1.default.promises.readFile(candidatePath, 'utf-8');
405
+ config = yaml.load(configContent);
406
+ configPath = candidatePath;
407
+ break; // Use the first config file found
408
+ }
409
+ catch {
410
+ // Config file doesn't exist, try next
411
+ }
344
412
  }
345
413
  // If config specifies flows, use those
346
414
  if (config?.flows && config.flows.length > 0) {
@@ -355,7 +423,7 @@ class Maestro extends base_provider_1.default {
355
423
  if (entry.isFile()) {
356
424
  const ext = node_path_1.default.extname(entry.name).toLowerCase();
357
425
  if ((ext === '.yaml' || ext === '.yml') &&
358
- entry.name !== 'config.yaml') {
426
+ !this.isConfigFile(entry.name)) {
359
427
  flowFiles.push(node_path_1.default.join(directory, entry.name));
360
428
  }
361
429
  }
@@ -367,8 +435,8 @@ class Maestro extends base_provider_1.default {
367
435
  const dependencies = await this.discoverDependencies(flowFile, directory);
368
436
  dependencies.forEach((dep) => allFiles.add(dep));
369
437
  }
370
- // Include config.yaml if it exists
371
- if (config) {
438
+ // Include config file if it exists
439
+ if (configPath) {
372
440
  allFiles.add(configPath);
373
441
  }
374
442
  return Array.from(allFiles);
@@ -400,6 +468,13 @@ class Maestro extends base_provider_1.default {
400
468
  }
401
469
  return dependencies;
402
470
  }
471
+ /**
472
+ * Check if a file path is a Maestro config file (config.yaml or config.yml)
473
+ */
474
+ isConfigFile(filePath) {
475
+ const basename = node_path_1.default.basename(filePath);
476
+ return basename === 'config.yaml' || basename === 'config.yml';
477
+ }
403
478
  /**
404
479
  * Check if a string looks like a file path (relative path with extension)
405
480
  */
@@ -560,7 +635,7 @@ class Maestro extends base_provider_1.default {
560
635
  * This validates that all referenced files (runScript, runFlow, addMedia, etc.)
561
636
  * will be included in the zip.
562
637
  */
563
- async findMissingReferences(flowFiles, allIncludedFiles, baseDir) {
638
+ async findMissingReferences(flowFiles, allIncludedFiles) {
564
639
  const missingReferences = [];
565
640
  const includedFilesSet = new Set(allIncludedFiles.map((f) => node_path_1.default.resolve(f)));
566
641
  for (const flowFile of flowFiles) {
@@ -593,20 +668,12 @@ class Maestro extends base_provider_1.default {
593
668
  if (typeof value === 'string') {
594
669
  if (this.looksLikePath(value)) {
595
670
  const resolvedPath = node_path_1.default.resolve(node_path_1.default.dirname(flowFile), value);
596
- // Check if the file is in included files OR exists on disk
597
671
  if (!includedFiles.has(resolvedPath)) {
598
- try {
599
- await node_fs_1.default.promises.access(resolvedPath);
600
- // File exists on disk but won't be included - also warn
601
- }
602
- catch {
603
- // File doesn't exist
604
- missingReferences.push({
605
- flowFile,
606
- referencedFile: value,
607
- resolvedPath,
608
- });
609
- }
672
+ missingReferences.push({
673
+ flowFile,
674
+ referencedFile: value,
675
+ resolvedPath,
676
+ });
610
677
  }
611
678
  }
612
679
  }
@@ -630,16 +697,11 @@ class Maestro extends base_provider_1.default {
630
697
  if (typeof scriptFile === 'string') {
631
698
  const resolved = node_path_1.default.resolve(node_path_1.default.dirname(flowFile), scriptFile);
632
699
  if (!includedFiles.has(resolved)) {
633
- try {
634
- await node_fs_1.default.promises.access(resolved);
635
- }
636
- catch {
637
- missingReferences.push({
638
- flowFile,
639
- referencedFile: scriptFile,
640
- resolvedPath: resolved,
641
- });
642
- }
700
+ missingReferences.push({
701
+ flowFile,
702
+ referencedFile: scriptFile,
703
+ resolvedPath: resolved,
704
+ });
643
705
  }
644
706
  }
645
707
  // Don't recurse into runScript - it only has file, env, when (no nested file refs)
@@ -654,16 +716,11 @@ class Maestro extends base_provider_1.default {
654
716
  if (typeof flowRef === 'string') {
655
717
  const resolved = node_path_1.default.resolve(node_path_1.default.dirname(flowFile), flowRef);
656
718
  if (!includedFiles.has(resolved)) {
657
- try {
658
- await node_fs_1.default.promises.access(resolved);
659
- }
660
- catch {
661
- missingReferences.push({
662
- flowFile,
663
- referencedFile: flowRef,
664
- resolvedPath: resolved,
665
- });
666
- }
719
+ missingReferences.push({
720
+ flowFile,
721
+ referencedFile: flowRef,
722
+ resolvedPath: resolved,
723
+ });
667
724
  }
668
725
  }
669
726
  // Only recurse into 'commands' if present (for inline commands)
@@ -686,16 +743,11 @@ class Maestro extends base_provider_1.default {
686
743
  if (typeof mediaFile === 'string') {
687
744
  const resolved = node_path_1.default.resolve(node_path_1.default.dirname(flowFile), mediaFile);
688
745
  if (!includedFiles.has(resolved)) {
689
- try {
690
- await node_fs_1.default.promises.access(resolved);
691
- }
692
- catch {
693
- missingReferences.push({
694
- flowFile,
695
- referencedFile: mediaFile,
696
- resolvedPath: resolved,
697
- });
698
- }
746
+ missingReferences.push({
747
+ flowFile,
748
+ referencedFile: mediaFile,
749
+ resolvedPath: resolved,
750
+ });
699
751
  }
700
752
  }
701
753
  }
@@ -705,16 +757,11 @@ class Maestro extends base_provider_1.default {
705
757
  handledKeys.add('file');
706
758
  const resolved = node_path_1.default.resolve(node_path_1.default.dirname(flowFile), obj.file);
707
759
  if (!includedFiles.has(resolved)) {
708
- try {
709
- await node_fs_1.default.promises.access(resolved);
710
- }
711
- catch {
712
- missingReferences.push({
713
- flowFile,
714
- referencedFile: obj.file,
715
- resolvedPath: resolved,
716
- });
717
- }
760
+ missingReferences.push({
761
+ flowFile,
762
+ referencedFile: obj.file,
763
+ resolvedPath: resolved,
764
+ });
718
765
  }
719
766
  }
720
767
  // Handle onFlowStart, onFlowComplete, commands
@@ -756,8 +803,9 @@ class Maestro extends base_provider_1.default {
756
803
  }
757
804
  logIncludedFiles(files, baseDir) {
758
805
  // Get relative paths for display
806
+ const effectiveBase = baseDir || this.computeCommonDirectory(files);
759
807
  const relativePaths = files
760
- .map((f) => (baseDir ? node_path_1.default.relative(baseDir, f) : node_path_1.default.basename(f)))
808
+ .map((f) => node_path_1.default.relative(effectiveBase, f))
761
809
  .sort();
762
810
  // Group by file type
763
811
  const groups = {
@@ -770,7 +818,7 @@ class Maestro extends base_provider_1.default {
770
818
  for (const filePath of relativePaths) {
771
819
  const ext = node_path_1.default.extname(filePath).toLowerCase();
772
820
  if (ext === '.yaml' || ext === '.yml') {
773
- if (filePath === 'config.yaml' || filePath.endsWith('/config.yaml')) {
821
+ if (this.isConfigFile(filePath)) {
774
822
  groups['Config files'].push(filePath);
775
823
  }
776
824
  else {
@@ -811,20 +859,38 @@ class Maestro extends base_provider_1.default {
811
859
  output.on('close', () => resolve(zipPath));
812
860
  archive.on('error', (err) => reject(err));
813
861
  archive.pipe(output);
862
+ // Compute effective base directory for archive paths
863
+ const effectiveBase = baseDir || this.computeCommonDirectory(files);
814
864
  for (const file of files) {
815
- // Determine the name in the archive
816
- let archiveName;
817
- if (baseDir) {
818
- archiveName = node_path_1.default.relative(baseDir, file);
819
- }
820
- else {
821
- archiveName = node_path_1.default.basename(file);
822
- }
865
+ const archiveName = node_path_1.default.relative(effectiveBase, file);
823
866
  archive.file(file, { name: archiveName });
824
867
  }
825
868
  archive.finalize();
826
869
  });
827
870
  }
871
+ /**
872
+ * Compute the common parent directory of all files
873
+ */
874
+ computeCommonDirectory(files) {
875
+ if (files.length === 0)
876
+ return process.cwd();
877
+ if (files.length === 1)
878
+ return node_path_1.default.dirname(files[0]);
879
+ const dirs = files.map((f) => node_path_1.default.dirname(node_path_1.default.resolve(f)));
880
+ const parts = dirs[0].split(node_path_1.default.sep);
881
+ let commonLength = parts.length;
882
+ for (let i = 1; i < dirs.length; i++) {
883
+ const dirParts = dirs[i].split(node_path_1.default.sep);
884
+ commonLength = Math.min(commonLength, dirParts.length);
885
+ for (let j = 0; j < commonLength; j++) {
886
+ if (parts[j] !== dirParts[j]) {
887
+ commonLength = j;
888
+ break;
889
+ }
890
+ }
891
+ }
892
+ return parts.slice(0, commonLength).join(node_path_1.default.sep) || node_path_1.default.sep;
893
+ }
828
894
  async runTests() {
829
895
  try {
830
896
  const capabilities = this.options.getCapabilities(this.detectedPlatform);
@@ -889,6 +955,9 @@ class Maestro extends base_provider_1.default {
889
955
  // Check for version update notification
890
956
  const latestVersion = response.headers?.['x-testingbotctl-version'];
891
957
  utils_1.default.checkForUpdate(latestVersion);
958
+ if (this.options.debug) {
959
+ logger_1.default.debug(`API response: ${JSON.stringify(response.data, null, 2)}`);
960
+ }
892
961
  return response.data;
893
962
  });
894
963
  }
@@ -1 +1 @@
1
- {"version":3,"file":"xcuitest.d.ts","sourceRoot":"","sources":["../../src/providers/xcuitest.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,MAAM,4BAA4B,CAAC;AAEzD,OAAO,WAAW,MAAM,uBAAuB,CAAC;AAOhD,OAAO,YAAY,MAAM,iBAAiB,CAAC;AAE3C,MAAM,WAAW,sBAAsB;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;IAChD,YAAY,EAAE;QACZ,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;QACrB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,WAAW,CAAC,EAAE,sBAAsB,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,eAAe,EAAE,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,eAAe,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,CAAC,OAAO,OAAO,QAAS,SAAQ,YAAY,CAAC,eAAe,CAAC;IACjE,SAAS,CAAC,QAAQ,CAAC,GAAG,yDACkC;IAExD,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,SAAS,CAAuB;gBAErB,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe;YAIvD,QAAQ;IAuCT,GAAG,IAAI,OAAO,CAAC,cAAc,CAAC;YA+D7B,SAAS;YAaT,aAAa;YAYb,QAAQ;YA0DR,SAAS;YA4BT,iBAAiB;IAwE/B,OAAO,CAAC,gBAAgB;IAmCxB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,aAAa;YAkBP,YAAY;IA2D1B,OAAO,CAAC,qBAAqB;IAqC7B,OAAO,CAAC,0BAA0B;IAOlC,OAAO,CAAC,kBAAkB;IAc1B,OAAO,CAAC,mBAAmB;CAa5B"}
1
+ {"version":3,"file":"xcuitest.d.ts","sourceRoot":"","sources":["../../src/providers/xcuitest.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,MAAM,4BAA4B,CAAC;AAEzD,OAAO,WAAW,MAAM,uBAAuB,CAAC;AAOhD,OAAO,YAAY,MAAM,iBAAiB,CAAC;AAE3C,MAAM,WAAW,sBAAsB;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;IAChD,YAAY,EAAE;QACZ,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;QACrB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,WAAW,CAAC,EAAE,sBAAsB,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,eAAe,EAAE,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,eAAe,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,CAAC,OAAO,OAAO,QAAS,SAAQ,YAAY,CAAC,eAAe,CAAC;IACjE,SAAS,CAAC,QAAQ,CAAC,GAAG,yDACkC;IAExD,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,SAAS,CAAuB;gBAErB,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe;YAIvD,QAAQ;IAuCT,GAAG,IAAI,OAAO,CAAC,cAAc,CAAC;YA+D7B,SAAS;YAcT,aAAa;YAab,QAAQ;YA0DR,SAAS;YA4BT,iBAAiB;IAwE/B,OAAO,CAAC,gBAAgB;IAmCxB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,aAAa;YAkBP,YAAY;IA2D1B,OAAO,CAAC,qBAAqB;IAqC7B,OAAO,CAAC,0BAA0B;IAOlC,OAAO,CAAC,kBAAkB;IAc1B,OAAO,CAAC,mBAAmB;CAa5B"}
@@ -104,6 +104,7 @@ class XCUITest extends base_provider_1.default {
104
104
  credentials: this.credentials,
105
105
  contentType: 'application/octet-stream',
106
106
  showProgress: !this.options.quiet,
107
+ validateZipFormat: true,
107
108
  });
108
109
  this.appId = result.id;
109
110
  return true;
@@ -115,6 +116,7 @@ class XCUITest extends base_provider_1.default {
115
116
  credentials: this.credentials,
116
117
  contentType: 'application/zip',
117
118
  showProgress: !this.options.quiet,
119
+ validateZipFormat: true,
118
120
  });
119
121
  return true;
120
122
  }
package/dist/upload.d.ts CHANGED
@@ -7,6 +7,8 @@ export interface UploadOptions {
7
7
  contentType: ContentType;
8
8
  showProgress?: boolean;
9
9
  checksum?: string;
10
+ /** Validate that the file is a valid zip-based archive (APK, IPA, ZIP) */
11
+ validateZipFormat?: boolean;
10
12
  }
11
13
  export interface UploadResult {
12
14
  id: number;
@@ -19,6 +21,15 @@ export default class Upload {
19
21
  */
20
22
  private formatFileSize;
21
23
  private validateFile;
24
+ /**
25
+ * Validate that the file is a valid zip-based archive.
26
+ * ZIP, APK, IPA files all start with the ZIP magic bytes (PK\x03\x04).
27
+ */
28
+ private validateZipFormat;
29
+ /**
30
+ * Extract error message from server response data
31
+ */
32
+ private extractErrorMessage;
22
33
  /**
23
34
  * Calculate MD5 checksum of a file, returning base64-encoded result
24
35
  * This matches ActiveStorage's checksum format
@@ -1 +1 @@
1
- {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"AAMA,OAAO,WAAW,MAAM,sBAAsB,CAAC;AAK/C,MAAM,MAAM,WAAW,GACnB,yCAAyC,GACzC,0BAA0B,GAC1B,iBAAiB,CAAC;AAEtB,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,WAAW,CAAC;IACzB,WAAW,EAAE,WAAW,CAAC;IACzB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,CAAC,OAAO,OAAO,MAAM;IACZ,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IA6FlE,OAAO,CAAC,eAAe;IAmBvB;;OAEG;IACH,OAAO,CAAC,cAAc;YAUR,YAAY;IAQ1B;;;OAGG;IACU,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAUlE"}
1
+ {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"AAMA,OAAO,WAAW,MAAM,sBAAsB,CAAC;AAK/C,MAAM,MAAM,WAAW,GACnB,yCAAyC,GACzC,0BAA0B,GAC1B,iBAAiB,CAAC;AAEtB,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,WAAW,CAAC;IACzB,WAAW,EAAE,WAAW,CAAC;IACzB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,CAAC,OAAO,OAAO,MAAM;IACZ,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAyGlE,OAAO,CAAC,eAAe;IAmBvB;;OAEG;IACH,OAAO,CAAC,cAAc;YAUR,YAAY;IAQ1B;;;OAGG;YACW,iBAAiB;IAqB/B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAuB3B;;;OAGG;IACU,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAUlE"}
package/dist/upload.js CHANGED
@@ -16,6 +16,9 @@ class Upload {
16
16
  async upload(options) {
17
17
  const { filePath, url, credentials, showProgress = false } = options;
18
18
  await this.validateFile(filePath);
19
+ if (options.validateZipFormat) {
20
+ await this.validateZipFormat(filePath);
21
+ }
19
22
  const fileName = node_path_1.default.basename(filePath);
20
23
  const fileStats = await node_fs_1.default.promises.stat(filePath);
21
24
  const totalSize = fileStats.size;
@@ -85,6 +88,11 @@ class Upload {
85
88
  throw error;
86
89
  }
87
90
  if (axios_1.default.isAxiosError(error)) {
91
+ // Handle 400 errors specifically for file uploads
92
+ if (error.response?.status === 400) {
93
+ const serverMessage = this.extractErrorMessage(error.response.data);
94
+ throw new testingbot_error_1.default(`Upload rejected: ${serverMessage || 'The file was not accepted by the server'}`, { cause: error });
95
+ }
88
96
  throw (0, error_helpers_1.handleAxiosError)(error, 'Upload failed');
89
97
  }
90
98
  throw new testingbot_error_1.default(`Upload failed: ${error instanceof Error ? error.message : 'Unknown error'}`, { cause: error instanceof Error ? error : undefined });
@@ -122,6 +130,55 @@ class Upload {
122
130
  throw new testingbot_error_1.default(`File not found or not readable: ${filePath}`);
123
131
  }
124
132
  }
133
+ /**
134
+ * Validate that the file is a valid zip-based archive.
135
+ * ZIP, APK, IPA files all start with the ZIP magic bytes (PK\x03\x04).
136
+ */
137
+ async validateZipFormat(filePath) {
138
+ const ZIP_MAGIC_BYTES = Buffer.from([0x50, 0x4b, 0x03, 0x04]); // PK\x03\x04
139
+ const fd = await node_fs_1.default.promises.open(filePath, 'r');
140
+ try {
141
+ const buffer = Buffer.alloc(4);
142
+ const { bytesRead } = await fd.read(buffer, 0, 4, 0);
143
+ if (bytesRead < 4 || !buffer.subarray(0, 4).equals(ZIP_MAGIC_BYTES)) {
144
+ const fileName = node_path_1.default.basename(filePath);
145
+ const ext = node_path_1.default.extname(filePath).toLowerCase();
146
+ throw new testingbot_error_1.default(`Invalid file format: "${fileName}" is not a valid ${ext || 'archive'} file. ` +
147
+ `The file does not appear to be a valid zip-based archive (APK, IPA, or ZIP).`);
148
+ }
149
+ }
150
+ finally {
151
+ await fd.close();
152
+ }
153
+ }
154
+ /**
155
+ * Extract error message from server response data
156
+ */
157
+ extractErrorMessage(data) {
158
+ if (!data)
159
+ return undefined;
160
+ if (typeof data === 'string') {
161
+ try {
162
+ const parsed = JSON.parse(data);
163
+ return parsed.message || parsed.error || parsed.errors || data;
164
+ }
165
+ catch {
166
+ return data;
167
+ }
168
+ }
169
+ if (typeof data === 'object') {
170
+ const obj = data;
171
+ if (typeof obj.message === 'string')
172
+ return obj.message;
173
+ if (typeof obj.error === 'string')
174
+ return obj.error;
175
+ if (typeof obj.errors === 'string')
176
+ return obj.errors;
177
+ if (Array.isArray(obj.errors))
178
+ return obj.errors.join(', ');
179
+ }
180
+ return undefined;
181
+ }
125
182
  /**
126
183
  * Calculate MD5 checksum of a file, returning base64-encoded result
127
184
  * This matches ActiveStorage's checksum format
@@ -94,7 +94,7 @@ async function checkInternetConnectivity() {
94
94
  message: `Internet connectivity verified via ${successResult.endpoint} (${successResult.latencyMs}ms)`,
95
95
  };
96
96
  }
97
- catch (aggregateError) {
97
+ catch {
98
98
  // All endpoints failed - collect all results
99
99
  const endpointResults = await Promise.all(endpointPromises);
100
100
  const testedEndpoints = endpointResults.map((r) => r.endpoint).join(', ');
package/dist/utils.d.ts CHANGED
@@ -6,6 +6,24 @@ declare const _default: {
6
6
  * Returns: -1 if v1 < v2, 0 if equal, 1 if v1 > v2
7
7
  */
8
8
  compareVersions(v1: string, v2: string): number;
9
+ /**
10
+ * Check if a device specification is a wildcard or regex pattern
11
+ */
12
+ isWildcardDevice(device: string | undefined): boolean;
13
+ /**
14
+ * Check if a version specification is a wildcard or regex pattern
15
+ */
16
+ isWildcardVersion(version: string | undefined): boolean;
17
+ /**
18
+ * Show info message when running many flows on a specific real device without sharding
19
+ */
20
+ showRealDeviceFlowsInfo(options: {
21
+ realDevice: boolean;
22
+ device?: string;
23
+ version?: string;
24
+ flowCount: number;
25
+ shardSplit?: number;
26
+ }): void;
9
27
  /**
10
28
  * Check if a newer version is available and display update notice
11
29
  */
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";oBAOkB,MAAM;yBAID,MAAM;IAI3B;;;OAGG;wBACiB,MAAM,MAAM,MAAM,GAAG,MAAM;IAa/C;;OAEG;kCAC2B,MAAM,GAAG,SAAS,GAAG,IAAI;;AA7BzD,wBAuDE"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";oBAQkB,MAAM;yBAID,MAAM;IAI3B;;;OAGG;wBACiB,MAAM,MAAM,MAAM,GAAG,MAAM;IAa/C;;OAEG;6BACsB,MAAM,GAAG,SAAS,GAAG,OAAO;IAWrD;;OAEG;+BACwB,MAAM,GAAG,SAAS,GAAG,OAAO;IAWvD;;OAEG;qCAC8B;QAC/B,UAAU,EAAE,OAAO,CAAC;QACpB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,GAAG,IAAI;IAyDR;;OAEG;kCAC2B,MAAM,GAAG,SAAS,GAAG,IAAI;;AA3HzD,wBAqJE"}
package/dist/utils.js CHANGED
@@ -7,6 +7,7 @@ const package_json_1 = __importDefault(require("../package.json"));
7
7
  const logger_1 = __importDefault(require("./logger"));
8
8
  const picocolors_1 = __importDefault(require("picocolors"));
9
9
  let versionCheckDisplayed = false;
10
+ let realDeviceFlowsInfoDisplayed = false;
10
11
  exports.default = {
11
12
  getUserAgent() {
12
13
  return `TestingBot-CTL-${package_json_1.default.version}`;
@@ -31,6 +32,62 @@ exports.default = {
31
32
  }
32
33
  return 0;
33
34
  },
35
+ /**
36
+ * Check if a device specification is a wildcard or regex pattern
37
+ */
38
+ isWildcardDevice(device) {
39
+ if (!device)
40
+ return true;
41
+ // Check for common wildcard/regex characters
42
+ return (device === '*' ||
43
+ device.includes('*') ||
44
+ device.includes('?') ||
45
+ device.includes('.*'));
46
+ },
47
+ /**
48
+ * Check if a version specification is a wildcard or regex pattern
49
+ */
50
+ isWildcardVersion(version) {
51
+ if (!version)
52
+ return true;
53
+ // Check for common wildcard/regex characters
54
+ return (version === '*' ||
55
+ version.includes('*') ||
56
+ version.includes('?') ||
57
+ version.includes('.*'));
58
+ },
59
+ /**
60
+ * Show info message when running many flows on a specific real device without sharding
61
+ */
62
+ showRealDeviceFlowsInfo(options) {
63
+ // Only show once
64
+ if (realDeviceFlowsInfoDisplayed) {
65
+ return;
66
+ }
67
+ // Check conditions: real device, specific device, more than 2 flows, no shards
68
+ if (!options.realDevice ||
69
+ this.isWildcardDevice(options.device) ||
70
+ options.flowCount <= 2 ||
71
+ options.shardSplit) {
72
+ return;
73
+ }
74
+ realDeviceFlowsInfoDisplayed = true;
75
+ const border = '─'.repeat(80);
76
+ logger_1.default.info('');
77
+ logger_1.default.info(picocolors_1.default.cyan(border));
78
+ logger_1.default.info(picocolors_1.default.cyan('ℹ Performance Tip'));
79
+ logger_1.default.info(picocolors_1.default.cyan(` Running ${options.flowCount} flows on a specific device (${options.device}) in real device mode.`));
80
+ logger_1.default.info(picocolors_1.default.cyan(' Each flow runs in its own session on that device, which may be slow.'));
81
+ logger_1.default.info(picocolors_1.default.cyan(''));
82
+ logger_1.default.info(picocolors_1.default.cyan(' Consider these alternatives for faster execution:'));
83
+ logger_1.default.info(picocolors_1.default.cyan(` • Use ${picocolors_1.default.white('--shard-split <n>')} to run multiple flows in the same session`));
84
+ logger_1.default.info(picocolors_1.default.cyan(` • Use wildcards for device (e.g., ${picocolors_1.default.white('"Pixel.*"')}) to parallelize across devices`));
85
+ if (!this.isWildcardVersion(options.version)) {
86
+ logger_1.default.info(picocolors_1.default.cyan(` • Use wildcards for version (e.g., ${picocolors_1.default.white('"15.*"')}) for broader device selection`));
87
+ }
88
+ logger_1.default.info(picocolors_1.default.cyan(border));
89
+ logger_1.default.info('');
90
+ },
34
91
  /**
35
92
  * Check if a newer version is available and display update notice
36
93
  */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@testingbot/cli",
3
- "version": "1.0.3",
4
- "description": "CLI tool to run Espresso, XCUITest, and Maestro tests on TestingBot's cloud infrastructure",
3
+ "version": "1.0.5",
4
+ "description": "CLI tool to run Espresso, XCUITest and Maestro tests on TestingBot's cloud infrastructure",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
7
7
  "testingbot": "dist/index.js"
@@ -60,18 +60,18 @@
60
60
  "tracer": "^1.3.0"
61
61
  },
62
62
  "devDependencies": {
63
- "@eslint/js": "^9.39.1",
63
+ "@eslint/js": "^10.0.1",
64
64
  "@tsconfig/node20": "^20.1.8",
65
65
  "@types/archiver": "^7.0.0",
66
- "@types/jest": "^29.5.14",
66
+ "@types/jest": "^30.0.0",
67
67
  "@types/js-yaml": "^4.0.9",
68
- "@types/node": "^20.19.0",
68
+ "@types/node": "^25.4.0",
69
69
  "@types/progress-stream": "^2.0.5",
70
- "babel-jest": "^29.7.0",
71
- "eslint": "^9.39.1",
70
+ "babel-jest": "^30.3.0",
71
+ "eslint": "^10.0.3",
72
72
  "eslint-config-prettier": "^10.1.8",
73
73
  "eslint-plugin-prettier": "^5.5.4",
74
- "jest": "^29.7.0",
74
+ "jest": "^30.3.0",
75
75
  "prettier": "^3.7.4",
76
76
  "ts-jest": "^29.4.6",
77
77
  "typescript": "^5.9.3",