@testomatio/reporter 2.7.8 → 2.7.9-beta.2-markdown
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 +1 -0
- package/lib/bin/cli.js +1 -1
- package/lib/client.js +52 -2
- package/lib/constants.d.ts +7 -0
- package/lib/constants.js +13 -1
- package/lib/pipe/debug.d.ts +2 -0
- package/lib/pipe/debug.js +29 -13
- package/lib/pipe/html.js +21 -108
- package/lib/pipe/index.js +2 -0
- package/lib/pipe/markdown.d.ts +25 -0
- package/lib/pipe/markdown.js +665 -0
- package/lib/replay.d.ts +2 -1
- package/lib/replay.js +20 -15
- package/lib/template/testomatio.hbs +0 -2
- package/lib/utils/debug.d.ts +12 -0
- package/lib/utils/debug.js +27 -0
- package/package.json +1 -1
- package/src/bin/cli.js +2 -2
- package/src/client.js +49 -3
- package/src/constants.js +10 -0
- package/src/pipe/debug.js +27 -13
- package/src/pipe/html.js +18 -108
- package/src/pipe/index.js +2 -0
- package/src/pipe/markdown.js +707 -0
- package/src/replay.js +23 -17
- package/src/template/testomatio.hbs +0 -2
- package/src/utils/debug.js +20 -0
- package/types/types.d.ts +5 -0
package/lib/replay.js
CHANGED
|
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.Replay = void 0;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
|
-
const os_1 = __importDefault(require("os"));
|
|
10
9
|
const client_js_1 = __importDefault(require("./client.js"));
|
|
11
10
|
const constants_js_1 = require("./constants.js");
|
|
12
11
|
const config_js_1 = require("./config.js");
|
|
@@ -19,11 +18,12 @@ class Replay {
|
|
|
19
18
|
this.onError = options.onError || console.error;
|
|
20
19
|
}
|
|
21
20
|
/**
|
|
22
|
-
* Get the default debug file path
|
|
21
|
+
* Get the default debug file path.
|
|
22
|
+
* Returns ./testomatio.debug.json (actual file in CI, symlink to tmp file in local).
|
|
23
23
|
* @returns {string} Path to the latest debug file
|
|
24
24
|
*/
|
|
25
25
|
getDefaultDebugFile() {
|
|
26
|
-
return path_1.default.join(
|
|
26
|
+
return path_1.default.join(process.cwd(), `${constants_js_1.DEBUG_FILE}.json`);
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
29
|
* Parse a debug file and extract test data
|
|
@@ -125,8 +125,11 @@ class Replay {
|
|
|
125
125
|
testsWithoutRid.push({ ...test });
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
|
-
else if (logEntry.
|
|
128
|
+
else if (logEntry.action === 'finishRun') {
|
|
129
129
|
finishParams = logEntry.params || {};
|
|
130
|
+
if (logEntry.runId && !runId) {
|
|
131
|
+
runId = logEntry.runId;
|
|
132
|
+
}
|
|
130
133
|
}
|
|
131
134
|
}
|
|
132
135
|
catch (err) {
|
|
@@ -197,22 +200,25 @@ class Replay {
|
|
|
197
200
|
dryRun: true,
|
|
198
201
|
};
|
|
199
202
|
}
|
|
200
|
-
|
|
203
|
+
if (runId) {
|
|
204
|
+
this.onLog(`Using existing run ID: ${runId}`);
|
|
205
|
+
process.env.TESTOMATIO_RUN = runId;
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
this.onLog('Publishing to run...');
|
|
209
|
+
}
|
|
210
|
+
process.env.TESTOMATIO_REPLAY = '1';
|
|
201
211
|
const client = new client_js_1.default({
|
|
202
212
|
apiKey: this.apiKey,
|
|
203
213
|
isBatchEnabled: true,
|
|
204
214
|
...runParams,
|
|
215
|
+
...(runId && { runId }),
|
|
205
216
|
});
|
|
206
|
-
// Use the stored runId if available, otherwise create a new run
|
|
207
217
|
if (runId) {
|
|
208
|
-
this.onLog(`Using existing run ID: ${runId}`);
|
|
209
218
|
client.runId = runId;
|
|
219
|
+
client.pipeStore.runId = runId;
|
|
210
220
|
}
|
|
211
|
-
|
|
212
|
-
this.onLog('Publishing to run...');
|
|
213
|
-
await client.createRun(runParams);
|
|
214
|
-
}
|
|
215
|
-
// Send each test result
|
|
221
|
+
await client.createRun(runParams);
|
|
216
222
|
let successCount = 0;
|
|
217
223
|
let failureCount = 0;
|
|
218
224
|
for (const [index, test] of tests.entries()) {
|
|
@@ -239,7 +245,8 @@ class Replay {
|
|
|
239
245
|
}
|
|
240
246
|
}
|
|
241
247
|
await client.updateRunStatus(finishParams.status || constants_js_1.STATUS.FINISHED);
|
|
242
|
-
|
|
248
|
+
this.onLog(`Successfully replayed ${successCount}/${tests.length} tests from debug file`);
|
|
249
|
+
return {
|
|
243
250
|
success: true,
|
|
244
251
|
testsCount: tests.length,
|
|
245
252
|
successCount,
|
|
@@ -249,8 +256,6 @@ class Replay {
|
|
|
249
256
|
envVars,
|
|
250
257
|
runId: runId || client.runId,
|
|
251
258
|
};
|
|
252
|
-
this.onLog(`Successfully replayed ${successCount}/${tests.length} tests from debug file`);
|
|
253
|
-
return result;
|
|
254
259
|
}
|
|
255
260
|
}
|
|
256
261
|
exports.Replay = Replay;
|
|
@@ -2242,7 +2242,6 @@
|
|
|
2242
2242
|
<div class='env-var-item {{#unless this.isSet}}env-var-unset{{/unless}}'>
|
|
2243
2243
|
<div class='env-var-info'>
|
|
2244
2244
|
<div class='env-var-key'>{{@key}}</div>
|
|
2245
|
-
<div class='env-var-description'>{{this.description}}</div>
|
|
2246
2245
|
</div>
|
|
2247
2246
|
<div class='env-var-value {{#unless this.isSet}}env-var-empty{{/unless}} {{#if this.isSensitive}}env-var-confidential{{/if}}'>
|
|
2248
2247
|
{{#if this.isSensitive}}
|
|
@@ -2267,7 +2266,6 @@
|
|
|
2267
2266
|
<div class='env-var-item {{#unless this.isSet}}env-var-unset{{/unless}}'>
|
|
2268
2267
|
<div class='env-var-info'>
|
|
2269
2268
|
<div class='env-var-key'>{{@key}}</div>
|
|
2270
|
-
<div class='env-var-description'>{{this.description}}</div>
|
|
2271
2269
|
</div>
|
|
2272
2270
|
<div class='env-var-value {{#unless this.isSet}}env-var-empty{{/unless}} {{#if this.isSensitive}}env-var-confidential{{/if}}'>
|
|
2273
2271
|
{{#if this.isSensitive}}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get the debug file path(s).
|
|
3
|
+
*
|
|
4
|
+
* Always creates a timestamped file in tmp dir and a symlink in project root.
|
|
5
|
+
*
|
|
6
|
+
* @param {string} [suffix] - Optional suffix appended to the base name (e.g. 'replay').
|
|
7
|
+
* @returns {{root: string, tmp: string}} root path (symlink), tmp path (actual file)
|
|
8
|
+
*/
|
|
9
|
+
export function getDebugFilePath(suffix?: string): {
|
|
10
|
+
root: string;
|
|
11
|
+
tmp: string;
|
|
12
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getDebugFilePath = getDebugFilePath;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const os_1 = __importDefault(require("os"));
|
|
9
|
+
const constants_js_1 = require("../constants.js");
|
|
10
|
+
/**
|
|
11
|
+
* Get the debug file path(s).
|
|
12
|
+
*
|
|
13
|
+
* Always creates a timestamped file in tmp dir and a symlink in project root.
|
|
14
|
+
*
|
|
15
|
+
* @param {string} [suffix] - Optional suffix appended to the base name (e.g. 'replay').
|
|
16
|
+
* @returns {{root: string, tmp: string}} root path (symlink), tmp path (actual file)
|
|
17
|
+
*/
|
|
18
|
+
function getDebugFilePath(suffix = '') {
|
|
19
|
+
const dateTime = new Date().toISOString().slice(0, 19).replace(/[:.]/g, '-');
|
|
20
|
+
const baseName = suffix ? `${constants_js_1.DEBUG_FILE}-${suffix}` : constants_js_1.DEBUG_FILE;
|
|
21
|
+
return {
|
|
22
|
+
root: path_1.default.join(process.cwd(), `${baseName}.json`),
|
|
23
|
+
tmp: path_1.default.join(os_1.default.tmpdir(), `${baseName}.${dateTime}.json`),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports.getDebugFilePath = getDebugFilePath;
|
package/package.json
CHANGED
package/src/bin/cli.js
CHANGED
|
@@ -6,7 +6,7 @@ import { glob } from 'glob';
|
|
|
6
6
|
import createDebugMessages from 'debug';
|
|
7
7
|
import TestomatClient from '../client.js';
|
|
8
8
|
import XmlReader from '../xmlReader.js';
|
|
9
|
-
import { APP_PREFIX, STATUS } from '../constants.js';
|
|
9
|
+
import { APP_PREFIX, STATUS, DEBUG_FILE } from '../constants.js';
|
|
10
10
|
import { cleanLatestRunId, getPackageVersion, applyFilter } from '../utils/utils.js';
|
|
11
11
|
import { config } from '../config.js';
|
|
12
12
|
import { readLatestRunId } from '../utils/utils.js';
|
|
@@ -370,7 +370,7 @@ program
|
|
|
370
370
|
program
|
|
371
371
|
.command('replay')
|
|
372
372
|
.description('Replay test data from debug file and re-send to Testomat.io')
|
|
373
|
-
.argument('[debug-file]',
|
|
373
|
+
.argument('[debug-file]', `Path to debug file. Defaults to ./${DEBUG_FILE}.json`)
|
|
374
374
|
.option('--dry-run', 'Preview the data without sending to Testomat.io')
|
|
375
375
|
.action(async (debugFile, opts) => {
|
|
376
376
|
try {
|
package/src/client.js
CHANGED
|
@@ -215,6 +215,10 @@ class Client {
|
|
|
215
215
|
const { rid, error = null, steps: originalSteps, title, suite_title } = testData;
|
|
216
216
|
let steps = originalSteps;
|
|
217
217
|
|
|
218
|
+
// Capture step artifact paths BEFORE uploadStepArtifacts mutates them to URLs,
|
|
219
|
+
// so we can exclude them from the test-level artifacts list later.
|
|
220
|
+
const stepArtifactPaths = collectStepArtifactPaths(steps);
|
|
221
|
+
|
|
218
222
|
// Upload artifacts from steps
|
|
219
223
|
try {
|
|
220
224
|
await this.uploadStepArtifacts(steps, rid);
|
|
@@ -228,7 +232,6 @@ class Client {
|
|
|
228
232
|
const {
|
|
229
233
|
time = 0,
|
|
230
234
|
example = null,
|
|
231
|
-
files = [],
|
|
232
235
|
filesBuffers = [],
|
|
233
236
|
code = null,
|
|
234
237
|
file,
|
|
@@ -236,11 +239,17 @@ class Client {
|
|
|
236
239
|
test_id,
|
|
237
240
|
timestamp,
|
|
238
241
|
links,
|
|
239
|
-
manuallyAttachedArtifacts,
|
|
240
242
|
overwrite,
|
|
241
243
|
tags,
|
|
242
244
|
} = testData;
|
|
243
|
-
let { message = '', meta = {} } = testData;
|
|
245
|
+
let { files = [], manuallyAttachedArtifacts, message = '', meta = {} } = testData;
|
|
246
|
+
|
|
247
|
+
if (stepArtifactPaths.size) {
|
|
248
|
+
files = files.filter(f => !isStepArtifact(f, stepArtifactPaths));
|
|
249
|
+
if (Array.isArray(manuallyAttachedArtifacts)) {
|
|
250
|
+
manuallyAttachedArtifacts = manuallyAttachedArtifacts.filter(a => !isStepArtifact(a, stepArtifactPaths));
|
|
251
|
+
}
|
|
252
|
+
}
|
|
244
253
|
|
|
245
254
|
meta = Object.entries(meta)
|
|
246
255
|
.filter(([, value]) => value !== null && value !== undefined)
|
|
@@ -450,6 +459,43 @@ class Client {
|
|
|
450
459
|
}
|
|
451
460
|
}
|
|
452
461
|
|
|
462
|
+
/**
|
|
463
|
+
* Walks the step tree and returns the set of artifact path/url values
|
|
464
|
+
* referenced by `step.artifacts` at any depth.
|
|
465
|
+
*
|
|
466
|
+
* @param {any} steps
|
|
467
|
+
* @returns {Set<string>}
|
|
468
|
+
*/
|
|
469
|
+
function collectStepArtifactPaths(steps) {
|
|
470
|
+
const paths = new Set();
|
|
471
|
+
if (!Array.isArray(steps)) return paths;
|
|
472
|
+
const walk = arr => {
|
|
473
|
+
for (const step of arr) {
|
|
474
|
+
if (!step) continue;
|
|
475
|
+
if (Array.isArray(step.artifacts)) {
|
|
476
|
+
for (const a of step.artifacts) {
|
|
477
|
+
if (typeof a === 'string') paths.add(a);
|
|
478
|
+
else if (a && typeof a === 'object' && typeof a.path === 'string') paths.add(a.path);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
if (Array.isArray(step.steps)) walk(step.steps);
|
|
482
|
+
}
|
|
483
|
+
};
|
|
484
|
+
walk(steps);
|
|
485
|
+
return paths;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* @param {string|{path?: string}|null|undefined} item
|
|
490
|
+
* @param {Set<string>} paths
|
|
491
|
+
* @returns {boolean}
|
|
492
|
+
*/
|
|
493
|
+
function isStepArtifact(item, paths) {
|
|
494
|
+
if (!item) return false;
|
|
495
|
+
const p = typeof item === 'object' ? item.path : item;
|
|
496
|
+
return typeof p === 'string' && paths.has(p);
|
|
497
|
+
}
|
|
498
|
+
|
|
453
499
|
/**
|
|
454
500
|
*
|
|
455
501
|
* @param {TestData} testData
|
package/src/constants.js
CHANGED
|
@@ -35,6 +35,12 @@ const HTML_REPORT = {
|
|
|
35
35
|
TEMPLATE_NAME: 'testomatio.hbs',
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
+
// markdown pipe var
|
|
39
|
+
const MARKDOWN_REPORT = {
|
|
40
|
+
FOLDER: 'md-report',
|
|
41
|
+
REPORT_DEFAULT_NAME: 'testomatio-report.md',
|
|
42
|
+
};
|
|
43
|
+
|
|
38
44
|
const testomatLogoURL = 'https://avatars.githubusercontent.com/u/59105116?s=36&v=4';
|
|
39
45
|
|
|
40
46
|
const REPORTER_REQUEST_RETRIES = {
|
|
@@ -44,6 +50,8 @@ const REPORTER_REQUEST_RETRIES = {
|
|
|
44
50
|
withinTimeSeconds: Number(process.env.TESTOMATIO_MAX_REQUEST_RETRIES_WITHIN_TIME_SECONDS) || 60,
|
|
45
51
|
};
|
|
46
52
|
|
|
53
|
+
const DEBUG_FILE = 'testomatio.debug';
|
|
54
|
+
|
|
47
55
|
function getCreateRunRequestTimeout() {
|
|
48
56
|
return Math.max(REQUEST_TIMEOUT, 80 * 1000);
|
|
49
57
|
}
|
|
@@ -54,9 +62,11 @@ export {
|
|
|
54
62
|
CSV_HEADERS,
|
|
55
63
|
STATUS,
|
|
56
64
|
HTML_REPORT,
|
|
65
|
+
MARKDOWN_REPORT,
|
|
57
66
|
REQUEST_TIMEOUT,
|
|
58
67
|
getCreateRunRequestTimeout,
|
|
59
68
|
testomatLogoURL,
|
|
60
69
|
REPORTER_REQUEST_RETRIES,
|
|
61
70
|
SCREENSHOTS_ON_STEPS,
|
|
71
|
+
DEBUG_FILE,
|
|
62
72
|
};
|
package/src/pipe/debug.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import os from 'os';
|
|
4
3
|
import createDebugMessages from 'debug';
|
|
5
4
|
import prettyMs from 'pretty-ms';
|
|
6
5
|
import { log } from '../utils/log.js';
|
|
6
|
+
import { getDebugFilePath } from '../utils/debug.js';
|
|
7
7
|
|
|
8
8
|
const debug = createDebugMessages('@testomatio/reporter:pipe:debug');
|
|
9
9
|
|
|
@@ -21,23 +21,33 @@ export class DebugPipe {
|
|
|
21
21
|
tests: [],
|
|
22
22
|
batchIndex: 0,
|
|
23
23
|
};
|
|
24
|
-
|
|
24
|
+
const suffix = process.env.TESTOMATIO_REPLAY ? 'replay' : '';
|
|
25
|
+
const paths = getDebugFilePath(suffix);
|
|
26
|
+
this.logFilePath = paths.tmp;
|
|
27
|
+
this.rootPath = paths.root;
|
|
28
|
+
this.historyDir = path.dirname(paths.tmp);
|
|
25
29
|
|
|
26
30
|
debug('Creating debug file:', this.logFilePath);
|
|
27
31
|
fs.writeFileSync(this.logFilePath, '');
|
|
28
32
|
|
|
29
|
-
// Create symlink
|
|
30
|
-
|
|
33
|
+
// Create symlink in project root pointing to the timestamped debug file.
|
|
34
|
+
// Symlinks may fail on Windows without admin / on filesystems that don't support them;
|
|
35
|
+
// fall back to printing the actual tmp path so the user-facing log isn't misleading.
|
|
31
36
|
try {
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
// Use lstatSync (not existsSync) so we also detect dangling symlinks —
|
|
38
|
+
// existsSync follows links and returns false when the target is gone,
|
|
39
|
+
// which would leave a stale symlink in place and make symlinkSync fail with EEXIST.
|
|
40
|
+
try {
|
|
41
|
+
fs.lstatSync(paths.root);
|
|
42
|
+
fs.unlinkSync(paths.root);
|
|
43
|
+
} catch (e) {
|
|
44
|
+
if (e.code !== 'ENOENT') throw e;
|
|
35
45
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
debug('Created symlink:', symlinkPath, '->', this.logFilePath);
|
|
46
|
+
fs.symlinkSync(this.logFilePath, paths.root);
|
|
47
|
+
debug('Created symlink:', paths.root, '->', this.logFilePath);
|
|
39
48
|
} catch (err) {
|
|
40
|
-
debug('Failed to create symlink:', err.message);
|
|
49
|
+
debug('Failed to create symlink, using tmp path directly:', err.message);
|
|
50
|
+
this.rootPath = this.logFilePath;
|
|
41
51
|
}
|
|
42
52
|
|
|
43
53
|
log.info('🪲 Debug file created');
|
|
@@ -114,8 +124,12 @@ export class DebugPipe {
|
|
|
114
124
|
if (!this.isEnabled) return;
|
|
115
125
|
await this.sync();
|
|
116
126
|
if (this.batch.intervalFunction) clearInterval(this.batch.intervalFunction);
|
|
117
|
-
|
|
118
|
-
|
|
127
|
+
const logData = { action: 'finishRun', params };
|
|
128
|
+
if (this.store.runId) logData.runId = this.store.runId;
|
|
129
|
+
this.logToFile(logData);
|
|
130
|
+
|
|
131
|
+
log.info(`🪲 Debug file: ${this.rootPath}`);
|
|
132
|
+
log.info(`History: ${this.historyDir}`);
|
|
119
133
|
}
|
|
120
134
|
|
|
121
135
|
async sync() {
|
package/src/pipe/html.js
CHANGED
|
@@ -906,121 +906,31 @@ function dropISayEcho(lines) {
|
|
|
906
906
|
return out;
|
|
907
907
|
}
|
|
908
908
|
|
|
909
|
-
|
|
910
|
-
* Collects all Testomatio and S3 environment variables
|
|
911
|
-
* Uses hardcoded list to avoid file system dependencies for end users
|
|
912
|
-
* @returns {Object} Object with TESTOMATIO_ and S3_ variables grouped
|
|
913
|
-
*/
|
|
914
|
-
function collectEnvironmentVariables() {
|
|
915
|
-
return getHardcodedEnvVars();
|
|
916
|
-
}
|
|
909
|
+
const SENSITIVE_ENV_PATTERNS = [/TOKEN/, /SECRET/, /PASSWORD/, /KEY/, /^TESTOMATIO$/];
|
|
917
910
|
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
* @param {Set} sensitiveVars - Set of sensitive variable names
|
|
922
|
-
* @returns {Object} Processed environment variables with metadata
|
|
923
|
-
*/
|
|
924
|
-
function processEnvironmentVariables(varConfigs, sensitiveVars) {
|
|
925
|
-
const result = {};
|
|
911
|
+
function isSensitiveEnvName(name) {
|
|
912
|
+
return SENSITIVE_ENV_PATTERNS.some(re => re.test(name));
|
|
913
|
+
}
|
|
926
914
|
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
const isSensitive = sensitiveVars.has(key);
|
|
915
|
+
function collectEnvironmentVariables() {
|
|
916
|
+
const groups = { testomatio: {}, s3: {} };
|
|
930
917
|
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
result[key] = { value: '***', description: config.description, isSet: true, isSensitive: true };
|
|
934
|
-
} else {
|
|
935
|
-
result[key] = { value: '', description: config.description, isSet: false, isSensitive: true };
|
|
936
|
-
}
|
|
937
|
-
} else {
|
|
938
|
-
if (value !== undefined) {
|
|
939
|
-
result[key] = { value, description: config.description, isSet: true };
|
|
940
|
-
} else {
|
|
941
|
-
result[key] = { value: '', description: config.description, isSet: false };
|
|
942
|
-
}
|
|
943
|
-
}
|
|
944
|
-
}
|
|
918
|
+
for (const [name, value] of Object.entries(process.env)) {
|
|
919
|
+
if (value === undefined) continue;
|
|
945
920
|
|
|
946
|
-
|
|
947
|
-
|
|
921
|
+
let group = null;
|
|
922
|
+
if (name === 'TESTOMATIO' || name.startsWith('TESTOMATIO_')) group = 'testomatio';
|
|
923
|
+
else if (name.startsWith('S3_')) group = 's3';
|
|
924
|
+
if (!group) continue;
|
|
948
925
|
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
* @returns {Object} Object with TESTOMATIO_ and S3_ variables
|
|
953
|
-
*/
|
|
954
|
-
function getHardcodedEnvVars() {
|
|
955
|
-
const allVars = {
|
|
956
|
-
testomatio: {
|
|
957
|
-
TESTOMATIO: { description: 'API Key for Testomat.io' },
|
|
958
|
-
TESTOMATIO_API_KEY: { description: 'API Key (alias for TESTOMATIO)' },
|
|
959
|
-
TESTOMATIO_CREATE: { description: 'Create new tests in Testomat.io' },
|
|
960
|
-
TESTOMATIO_DEBUG: { description: 'Enable debug mode' },
|
|
961
|
-
TESTOMATIO_DISABLE_BATCH_UPLOAD: { description: 'Disable batch upload' },
|
|
962
|
-
TESTOMATIO_ENV: { description: 'Environment label (e.g., "Windows, Chrome")' },
|
|
963
|
-
TESTOMATIO_EXCLUDE_FILES_FROM_REPORT_GLOB_PATTERN: { description: 'Glob pattern to exclude files' },
|
|
964
|
-
TESTOMATIO_EXCLUDE_SKIPPED: { description: 'Exclude skipped tests from report' },
|
|
965
|
-
TESTOMATIO_FILENAME: { description: 'HTML report filename' },
|
|
966
|
-
TESTOMATIO_HTML_FILENAME: { description: 'HTML report filename' },
|
|
967
|
-
TESTOMATIO_HTML_REPORT_FOLDER: { description: 'Folder for HTML report' },
|
|
968
|
-
TESTOMATIO_HTML_REPORT_SAVE: { description: 'Save HTML report' },
|
|
969
|
-
TESTOMATIO_INTERCEPT_CONSOLE_LOGS: { description: 'Intercept console logs' },
|
|
970
|
-
TESTOMATIO_MARK_DETACHED: { description: 'Mark tests as detached' },
|
|
971
|
-
TESTOMATIO_MAX_REQUEST_FAILURES: { description: 'Max request failures' },
|
|
972
|
-
TESTOMATIO_MAX_REQUEST_FAILURES_COUNT: { description: 'Max request failures count' },
|
|
973
|
-
TESTOMATIO_MAX_REQUEST_RETRIES_WITHIN_TIME_SECONDS: { description: 'Max retries within time period' },
|
|
974
|
-
TESTOMATIO_NO_STEPS: { description: 'Disable steps reporting' },
|
|
975
|
-
TESTOMATIO_NO_TIMESTAMP: { description: 'Remove timestamps from logs' },
|
|
976
|
-
TESTOMATIO_PROCEED: { description: 'Proceed even if tests fail' },
|
|
977
|
-
TESTOMATIO_PUBLISH: { description: 'Publish results to Testomat.io' },
|
|
978
|
-
TESTOMATIO_REQUEST_TIMEOUT: { description: 'Request timeout in milliseconds' },
|
|
979
|
-
TESTOMATIO_RUN: { description: 'Run ID to report tests to' },
|
|
980
|
-
TESTOMATIO_RUNGROUP_TITLE: { description: 'Title for run group' },
|
|
981
|
-
TESTOMATIO_SHARED_RUN: { description: 'Share run for parallel execution' },
|
|
982
|
-
TESTOMATIO_SHARED_RUN_TIMEOUT: { description: 'Timeout for shared run (in seconds)' },
|
|
983
|
-
TESTOMATIO_STACK_ARTIFACTS: { description: 'Stack artifacts in report' },
|
|
984
|
-
TESTOMATIO_STACK_FILTER: { description: 'Filter stack traces' },
|
|
985
|
-
TESTOMATIO_STACK_PASSED: { description: 'Report stack for passed tests' },
|
|
986
|
-
TESTOMATIO_STEPS_PASSED: { description: 'Report steps for passed tests' },
|
|
987
|
-
TESTOMATIO_SUITE: { description: 'Suite ID for new tests' },
|
|
988
|
-
TESTOMATIO_TOKEN: { description: 'API Token (alias for TESTOMATIO)' },
|
|
989
|
-
TESTOMATIO_TITLE: { description: 'Title for the test run' },
|
|
990
|
-
TESTOMATIO_URL: { description: 'Testomat.io URL (custom instance)' },
|
|
991
|
-
TESTOMATIO_WORKDIR: { description: 'Working directory for relative paths' },
|
|
992
|
-
},
|
|
993
|
-
s3: {
|
|
994
|
-
S3_ACCESS_KEY_ID: { description: 'S3 access key ID' },
|
|
995
|
-
S3_BUCKET: { description: 'S3 bucket name' },
|
|
996
|
-
S3_ENDPOINT: { description: 'S3 endpoint URL' },
|
|
997
|
-
S3_FORCE_PATH_STYLE: { description: 'S3 force path style' },
|
|
998
|
-
S3_KEY: { description: 'S3 access key' },
|
|
999
|
-
S3_PREFIX: { description: 'S3 key prefix' },
|
|
1000
|
-
S3_REGION: { description: 'S3 region' },
|
|
1001
|
-
S3_SECRET: { description: 'S3 secret key' },
|
|
1002
|
-
S3_SECRET_ACCESS_KEY: { description: 'S3 secret access key' },
|
|
1003
|
-
S3_SESSION_TOKEN: { description: 'S3 session token' },
|
|
1004
|
-
},
|
|
1005
|
-
};
|
|
926
|
+
const isSensitive = isSensitiveEnvName(name);
|
|
927
|
+
let displayValue = value;
|
|
928
|
+
if (isSensitive) displayValue = '***';
|
|
1006
929
|
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
'TESTOMATIO_TOKEN',
|
|
1010
|
-
'TESTOMATIO_API_KEY',
|
|
1011
|
-
'S3_KEY',
|
|
1012
|
-
'S3_SECRET',
|
|
1013
|
-
'S3_ACCESS_KEY_ID',
|
|
1014
|
-
'S3_SECRET_ACCESS_KEY',
|
|
1015
|
-
'S3_SESSION_TOKEN',
|
|
1016
|
-
]);
|
|
1017
|
-
|
|
1018
|
-
const envVars = {
|
|
1019
|
-
testomatio: processEnvironmentVariables(allVars.testomatio, sensitiveVars),
|
|
1020
|
-
s3: processEnvironmentVariables(allVars.s3, sensitiveVars),
|
|
1021
|
-
};
|
|
930
|
+
groups[group][name] = { value: displayValue, isSet: true, isSensitive };
|
|
931
|
+
}
|
|
1022
932
|
|
|
1023
|
-
return
|
|
933
|
+
return groups;
|
|
1024
934
|
}
|
|
1025
935
|
|
|
1026
936
|
/**
|
package/src/pipe/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import GitHubPipe from './github.js';
|
|
|
6
6
|
import GitLabPipe from './gitlab.js';
|
|
7
7
|
import CsvPipe from './csv.js';
|
|
8
8
|
import HtmlPipe from './html.js';
|
|
9
|
+
import MarkdownPipe from './markdown.js';
|
|
9
10
|
import CoveragePipe from './coverage.js';
|
|
10
11
|
import { BitbucketPipe } from './bitbucket.js';
|
|
11
12
|
import { DebugPipe } from './debug.js';
|
|
@@ -48,6 +49,7 @@ export async function pipesFactory(params, opts) {
|
|
|
48
49
|
new GitLabPipe(params, opts),
|
|
49
50
|
new CsvPipe(params, opts),
|
|
50
51
|
new HtmlPipe(params, opts),
|
|
52
|
+
new MarkdownPipe(params, opts),
|
|
51
53
|
new BitbucketPipe(params, opts),
|
|
52
54
|
new CoveragePipe(params, opts),
|
|
53
55
|
new DebugPipe(params, opts),
|