@testrigor/testrigor-cli 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +230 -3
- package/dist/commands/authenticate.d.ts +14 -0
- package/dist/commands/authenticate.js +87 -26
- package/dist/commands/test-suite/config.js +1 -1
- package/dist/commands/test-suite/run.js +253 -234
- package/dist/commands/test-suite/validate-syntax.js +2 -3
- package/dist/flags/chrome-extension.js +3 -2
- package/dist/types.d.ts +0 -12
- package/dist/util/appium.js +92 -34
- package/dist/util/certificate-uploader.js +5 -6
- package/dist/util/config.js +15 -15
- package/dist/util/parser.js +8 -8
- package/dist/util/request-builder.d.ts +2 -8
- package/dist/util/request-builder.js +12 -35
- package/dist/util/trtc.d.ts +2 -0
- package/dist/util/trtc.js +107 -38
- package/dist/util/tunnel.js +7 -6
- package/dist/util/type-guards.js +3 -4
- package/dist/util/utils.d.ts +3 -3
- package/dist/util/utils.js +23 -23
- package/dist/util/variable-file-uploader.js +7 -13
- package/dist/util/variables-path-parser.js +4 -4
- package/npm-shrinkwrap.json +11047 -0
- package/oclif.manifest.json +253 -180
- package/package.json +21 -20
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
3
4
|
const core_1 = require("@oclif/core");
|
|
4
|
-
const
|
|
5
|
-
const
|
|
5
|
+
const fs_1 = tslib_1.__importDefault(require("@supercharge/fs"));
|
|
6
|
+
const fs_2 = require("fs");
|
|
6
7
|
const listr2_1 = require("listr2");
|
|
7
|
-
const node_fetch_commonjs_1 = require("node-fetch-commonjs");
|
|
8
8
|
const command_base_1 = require("../../command-base");
|
|
9
9
|
const environments_1 = require("../../config/environments");
|
|
10
10
|
const chrome_extension_1 = require("../../flags/chrome-extension");
|
|
11
11
|
const parser_1 = require("../../util/parser");
|
|
12
12
|
const request_builder_1 = require("../../util/request-builder");
|
|
13
|
-
const tunnel_1 = require("../../util/tunnel");
|
|
13
|
+
const tunnel_1 = tslib_1.__importDefault(require("../../util/tunnel"));
|
|
14
14
|
const certificate_uploader_1 = require("../../util/certificate-uploader");
|
|
15
15
|
const variable_file_uploader_1 = require("../../util/variable-file-uploader");
|
|
16
16
|
const variables_path_parser_1 = require("../../util/variables-path-parser");
|
|
@@ -31,6 +31,7 @@ const JUNIT_REPORT_STATUS = {
|
|
|
31
31
|
FAILED: "JUnit report generation is failed",
|
|
32
32
|
RUNNING: "JUnit report is still in progress",
|
|
33
33
|
};
|
|
34
|
+
const FAILED_TO_START_TITLE = "Test suite run failed";
|
|
34
35
|
class Run extends command_base_1.CommandBase {
|
|
35
36
|
initializeUrls(flags) {
|
|
36
37
|
const baseUrlWeb = flags["base-url-web"];
|
|
@@ -120,7 +121,7 @@ class Run extends command_base_1.CommandBase {
|
|
|
120
121
|
}
|
|
121
122
|
if (variablesPath) {
|
|
122
123
|
try {
|
|
123
|
-
const file = await
|
|
124
|
+
const file = await fs_1.default.content(variablesPath);
|
|
124
125
|
const parsed = JSON.parse(file.toString());
|
|
125
126
|
const { textValues, fileInputs, certInputs } = (0, variables_path_parser_1.parseVariablesJson)(parsed);
|
|
126
127
|
context.configuration.storedValues = textValues;
|
|
@@ -147,7 +148,7 @@ class Run extends command_base_1.CommandBase {
|
|
|
147
148
|
context.configuration.baselineMutations = testCases;
|
|
148
149
|
}
|
|
149
150
|
}
|
|
150
|
-
catch
|
|
151
|
+
catch {
|
|
151
152
|
core_1.ux.error("--test-cases-path must be a valid JSON path");
|
|
152
153
|
}
|
|
153
154
|
}
|
|
@@ -158,7 +159,7 @@ class Run extends command_base_1.CommandBase {
|
|
|
158
159
|
context.configuration.ruleMutations = rules;
|
|
159
160
|
}
|
|
160
161
|
}
|
|
161
|
-
catch
|
|
162
|
+
catch {
|
|
162
163
|
core_1.ux.error("--rules-path must be a valid JSON path");
|
|
163
164
|
}
|
|
164
165
|
}
|
|
@@ -169,7 +170,7 @@ class Run extends command_base_1.CommandBase {
|
|
|
169
170
|
context.configuration.settings = settings;
|
|
170
171
|
}
|
|
171
172
|
}
|
|
172
|
-
catch
|
|
173
|
+
catch {
|
|
173
174
|
core_1.ux.error("--settings-path must be a valid JSON/YAML path");
|
|
174
175
|
}
|
|
175
176
|
}
|
|
@@ -187,7 +188,7 @@ class Run extends command_base_1.CommandBase {
|
|
|
187
188
|
Object.assign(context.configuration, localTestNodes);
|
|
188
189
|
}
|
|
189
190
|
}
|
|
190
|
-
catch
|
|
191
|
+
catch {
|
|
191
192
|
core_1.ux.error("--local-test-nodes-path must be a valid JSON/YAML path");
|
|
192
193
|
}
|
|
193
194
|
}
|
|
@@ -197,12 +198,12 @@ class Run extends command_base_1.CommandBase {
|
|
|
197
198
|
delete flags["file-path"];
|
|
198
199
|
}
|
|
199
200
|
else {
|
|
200
|
-
const fileExists = await
|
|
201
|
+
const fileExists = await fs_1.default.isFile(filePath);
|
|
201
202
|
if (!fileExists || !(0, utils_1.isValidFileExtensionToUpload)(filePath)) {
|
|
202
203
|
core_1.ux.error("--file-path must be one of the valid format types: [zip, exe, msi, apk, aab, ipa, app]");
|
|
203
204
|
}
|
|
204
|
-
const fileName =
|
|
205
|
-
const fileSize =
|
|
205
|
+
const fileName = fs_1.default.basename(filePath);
|
|
206
|
+
const fileSize = fs_1.default.statSync(filePath).size;
|
|
206
207
|
context.fileProperties = { fileName, fileSize };
|
|
207
208
|
}
|
|
208
209
|
}
|
|
@@ -222,6 +223,11 @@ class Run extends command_base_1.CommandBase {
|
|
|
222
223
|
enabled: () => (flags.localhost || !!localTestNodesPath) && context.isMobile,
|
|
223
224
|
task: (ctx, task) => {
|
|
224
225
|
task.title = "Starting mobile server";
|
|
226
|
+
// A driver that fails to install is tolerated (xcuitest is useless on
|
|
227
|
+
// Linux, uiautomator2 on a Mac targeting iOS), but losing all of them
|
|
228
|
+
// means the server has nothing to drive - fail there, with the
|
|
229
|
+
// reasons, instead of timing out on the health check 30s later.
|
|
230
|
+
const driverFailures = [];
|
|
225
231
|
return task.newListr([
|
|
226
232
|
{
|
|
227
233
|
task: async (_ctx, subtask) => {
|
|
@@ -241,14 +247,22 @@ class Run extends command_base_1.CommandBase {
|
|
|
241
247
|
? `Updating ${driver.name} (${status.version} → ${driver.version})`
|
|
242
248
|
: `Installing ${driver.name}@${driver.version}`;
|
|
243
249
|
const err = await (0, appium_1.ensureDriver)(driver.name, driver.version);
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
250
|
+
if (err) {
|
|
251
|
+
driverFailures.push(`${driver.name}@${driver.version}: ${err}`);
|
|
252
|
+
subtask.title = `Driver ${driver.name} skipped — ${err.split("\n")[0]}`;
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
subtask.title = `Driver ${driver.name}@${driver.version} ready`;
|
|
256
|
+
}
|
|
247
257
|
},
|
|
248
258
|
rendererOptions: { timer: listr2_1.PRESET_TIMER },
|
|
249
259
|
})),
|
|
250
260
|
{
|
|
251
261
|
task: async (ctx, subtask) => {
|
|
262
|
+
if (driverFailures.length === appium_1.REQUIRED_DRIVERS.length) {
|
|
263
|
+
throw new Error("No mobile driver could be installed, so the mobile server has nothing to run:\n" +
|
|
264
|
+
driverFailures.map((f) => ` - ${f}`).join("\n"));
|
|
265
|
+
}
|
|
252
266
|
const result = await (0, appium_1.startAppium)();
|
|
253
267
|
ctx.appiumStartedByUs = !result.alreadyRunning;
|
|
254
268
|
subtask.title = result.alreadyRunning
|
|
@@ -296,90 +310,143 @@ class Run extends command_base_1.CommandBase {
|
|
|
296
310
|
},
|
|
297
311
|
{
|
|
298
312
|
title: "Running test suite",
|
|
299
|
-
task: async (ctx, task) =>
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
313
|
+
task: async (ctx, task) => {
|
|
314
|
+
const steps = task.newListr([
|
|
315
|
+
{
|
|
316
|
+
task: async (ctx) => {
|
|
317
|
+
let pollBranch = flags.branch;
|
|
318
|
+
if (this.isSingleTestCaseExecution(testCaseUuids, flags.branch)) {
|
|
319
|
+
pollBranch = `single-test-execution-${testCaseUuids[0]}`;
|
|
320
|
+
}
|
|
321
|
+
const statusResponse = await this.fetchStatus(testSuiteId, token, pollBranch, ctx.configuration.labels, ctx.configuration.excludedLabels);
|
|
322
|
+
context.lastRunId = (0, utils_1.extractRunIdFromDetailsUrl)(statusResponse.detailsUrl);
|
|
323
|
+
},
|
|
324
|
+
exitOnError: false,
|
|
309
325
|
},
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
task: (ctx) => this.uploadVariableFiles(ctx, testSuiteId, token),
|
|
316
|
-
exitOnError: false,
|
|
317
|
-
},
|
|
318
|
-
{
|
|
319
|
-
title: "Uploading client certificates",
|
|
320
|
-
enabled: () => !!context.storedValueCertInputs?.length,
|
|
321
|
-
task: (ctx, task) => this.uploadClientCertificates(ctx, testSuiteId, token, task),
|
|
322
|
-
exitOnError: false,
|
|
323
|
-
},
|
|
324
|
-
{
|
|
325
|
-
enabled: () => !flags["file-path"] && !flags["chrome-extension"],
|
|
326
|
-
task: async (ctx) => {
|
|
327
|
-
if (flags.url) {
|
|
328
|
-
ctx.configuration.url = flags.url;
|
|
329
|
-
}
|
|
330
|
-
if (flags.branch && flags.commit) {
|
|
331
|
-
ctx.configuration.branch = {
|
|
332
|
-
name: flags.branch,
|
|
333
|
-
commit: flags.commit,
|
|
334
|
-
};
|
|
335
|
-
}
|
|
336
|
-
const response = await this.callRetest(testSuiteId, ctx.configuration, token);
|
|
337
|
-
ctx.response = (await response.json());
|
|
338
|
-
if (!response.ok) {
|
|
339
|
-
const errorMessage = JSON.stringify(ctx.response);
|
|
340
|
-
throw new Error(`Test suite failed to start: ${ctx.response?.msg ||
|
|
341
|
-
ctx.response?.errName ||
|
|
342
|
-
errorMessage}`);
|
|
343
|
-
}
|
|
344
|
-
if (ctx.response?.taskId) {
|
|
345
|
-
task.title = `Running test suite [ ${this.TESTRIGOR_URL}/test-suites/${testSuiteId}/runs/${ctx.response?.taskId} ]`;
|
|
346
|
-
}
|
|
326
|
+
{
|
|
327
|
+
title: "Uploading variable files",
|
|
328
|
+
enabled: () => !!context.storedValueFileInputs?.length,
|
|
329
|
+
task: (ctx) => this.uploadVariableFiles(ctx, testSuiteId, token),
|
|
330
|
+
exitOnError: false,
|
|
347
331
|
},
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
332
|
+
{
|
|
333
|
+
title: "Uploading client certificates",
|
|
334
|
+
enabled: () => !!context.storedValueCertInputs?.length,
|
|
335
|
+
task: (ctx, task) => this.uploadClientCertificates(ctx, testSuiteId, token, task),
|
|
336
|
+
exitOnError: false,
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
enabled: () => !flags["file-path"] && !flags["chrome-extension"],
|
|
340
|
+
task: async (ctx) => {
|
|
341
|
+
if (flags.url) {
|
|
342
|
+
ctx.configuration.url = flags.url;
|
|
343
|
+
}
|
|
344
|
+
if (flags.branch && flags.commit) {
|
|
345
|
+
ctx.configuration.branch = {
|
|
346
|
+
name: flags.branch,
|
|
347
|
+
commit: flags.commit,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
const response = await this.callRetest(testSuiteId, ctx.configuration, token);
|
|
351
|
+
ctx.response = (await response.json());
|
|
352
|
+
if (!response.ok) {
|
|
353
|
+
task.title = FAILED_TO_START_TITLE;
|
|
354
|
+
const errorMessage = JSON.stringify(ctx.response);
|
|
355
|
+
throw new Error(`Test suite failed to start: ${ctx.response?.msg ||
|
|
356
|
+
ctx.response?.errName ||
|
|
357
|
+
errorMessage}`);
|
|
358
|
+
}
|
|
359
|
+
if (ctx.response?.taskId) {
|
|
360
|
+
task.title = `Running test suite [ ${this.TESTRIGOR_URL}/test-suites/${testSuiteId}/runs/${ctx.response?.taskId} ]`;
|
|
361
|
+
}
|
|
362
|
+
},
|
|
363
|
+
exitOnError: false,
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
title: "Uploading Chrome extension(s)",
|
|
367
|
+
enabled: () => !!context.chromeExtensions?.length,
|
|
368
|
+
task: async (ctx) => {
|
|
369
|
+
if (flags.url) {
|
|
370
|
+
ctx.configuration.url = flags.url;
|
|
371
|
+
}
|
|
372
|
+
if (flags.branch && flags.commit) {
|
|
373
|
+
ctx.configuration.branch = {
|
|
374
|
+
name: flags.branch,
|
|
375
|
+
commit: flags.commit,
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
const form = await (0, request_builder_1.buildChromeExtensionFormData)(ctx.chromeExtensions);
|
|
379
|
+
form.append("data", JSON.stringify(ctx.configuration));
|
|
380
|
+
const controller = new AbortController();
|
|
381
|
+
const timeoutId = setTimeout(() => controller.abort(), utils_1.UPLOAD_TIMEOUT_MS);
|
|
382
|
+
try {
|
|
383
|
+
const response = await fetch(`${this.TESTRIGOR_API2_URL}/apps/${testSuiteId}/retest`, {
|
|
384
|
+
method: "POST",
|
|
385
|
+
body: form,
|
|
386
|
+
headers: {
|
|
387
|
+
Accept: "application/json",
|
|
388
|
+
"auth-token": token,
|
|
389
|
+
},
|
|
390
|
+
signal: controller.signal,
|
|
391
|
+
});
|
|
392
|
+
const retestApi2Response = (await response.json());
|
|
393
|
+
if (!response.ok || retestApi2Response.status >= 300) {
|
|
394
|
+
throw new Error(`Chrome extension upload failed: ${retestApi2Response?.message ||
|
|
395
|
+
retestApi2Response?.errors}`);
|
|
396
|
+
}
|
|
397
|
+
ctx.response = {
|
|
398
|
+
result: "ok",
|
|
399
|
+
msg: retestApi2Response.message,
|
|
400
|
+
taskId: retestApi2Response.data?.taskId,
|
|
401
|
+
queueId: retestApi2Response.data?.queueId,
|
|
402
|
+
};
|
|
403
|
+
if (ctx.response?.taskId) {
|
|
404
|
+
task.title = `Running test suite [ ${this.TESTRIGOR_URL}/test-suites/${testSuiteId}/runs/${ctx.response?.taskId} ]`;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
catch (error) {
|
|
408
|
+
if (error.name === "AbortError") {
|
|
409
|
+
throw new Error("Chrome extension upload timed out. Please check your network connection.");
|
|
410
|
+
}
|
|
411
|
+
throw error;
|
|
412
|
+
}
|
|
413
|
+
finally {
|
|
414
|
+
clearTimeout(timeoutId);
|
|
415
|
+
}
|
|
416
|
+
},
|
|
417
|
+
exitOnError: false,
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
title: "Uploading file",
|
|
421
|
+
enabled: () => context.fileProperties &&
|
|
422
|
+
context.fileProperties.fileSize < utils_1.MAX_FILE_SIZE_100_MB,
|
|
423
|
+
task: async (ctx) => {
|
|
424
|
+
if (flags.branch && flags.commit) {
|
|
425
|
+
ctx.configuration.branch = {
|
|
426
|
+
name: flags.branch,
|
|
427
|
+
commit: flags.commit,
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
if (!flags["file-path"]) {
|
|
431
|
+
throw new Error("file-path is not provided");
|
|
432
|
+
}
|
|
433
|
+
const configuration = ctx.configuration;
|
|
434
|
+
const filePath = flags["file-path"];
|
|
435
|
+
const form = new FormData();
|
|
436
|
+
form.append("file", await (0, fs_2.openAsBlob)(filePath), fs_1.default.basename(filePath));
|
|
437
|
+
form.append("data", JSON.stringify(configuration));
|
|
438
|
+
const response = await fetch(`${this.TESTRIGOR_API2_URL}/apps/${testSuiteId}/retest`, {
|
|
375
439
|
method: "POST",
|
|
376
440
|
body: form,
|
|
377
|
-
headers:
|
|
378
|
-
|
|
441
|
+
headers: {
|
|
442
|
+
Accept: "application/json",
|
|
443
|
+
"auth-token": token,
|
|
444
|
+
},
|
|
379
445
|
});
|
|
380
446
|
const retestApi2Response = (await response.json());
|
|
381
447
|
if (!response.ok || retestApi2Response.status >= 300) {
|
|
382
|
-
|
|
448
|
+
task.title = FAILED_TO_START_TITLE;
|
|
449
|
+
throw new Error(`Test suite failed to start: ${retestApi2Response?.message ||
|
|
383
450
|
retestApi2Response?.errors}`);
|
|
384
451
|
}
|
|
385
452
|
ctx.response = {
|
|
@@ -388,145 +455,101 @@ class Run extends command_base_1.CommandBase {
|
|
|
388
455
|
taskId: retestApi2Response.data?.taskId,
|
|
389
456
|
queueId: retestApi2Response.data?.queueId,
|
|
390
457
|
};
|
|
391
|
-
|
|
392
|
-
|
|
458
|
+
},
|
|
459
|
+
exitOnError: false,
|
|
460
|
+
},
|
|
461
|
+
{
|
|
462
|
+
title: "Uploading file (> 100 MB)",
|
|
463
|
+
enabled: () => context.fileProperties &&
|
|
464
|
+
context.fileProperties.fileSize >= utils_1.MAX_FILE_SIZE_100_MB,
|
|
465
|
+
task: async (ctx) => {
|
|
466
|
+
if (flags.branch && flags.commit) {
|
|
467
|
+
ctx.configuration.branch = {
|
|
468
|
+
name: flags.branch,
|
|
469
|
+
commit: flags.commit,
|
|
470
|
+
};
|
|
393
471
|
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
if (error.name === "AbortError") {
|
|
397
|
-
throw new Error("Chrome extension upload timed out. Please check your network connection.");
|
|
472
|
+
if (!flags["file-path"]) {
|
|
473
|
+
throw new Error("file-path is not provided");
|
|
398
474
|
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
task: async (ctx) => {
|
|
413
|
-
if (flags.branch && flags.commit) {
|
|
414
|
-
ctx.configuration.branch = {
|
|
415
|
-
name: flags.branch,
|
|
416
|
-
commit: flags.commit,
|
|
417
|
-
};
|
|
418
|
-
}
|
|
419
|
-
if (!flags["file-path"]) {
|
|
420
|
-
throw new Error("file-path is not provided");
|
|
421
|
-
}
|
|
422
|
-
const configuration = ctx.configuration;
|
|
423
|
-
const filePath = flags["file-path"];
|
|
424
|
-
const form = new FormData();
|
|
425
|
-
form.append("file", Fs.createReadStream(filePath));
|
|
426
|
-
form.append("data", JSON.stringify(configuration));
|
|
427
|
-
const response = await (0, node_fetch_commonjs_1.default)(`${this.TESTRIGOR_API2_URL}/apps/${testSuiteId}/retest`, {
|
|
428
|
-
method: "POST",
|
|
429
|
-
body: form,
|
|
430
|
-
headers: {
|
|
431
|
-
...form.getHeaders(),
|
|
432
|
-
Accept: "application/json",
|
|
433
|
-
"auth-token": token,
|
|
434
|
-
},
|
|
435
|
-
});
|
|
436
|
-
const retestApi2Response = (await response.json());
|
|
437
|
-
if (!response.ok || retestApi2Response.status >= 300) {
|
|
438
|
-
throw new Error(`Test suite failed to start: ${retestApi2Response?.message ||
|
|
439
|
-
retestApi2Response?.errors}`);
|
|
440
|
-
}
|
|
441
|
-
ctx.response = {
|
|
442
|
-
result: "ok",
|
|
443
|
-
msg: retestApi2Response.message,
|
|
444
|
-
taskId: retestApi2Response.data?.taskId,
|
|
445
|
-
queueId: retestApi2Response.data?.queueId,
|
|
446
|
-
};
|
|
475
|
+
if (!ctx.fileProperties) {
|
|
476
|
+
throw new Error(`Error getting details of file provided by --file-path ${flags["file-path"]}`);
|
|
477
|
+
}
|
|
478
|
+
const configuration = ctx.configuration;
|
|
479
|
+
const filePath = flags["file-path"];
|
|
480
|
+
const response = await this.uploadFile(task, testSuiteId, configuration, filePath, token, ctx.fileProperties);
|
|
481
|
+
ctx.response = (await response.json());
|
|
482
|
+
if (!response.ok) {
|
|
483
|
+
task.title = FAILED_TO_START_TITLE;
|
|
484
|
+
throw new Error(`Test suite failed to start: ${ctx.response?.msg || ctx.response?.errName}`);
|
|
485
|
+
}
|
|
486
|
+
},
|
|
487
|
+
exitOnError: false,
|
|
447
488
|
},
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
ctx.configuration.
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
if (!flags["file-path"]) {
|
|
462
|
-
throw new Error("file-path is not provided");
|
|
463
|
-
}
|
|
464
|
-
if (!ctx.fileProperties) {
|
|
465
|
-
throw new Error(`Error getting details of file provided by --file-path ${flags["file-path"]}`);
|
|
466
|
-
}
|
|
467
|
-
const configuration = ctx.configuration;
|
|
468
|
-
const filePath = flags["file-path"];
|
|
469
|
-
const response = await this.uploadFile(task, testSuiteId, configuration, filePath, token, ctx.fileProperties);
|
|
470
|
-
ctx.response = (await response.json());
|
|
471
|
-
if (!response.ok) {
|
|
472
|
-
throw new Error(`Test suite failed to start: ${ctx.response?.msg || ctx.response?.errName}`);
|
|
473
|
-
}
|
|
489
|
+
{
|
|
490
|
+
title: "Waiting for test suite run creation",
|
|
491
|
+
enabled: (ctx) => ctx.response?.queueId,
|
|
492
|
+
task: async (ctx, currentTask) => {
|
|
493
|
+
let pollBranch = flags.branch;
|
|
494
|
+
if (this.isSingleTestCaseExecution(testCaseUuids, flags.branch)) {
|
|
495
|
+
pollBranch = `single-test-execution-${testCaseUuids[0]}`;
|
|
496
|
+
}
|
|
497
|
+
const detailsUrl = await this.waitForTestSuiteToBeCreated(testSuiteId, token, ctx.lastRunId, pollBranch, ctx.configuration.labels, ctx.configuration.excludedLabels);
|
|
498
|
+
task.title = `Running test suite [ ${detailsUrl} ]`;
|
|
499
|
+
currentTask.title = "Test suite run created successfully";
|
|
500
|
+
},
|
|
501
|
+
exitOnError: false,
|
|
474
502
|
},
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
503
|
+
{
|
|
504
|
+
title: "Checking status",
|
|
505
|
+
enabled: (ctx) => ctx.response?.result === "ok" && !flags.async,
|
|
506
|
+
task: async (ctx, task) => {
|
|
507
|
+
let pollBranch = flags.branch;
|
|
508
|
+
if (this.isSingleTestCaseExecution(testCaseUuids, flags.branch)) {
|
|
509
|
+
pollBranch = `single-test-execution-${testCaseUuids[0]}`;
|
|
510
|
+
}
|
|
511
|
+
return task.newListr([
|
|
512
|
+
{
|
|
513
|
+
task: async (ctx, statusTask) => {
|
|
514
|
+
await this.waitForTestSuiteToFinish(testSuiteId, token, statusTask, pollBranch, ctx.configuration.labels, ctx.configuration.excludedLabels);
|
|
515
|
+
},
|
|
516
|
+
},
|
|
517
|
+
]);
|
|
518
|
+
},
|
|
519
|
+
exitOnError: false,
|
|
488
520
|
},
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
if (this.isSingleTestCaseExecution(testCaseUuids, flags.branch)) {
|
|
497
|
-
pollBranch = `single-test-execution-${testCaseUuids[0]}`;
|
|
498
|
-
}
|
|
499
|
-
return task.newListr([
|
|
521
|
+
{
|
|
522
|
+
title: "Generating JUnit report",
|
|
523
|
+
enabled: (ctx) => ctx.response?.result === "ok" &&
|
|
524
|
+
!flags.async &&
|
|
525
|
+
flags["junit-report-save-path"] &&
|
|
526
|
+
ctx.response?.taskId,
|
|
527
|
+
task: async (ctx, task) => task.newListr([
|
|
500
528
|
{
|
|
501
529
|
task: async (ctx, statusTask) => {
|
|
502
|
-
await this.
|
|
530
|
+
await this.startAndWaitForJunitReportToFinish(testSuiteId, String(ctx.response?.taskId), String(flags["junit-report-save-path"]), token, statusTask);
|
|
503
531
|
},
|
|
504
532
|
},
|
|
505
|
-
])
|
|
533
|
+
]),
|
|
534
|
+
exitOnError: false,
|
|
506
535
|
},
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
flags["junit-report-save-path"] &&
|
|
514
|
-
ctx.response?.taskId,
|
|
515
|
-
task: async (ctx, task) => task.newListr([
|
|
516
|
-
{
|
|
517
|
-
task: async (ctx, statusTask) => {
|
|
518
|
-
await this.startAndWaitForJunitReportToFinish(testSuiteId, String(ctx.response?.taskId), String(flags["junit-report-save-path"]), token, statusTask);
|
|
519
|
-
},
|
|
536
|
+
{
|
|
537
|
+
task: () => {
|
|
538
|
+
const failed = steps.tasks.find((step) => step.hasFailed());
|
|
539
|
+
if (failed) {
|
|
540
|
+
throw new Error(failed.message?.error ?? FAILED_TO_START_TITLE);
|
|
541
|
+
}
|
|
520
542
|
},
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
543
|
+
exitOnError: true,
|
|
544
|
+
},
|
|
545
|
+
], {
|
|
546
|
+
concurrent: false,
|
|
547
|
+
rendererOptions: { collapseSubtasks: false, timer: listr2_1.PRESET_TIMER },
|
|
548
|
+
fallbackRendererCondition: true,
|
|
549
|
+
fallbackRendererOptions: { timer: listr2_1.PRESET_TIMER },
|
|
550
|
+
});
|
|
551
|
+
return steps;
|
|
552
|
+
},
|
|
530
553
|
exitOnError: false,
|
|
531
554
|
rendererOptions: {
|
|
532
555
|
timer: listr2_1.PRESET_TIMER,
|
|
@@ -568,7 +591,7 @@ class Run extends command_base_1.CommandBase {
|
|
|
568
591
|
}
|
|
569
592
|
async fetchStatus(testSuiteId, token, branch, labels, excludedLabels) {
|
|
570
593
|
const statusApiEndpoint = this.getStatusApiEndpoint(testSuiteId, branch, labels, excludedLabels);
|
|
571
|
-
const response = await (
|
|
594
|
+
const response = await fetch(statusApiEndpoint, {
|
|
572
595
|
method: "GET",
|
|
573
596
|
headers: {
|
|
574
597
|
Accept: "application/json",
|
|
@@ -659,7 +682,7 @@ class Run extends command_base_1.CommandBase {
|
|
|
659
682
|
}
|
|
660
683
|
}
|
|
661
684
|
async callRetest(testSuiteId, configuration, token) {
|
|
662
|
-
return (
|
|
685
|
+
return fetch(`${this.TESTRIGOR_API_URL}/apps/${testSuiteId}/retest`, {
|
|
663
686
|
method: "POST",
|
|
664
687
|
body: JSON.stringify(configuration),
|
|
665
688
|
headers: {
|
|
@@ -670,7 +693,7 @@ class Run extends command_base_1.CommandBase {
|
|
|
670
693
|
});
|
|
671
694
|
}
|
|
672
695
|
async fetchSuiteType(testSuiteId, token) {
|
|
673
|
-
const response = await (
|
|
696
|
+
const response = await fetch(`${this.TESTRIGOR_API_URL}/apps/${testSuiteId}/status`, {
|
|
674
697
|
method: "GET",
|
|
675
698
|
headers: {
|
|
676
699
|
Accept: "application/json",
|
|
@@ -691,7 +714,7 @@ class Run extends command_base_1.CommandBase {
|
|
|
691
714
|
const body = {
|
|
692
715
|
fileName: fileProperties.fileName,
|
|
693
716
|
};
|
|
694
|
-
const preSignedUrl = await (
|
|
717
|
+
const preSignedUrl = await fetch(`${this.TESTRIGOR_API2_URL}/apps/${testSuiteId}/retest/pre-signed-url`, {
|
|
695
718
|
method: "POST",
|
|
696
719
|
body: JSON.stringify(body),
|
|
697
720
|
headers: {
|
|
@@ -707,13 +730,9 @@ class Run extends command_base_1.CommandBase {
|
|
|
707
730
|
throw new Error(`Failed to prepare upload: ${preSignedUrlResponse.message}`);
|
|
708
731
|
}
|
|
709
732
|
const preSignedUrlData = preSignedUrlResponse.data;
|
|
710
|
-
const
|
|
711
|
-
const uploadFileResponse = await (0, node_fetch_commonjs_1.default)(preSignedUrlData.url, {
|
|
733
|
+
const uploadFileResponse = await fetch(preSignedUrlData.url, {
|
|
712
734
|
method: "PUT",
|
|
713
|
-
body:
|
|
714
|
-
headers: {
|
|
715
|
-
"Content-length": `${fileProperties.fileSize}`,
|
|
716
|
-
},
|
|
735
|
+
body: await (0, fs_2.openAsBlob)(filePath),
|
|
717
736
|
});
|
|
718
737
|
if (!uploadFileResponse.ok) {
|
|
719
738
|
throw new Error(`Failed to upload file: ${uploadFileResponse.statusText}`);
|
|
@@ -774,7 +793,7 @@ class Run extends command_base_1.CommandBase {
|
|
|
774
793
|
}
|
|
775
794
|
}
|
|
776
795
|
async fetchTestSuiteStatus(statusApiEndpoint, token) {
|
|
777
|
-
return await (
|
|
796
|
+
return await fetch(statusApiEndpoint, {
|
|
778
797
|
method: "GET",
|
|
779
798
|
headers: {
|
|
780
799
|
Accept: "application/json",
|
|
@@ -810,7 +829,7 @@ class Run extends command_base_1.CommandBase {
|
|
|
810
829
|
const url = `${this.TESTRIGOR_API2_URL}/apps/${testSuiteId}/runs/${runId}/junit_report`;
|
|
811
830
|
for (;;) {
|
|
812
831
|
// eslint-disable-next-line no-await-in-loop
|
|
813
|
-
const response = await (
|
|
832
|
+
const response = await fetch(url, {
|
|
814
833
|
method: "GET",
|
|
815
834
|
headers: {
|
|
816
835
|
Accept: "application/json",
|
|
@@ -823,7 +842,7 @@ class Run extends command_base_1.CommandBase {
|
|
|
823
842
|
throw new Error(`Unexpected contentType of junit report: ${contentType}`);
|
|
824
843
|
}
|
|
825
844
|
const xmlData = await response.text();
|
|
826
|
-
await
|
|
845
|
+
await fs_1.default.writeFile(savePath, xmlData);
|
|
827
846
|
task.title = JUNIT_REPORT_STATUS.READY;
|
|
828
847
|
return;
|
|
829
848
|
}
|
|
@@ -839,7 +858,6 @@ class Run extends command_base_1.CommandBase {
|
|
|
839
858
|
}
|
|
840
859
|
}
|
|
841
860
|
}
|
|
842
|
-
exports.default = Run;
|
|
843
861
|
Run.description = "Run all tests of a Test Suite";
|
|
844
862
|
Run.examples = [];
|
|
845
863
|
Run.flags = {
|
|
@@ -928,3 +946,4 @@ Run.args = {
|
|
|
928
946
|
required: false,
|
|
929
947
|
}),
|
|
930
948
|
};
|
|
949
|
+
exports.default = Run;
|