@testomatio/reporter 2.7.6 → 2.7.9-beta.1-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/lib/bin/cli.js CHANGED
@@ -310,7 +310,7 @@ program
310
310
  program
311
311
  .command('replay')
312
312
  .description('Replay test data from debug file and re-send to Testomat.io')
313
- .argument('[debug-file]', 'Path to debug file (defaults to /tmp/testomatio.debug.latest.json)')
313
+ .argument('[debug-file]', `Path to debug file. Defaults to ./${constants_js_1.DEBUG_FILE}.json`)
314
314
  .option('--dry-run', 'Preview the data without sending to Testomat.io')
315
315
  .action(async (debugFile, opts) => {
316
316
  try {
@@ -15,7 +15,14 @@ export namespace HTML_REPORT {
15
15
  let REPORT_DEFAULT_NAME: string;
16
16
  let TEMPLATE_NAME: string;
17
17
  }
18
- export const AXIOS_TIMEOUT: number;
18
+ export namespace MARKDOWN_REPORT {
19
+ let FOLDER_1: string;
20
+ export { FOLDER_1 as FOLDER };
21
+ let REPORT_DEFAULT_NAME_1: string;
22
+ export { REPORT_DEFAULT_NAME_1 as REPORT_DEFAULT_NAME };
23
+ }
24
+ export const REQUEST_TIMEOUT: number;
25
+ export function getCreateRunRequestTimeout(): number;
19
26
  export const testomatLogoURL: "https://avatars.githubusercontent.com/u/59105116?s=36&v=4";
20
27
  export namespace REPORTER_REQUEST_RETRIES {
21
28
  let retryTimeout: number;
@@ -24,3 +31,4 @@ export namespace REPORTER_REQUEST_RETRIES {
24
31
  let withinTimeSeconds: number;
25
32
  }
26
33
  export const SCREENSHOTS_ON_STEPS: boolean;
34
+ export const DEBUG_FILE: "testomatio.debug";
package/lib/constants.js CHANGED
@@ -3,7 +3,8 @@ 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.SCREENSHOTS_ON_STEPS = exports.REPORTER_REQUEST_RETRIES = exports.testomatLogoURL = exports.AXIOS_TIMEOUT = exports.HTML_REPORT = exports.STATUS = exports.CSV_HEADERS = exports.TESTOMAT_TMP_STORAGE_DIR = exports.APP_PREFIX = void 0;
6
+ exports.DEBUG_FILE = exports.SCREENSHOTS_ON_STEPS = exports.REPORTER_REQUEST_RETRIES = exports.testomatLogoURL = exports.REQUEST_TIMEOUT = exports.MARKDOWN_REPORT = exports.HTML_REPORT = exports.STATUS = exports.CSV_HEADERS = exports.TESTOMAT_TMP_STORAGE_DIR = exports.APP_PREFIX = void 0;
7
+ exports.getCreateRunRequestTimeout = getCreateRunRequestTimeout;
7
8
  const picocolors_1 = __importDefault(require("picocolors"));
8
9
  const os_1 = __importDefault(require("os"));
9
10
  const path_1 = __importDefault(require("path"));
@@ -14,8 +15,8 @@ const TESTOMATIO_REQUEST_TIMEOUT = parseInt(process.env.TESTOMATIO_REQUEST_TIMEO
14
15
  if (TESTOMATIO_REQUEST_TIMEOUT) {
15
16
  console.log(`${APP_PREFIX} Request timeout is set to ${TESTOMATIO_REQUEST_TIMEOUT / 1000}s`);
16
17
  }
17
- const AXIOS_TIMEOUT = TESTOMATIO_REQUEST_TIMEOUT || 20 * 1000;
18
- exports.AXIOS_TIMEOUT = AXIOS_TIMEOUT;
18
+ const REQUEST_TIMEOUT = TESTOMATIO_REQUEST_TIMEOUT || 20 * 1000;
19
+ exports.REQUEST_TIMEOUT = REQUEST_TIMEOUT;
19
20
  const SCREENSHOTS_ON_STEPS = process.env.TESTOMATIO_SCREENSHOTS_ON_STEPS == null
20
21
  || (0, utils_js_1.transformEnvVarToBoolean)(process.env.TESTOMATIO_SCREENSHOTS_ON_STEPS);
21
22
  exports.SCREENSHOTS_ON_STEPS = SCREENSHOTS_ON_STEPS;
@@ -43,6 +44,12 @@ const HTML_REPORT = {
43
44
  TEMPLATE_NAME: 'testomatio.hbs',
44
45
  };
45
46
  exports.HTML_REPORT = HTML_REPORT;
47
+ // markdown pipe var
48
+ const MARKDOWN_REPORT = {
49
+ FOLDER: 'md-report',
50
+ REPORT_DEFAULT_NAME: 'testomatio-report.md',
51
+ };
52
+ exports.MARKDOWN_REPORT = MARKDOWN_REPORT;
46
53
  const testomatLogoURL = 'https://avatars.githubusercontent.com/u/59105116?s=36&v=4';
47
54
  exports.testomatLogoURL = testomatLogoURL;
48
55
  const REPORTER_REQUEST_RETRIES = {
@@ -52,10 +59,17 @@ const REPORTER_REQUEST_RETRIES = {
52
59
  withinTimeSeconds: Number(process.env.TESTOMATIO_MAX_REQUEST_RETRIES_WITHIN_TIME_SECONDS) || 60,
53
60
  };
54
61
  exports.REPORTER_REQUEST_RETRIES = REPORTER_REQUEST_RETRIES;
62
+ const DEBUG_FILE = 'testomatio.debug';
63
+ exports.DEBUG_FILE = DEBUG_FILE;
64
+ function getCreateRunRequestTimeout() {
65
+ return Math.max(REQUEST_TIMEOUT, 80 * 1000);
66
+ }
67
+
68
+ module.exports.getCreateRunRequestTimeout = getCreateRunRequestTimeout;
55
69
 
56
70
  module.exports.APP_PREFIX = APP_PREFIX;
57
71
 
58
- module.exports.AXIOS_TIMEOUT = AXIOS_TIMEOUT;
72
+ module.exports.REQUEST_TIMEOUT = REQUEST_TIMEOUT;
59
73
 
60
74
  module.exports.SCREENSHOTS_ON_STEPS = SCREENSHOTS_ON_STEPS;
61
75
 
@@ -67,6 +81,10 @@ module.exports.STATUS = STATUS;
67
81
 
68
82
  module.exports.HTML_REPORT = HTML_REPORT;
69
83
 
84
+ module.exports.MARKDOWN_REPORT = MARKDOWN_REPORT;
85
+
70
86
  module.exports.testomatLogoURL = testomatLogoURL;
71
87
 
72
88
  module.exports.REPORTER_REQUEST_RETRIES = REPORTER_REQUEST_RETRIES;
89
+
90
+ module.exports.DEBUG_FILE = DEBUG_FILE;
@@ -67,7 +67,7 @@ class CoveragePipe {
67
67
  // Create a new instance of gaxios with a custom config
68
68
  this.client = new gaxios_1.Gaxios({
69
69
  baseURL: `${this.url.trim()}`,
70
- timeout: constants_js_1.AXIOS_TIMEOUT,
70
+ timeout: constants_js_1.REQUEST_TIMEOUT,
71
71
  proxy: proxy ? proxy.toString() : undefined,
72
72
  retry: true,
73
73
  retryConfig: {
@@ -11,6 +11,8 @@ export class DebugPipe {
11
11
  batchIndex: number;
12
12
  };
13
13
  logFilePath: string;
14
+ rootPath: string;
15
+ historyDir: string;
14
16
  testomatioEnvVars: {};
15
17
  batchUpload(): Promise<void>;
16
18
  /**
package/lib/pipe/debug.js CHANGED
@@ -6,10 +6,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.DebugPipe = 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 debug_1 = __importDefault(require("debug"));
11
10
  const pretty_ms_1 = __importDefault(require("pretty-ms"));
12
11
  const log_js_1 = require("../utils/log.js");
12
+ const debug_js_1 = require("../utils/debug.js");
13
13
  const debug = (0, debug_1.default)('@testomatio/reporter:pipe:debug');
14
14
  class DebugPipe {
15
15
  constructor(params, store) {
@@ -24,22 +24,34 @@ class DebugPipe {
24
24
  tests: [],
25
25
  batchIndex: 0,
26
26
  };
27
- this.logFilePath = path_1.default.join(os_1.default.tmpdir(), `testomatio.debug.${Date.now()}.json`);
27
+ const suffix = process.env.TESTOMATIO_REPLAY ? 'replay' : '';
28
+ const paths = (0, debug_js_1.getDebugFilePath)(suffix);
29
+ this.logFilePath = paths.tmp;
30
+ this.rootPath = paths.root;
31
+ this.historyDir = path_1.default.dirname(paths.tmp);
28
32
  debug('Creating debug file:', this.logFilePath);
29
33
  fs_1.default.writeFileSync(this.logFilePath, '');
30
- // Create symlink to ensure consistent path to latest debug file
31
- const symlinkPath = path_1.default.join(os_1.default.tmpdir(), 'testomatio.debug.latest.json');
34
+ // Create symlink in project root pointing to the timestamped debug file.
35
+ // Symlinks may fail on Windows without admin / on filesystems that don't support them;
36
+ // fall back to printing the actual tmp path so the user-facing log isn't misleading.
32
37
  try {
33
- // Remove existing symlink if it exists
34
- if (fs_1.default.existsSync(symlinkPath)) {
35
- fs_1.default.unlinkSync(symlinkPath);
38
+ // Use lstatSync (not existsSync) so we also detect dangling symlinks —
39
+ // existsSync follows links and returns false when the target is gone,
40
+ // which would leave a stale symlink in place and make symlinkSync fail with EEXIST.
41
+ try {
42
+ fs_1.default.lstatSync(paths.root);
43
+ fs_1.default.unlinkSync(paths.root);
36
44
  }
37
- // Create new symlink pointing to the timestamped debug file
38
- fs_1.default.symlinkSync(this.logFilePath, symlinkPath);
39
- debug('Created symlink:', symlinkPath, '->', this.logFilePath);
45
+ catch (e) {
46
+ if (e.code !== 'ENOENT')
47
+ throw e;
48
+ }
49
+ fs_1.default.symlinkSync(this.logFilePath, paths.root);
50
+ debug('Created symlink:', paths.root, '->', this.logFilePath);
40
51
  }
41
52
  catch (err) {
42
- debug('Failed to create symlink:', err.message);
53
+ debug('Failed to create symlink, using tmp path directly:', err.message);
54
+ this.rootPath = this.logFilePath;
43
55
  }
44
56
  log_js_1.log.info('🪲 Debug file created');
45
57
  this.testomatioEnvVars = Object.keys(process.env)
@@ -117,8 +129,12 @@ class DebugPipe {
117
129
  await this.sync();
118
130
  if (this.batch.intervalFunction)
119
131
  clearInterval(this.batch.intervalFunction);
120
- this.logToFile({ action: 'finishRun', params });
121
- log_js_1.log.info('🪲 Debug Saved to', this.logFilePath);
132
+ const logData = { action: 'finishRun', params };
133
+ if (this.store.runId)
134
+ logData.runId = this.store.runId;
135
+ this.logToFile(logData);
136
+ log_js_1.log.info(`🪲 Debug file: ${this.rootPath}`);
137
+ log_js_1.log.info(`History: ${this.historyDir}`);
122
138
  }
123
139
  async sync() {
124
140
  if (!this.isEnabled)
package/lib/pipe/html.js CHANGED
@@ -760,116 +760,29 @@ function dropISayEcho(lines) {
760
760
  }
761
761
  return out;
762
762
  }
763
- /**
764
- * Collects all Testomatio and S3 environment variables
765
- * Uses hardcoded list to avoid file system dependencies for end users
766
- * @returns {Object} Object with TESTOMATIO_ and S3_ variables grouped
767
- */
768
- function collectEnvironmentVariables() {
769
- return getHardcodedEnvVars();
763
+ const SENSITIVE_ENV_PATTERNS = [/TOKEN/, /SECRET/, /PASSWORD/, /KEY/, /^TESTOMATIO$/];
764
+ function isSensitiveEnvName(name) {
765
+ return SENSITIVE_ENV_PATTERNS.some(re => re.test(name));
770
766
  }
771
- /**
772
- * Process environment variables configuration and collect their values
773
- * @param {Object} varConfigs - Object with variable configurations { [key]: { description } }
774
- * @param {Set} sensitiveVars - Set of sensitive variable names
775
- * @returns {Object} Processed environment variables with metadata
776
- */
777
- function processEnvironmentVariables(varConfigs, sensitiveVars) {
778
- const result = {};
779
- for (const [key, config] of Object.entries(varConfigs)) {
780
- const value = process.env[key];
781
- const isSensitive = sensitiveVars.has(key);
782
- if (isSensitive) {
783
- if (value !== undefined) {
784
- result[key] = { value: '***', description: config.description, isSet: true, isSensitive: true };
785
- }
786
- else {
787
- result[key] = { value: '', description: config.description, isSet: false, isSensitive: true };
788
- }
789
- }
790
- else {
791
- if (value !== undefined) {
792
- result[key] = { value, description: config.description, isSet: true };
793
- }
794
- else {
795
- result[key] = { value: '', description: config.description, isSet: false };
796
- }
797
- }
767
+ function collectEnvironmentVariables() {
768
+ const groups = { testomatio: {}, s3: {} };
769
+ for (const [name, value] of Object.entries(process.env)) {
770
+ if (value === undefined)
771
+ continue;
772
+ let group = null;
773
+ if (name === 'TESTOMATIO' || name.startsWith('TESTOMATIO_'))
774
+ group = 'testomatio';
775
+ else if (name.startsWith('S3_'))
776
+ group = 's3';
777
+ if (!group)
778
+ continue;
779
+ const isSensitive = isSensitiveEnvName(name);
780
+ let displayValue = value;
781
+ if (isSensitive)
782
+ displayValue = '***';
783
+ groups[group][name] = { value: displayValue, isSet: true, isSensitive };
798
784
  }
799
- return result;
800
- }
801
- /**
802
- * Hardcoded environment variables stored in code
803
- * This is the main source of truth for env vars to avoid file system dependencies
804
- * @returns {Object} Object with TESTOMATIO_ and S3_ variables
805
- */
806
- function getHardcodedEnvVars() {
807
- const allVars = {
808
- testomatio: {
809
- TESTOMATIO: { description: 'API Key for Testomat.io' },
810
- TESTOMATIO_API_KEY: { description: 'API Key (alias for TESTOMATIO)' },
811
- TESTOMATIO_CREATE: { description: 'Create new tests in Testomat.io' },
812
- TESTOMATIO_DEBUG: { description: 'Enable debug mode' },
813
- TESTOMATIO_DISABLE_BATCH_UPLOAD: { description: 'Disable batch upload' },
814
- TESTOMATIO_ENV: { description: 'Environment label (e.g., "Windows, Chrome")' },
815
- TESTOMATIO_EXCLUDE_FILES_FROM_REPORT_GLOB_PATTERN: { description: 'Glob pattern to exclude files' },
816
- TESTOMATIO_EXCLUDE_SKIPPED: { description: 'Exclude skipped tests from report' },
817
- TESTOMATIO_FILENAME: { description: 'HTML report filename' },
818
- TESTOMATIO_HTML_FILENAME: { description: 'HTML report filename' },
819
- TESTOMATIO_HTML_REPORT_FOLDER: { description: 'Folder for HTML report' },
820
- TESTOMATIO_HTML_REPORT_SAVE: { description: 'Save HTML report' },
821
- TESTOMATIO_INTERCEPT_CONSOLE_LOGS: { description: 'Intercept console logs' },
822
- TESTOMATIO_MARK_DETACHED: { description: 'Mark tests as detached' },
823
- TESTOMATIO_MAX_REQUEST_FAILURES: { description: 'Max request failures' },
824
- TESTOMATIO_MAX_REQUEST_FAILURES_COUNT: { description: 'Max request failures count' },
825
- TESTOMATIO_MAX_REQUEST_RETRIES_WITHIN_TIME_SECONDS: { description: 'Max retries within time period' },
826
- TESTOMATIO_NO_STEPS: { description: 'Disable steps reporting' },
827
- TESTOMATIO_NO_TIMESTAMP: { description: 'Remove timestamps from logs' },
828
- TESTOMATIO_PROCEED: { description: 'Proceed even if tests fail' },
829
- TESTOMATIO_PUBLISH: { description: 'Publish results to Testomat.io' },
830
- TESTOMATIO_REQUEST_TIMEOUT: { description: 'Request timeout in milliseconds' },
831
- TESTOMATIO_RUN: { description: 'Run ID to report tests to' },
832
- TESTOMATIO_RUNGROUP_TITLE: { description: 'Title for run group' },
833
- TESTOMATIO_SHARED_RUN: { description: 'Share run for parallel execution' },
834
- TESTOMATIO_SHARED_RUN_TIMEOUT: { description: 'Timeout for shared run (in seconds)' },
835
- TESTOMATIO_STACK_ARTIFACTS: { description: 'Stack artifacts in report' },
836
- TESTOMATIO_STACK_FILTER: { description: 'Filter stack traces' },
837
- TESTOMATIO_STACK_PASSED: { description: 'Report stack for passed tests' },
838
- TESTOMATIO_STEPS_PASSED: { description: 'Report steps for passed tests' },
839
- TESTOMATIO_SUITE: { description: 'Suite ID for new tests' },
840
- TESTOMATIO_TOKEN: { description: 'API Token (alias for TESTOMATIO)' },
841
- TESTOMATIO_TITLE: { description: 'Title for the test run' },
842
- TESTOMATIO_URL: { description: 'Testomat.io URL (custom instance)' },
843
- TESTOMATIO_WORKDIR: { description: 'Working directory for relative paths' },
844
- },
845
- s3: {
846
- S3_ACCESS_KEY_ID: { description: 'S3 access key ID' },
847
- S3_BUCKET: { description: 'S3 bucket name' },
848
- S3_ENDPOINT: { description: 'S3 endpoint URL' },
849
- S3_FORCE_PATH_STYLE: { description: 'S3 force path style' },
850
- S3_KEY: { description: 'S3 access key' },
851
- S3_PREFIX: { description: 'S3 key prefix' },
852
- S3_REGION: { description: 'S3 region' },
853
- S3_SECRET: { description: 'S3 secret key' },
854
- S3_SECRET_ACCESS_KEY: { description: 'S3 secret access key' },
855
- S3_SESSION_TOKEN: { description: 'S3 session token' },
856
- },
857
- };
858
- const sensitiveVars = new Set([
859
- 'TESTOMATIO',
860
- 'TESTOMATIO_TOKEN',
861
- 'TESTOMATIO_API_KEY',
862
- 'S3_KEY',
863
- 'S3_SECRET',
864
- 'S3_ACCESS_KEY_ID',
865
- 'S3_SECRET_ACCESS_KEY',
866
- 'S3_SESSION_TOKEN',
867
- ]);
868
- const envVars = {
869
- testomatio: processEnvironmentVariables(allVars.testomatio, sensitiveVars),
870
- s3: processEnvironmentVariables(allVars.s3, sensitiveVars),
871
- };
872
- return envVars;
785
+ return groups;
873
786
  }
874
787
  /**
875
788
  * Prepares test steps for HTML report display
package/lib/pipe/index.js CHANGED
@@ -45,6 +45,7 @@ const github_js_1 = __importDefault(require("./github.js"));
45
45
  const gitlab_js_1 = __importDefault(require("./gitlab.js"));
46
46
  const csv_js_1 = __importDefault(require("./csv.js"));
47
47
  const html_js_1 = __importDefault(require("./html.js"));
48
+ const markdown_js_1 = __importDefault(require("./markdown.js"));
48
49
  const coverage_js_1 = __importDefault(require("./coverage.js"));
49
50
  const bitbucket_js_1 = require("./bitbucket.js");
50
51
  const debug_js_1 = require("./debug.js");
@@ -83,6 +84,7 @@ async function pipesFactory(params, opts) {
83
84
  new gitlab_js_1.default(params, opts),
84
85
  new csv_js_1.default(params, opts),
85
86
  new html_js_1.default(params, opts),
87
+ new markdown_js_1.default(params, opts),
86
88
  new bitbucket_js_1.BitbucketPipe(params, opts),
87
89
  new coverage_js_1.default(params, opts),
88
90
  new debug_js_1.DebugPipe(params, opts),
@@ -0,0 +1,25 @@
1
+ export default MarkdownPipe;
2
+ declare class MarkdownPipe {
3
+ constructor(params: any, store?: {});
4
+ store: {};
5
+ title: any;
6
+ apiKey: any;
7
+ isMarkdown: string;
8
+ isEnabled: boolean;
9
+ markdownOutputPath: string;
10
+ filenameMsg: string;
11
+ tests: any[];
12
+ markdownReportDir: string;
13
+ markdownReportName: string;
14
+ createRun(): Promise<void>;
15
+ prepareRun(): Promise<void>;
16
+ updateRun(): void;
17
+ /**
18
+ * @param {import('../../types/types.js').MarkdownTestData} test
19
+ */
20
+ addTest(test: import("../../types/types.js").MarkdownTestData): void;
21
+ finishRun(runParams: any): Promise<void>;
22
+ buildReport(opts: any): void;
23
+ sync(): Promise<void>;
24
+ toString(): string;
25
+ }