@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 +1 -1
- package/dist/cli.js +39 -1
- package/dist/logger.d.ts +1 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +4 -0
- package/dist/models/maestro_options.d.ts +3 -0
- package/dist/models/maestro_options.d.ts.map +1 -1
- package/dist/models/maestro_options.js +7 -1
- package/dist/providers/espresso.d.ts.map +1 -1
- package/dist/providers/espresso.js +2 -0
- package/dist/providers/maestro.d.ts +13 -1
- package/dist/providers/maestro.d.ts.map +1 -1
- package/dist/providers/maestro.js +182 -113
- package/dist/providers/xcuitest.d.ts.map +1 -1
- package/dist/providers/xcuitest.js +2 -0
- package/dist/upload.d.ts +11 -0
- package/dist/upload.d.ts.map +1 -1
- package/dist/upload.js +57 -0
- package/dist/utils/connectivity.js +1 -1
- package/dist/utils.d.ts +18 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +57 -0
- package/package.json +8 -8
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;
|
|
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 =
|
|
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
package/dist/logger.d.ts.map
CHANGED
|
@@ -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":"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;
|
|
1
|
+
{"version":3,"file":"maestro_options.d.ts","sourceRoot":"","sources":["../../src/models/maestro_options.ts"],"names":[],"mappings":"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"}
|
|
@@ -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 =
|
|
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;
|
|
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[]
|
|
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
|
-
|
|
175
|
+
let appPath = this.options.app;
|
|
176
176
|
const ext = node_path_1.default.extname(appPath).toLowerCase();
|
|
177
|
-
let
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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('
|
|
183
|
+
logger_1.default.info('Zipping .app bundle for upload');
|
|
197
184
|
}
|
|
198
|
-
|
|
185
|
+
tempZipPath = await this.zipAppBundle(appPath);
|
|
186
|
+
appPath = tempZipPath;
|
|
199
187
|
}
|
|
200
188
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
398
|
+
let configPath = null;
|
|
336
399
|
let config = null;
|
|
337
|
-
// Check for config.yaml
|
|
338
|
-
|
|
339
|
-
const
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
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
|
|
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
|
|
371
|
-
if (
|
|
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
|
|
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
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
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
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
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
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
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
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
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
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
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) =>
|
|
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 (
|
|
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
|
-
|
|
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;
|
|
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
|
package/dist/upload.d.ts.map
CHANGED
|
@@ -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;
|
|
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
|
|
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
|
*/
|
package/dist/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";
|
|
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.
|
|
4
|
-
"description": "CLI tool to run Espresso, XCUITest
|
|
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": "^
|
|
63
|
+
"@eslint/js": "^10.0.1",
|
|
64
64
|
"@tsconfig/node20": "^20.1.8",
|
|
65
65
|
"@types/archiver": "^7.0.0",
|
|
66
|
-
"@types/jest": "^
|
|
66
|
+
"@types/jest": "^30.0.0",
|
|
67
67
|
"@types/js-yaml": "^4.0.9",
|
|
68
|
-
"@types/node": "^
|
|
68
|
+
"@types/node": "^25.4.0",
|
|
69
69
|
"@types/progress-stream": "^2.0.5",
|
|
70
|
-
"babel-jest": "^
|
|
71
|
-
"eslint": "^
|
|
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": "^
|
|
74
|
+
"jest": "^30.3.0",
|
|
75
75
|
"prettier": "^3.7.4",
|
|
76
76
|
"ts-jest": "^29.4.6",
|
|
77
77
|
"typescript": "^5.9.3",
|