testbeats 2.2.7 → 2.2.9

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.
@@ -6,7 +6,10 @@ class BasePlatform {
6
6
  * @param {string|number} text
7
7
  */
8
8
  bold(text) {
9
- return `**${text}**`;
9
+ if (text) {
10
+ return `**${text}**`;
11
+ }
12
+ return text;
10
13
  }
11
14
 
12
15
  break() {
@@ -39,117 +42,19 @@ class BasePlatform {
39
42
  return text;
40
43
  }
41
44
 
42
-
43
-
44
- /**
45
- *
46
- * @param {import('..').ITarget} target
47
- * @param {import('test-results-parser').ITestSuite} suite
48
- */
49
- getSuiteSummaryText(target, suite) {
50
- const suite_title = this.getSuiteTitle(suite);
51
- const suite_results_text = this.#getSuiteResultsText(suite);
52
- const duration_text = this.#getSuiteDurationText(target, suite);
53
-
54
- const texts = [
55
- this.bold(suite_title),
56
- this.break(),
57
- this.break(),
58
- suite_results_text,
59
- this.break(),
60
- duration_text,
61
- ];
62
-
63
- const metadata_text = this.getSuiteMetaDataText(suite);
64
-
65
- if (metadata_text) {
66
- texts.push(this.break());
67
- texts.push(this.break());
68
- texts.push(metadata_text);
69
- }
70
-
71
- return texts.join('');
72
- }
73
-
74
- /**
75
- *
76
- * @param {import('test-results-parser').ITestSuite} suite
77
- * @returns {string}
78
- */
79
- getSuiteTitle(suite) {
80
- const emoji = suite.status === 'PASS' ? '✅' : suite.total === suite.skipped ? '⏭️' : '❌';
81
- return `${emoji} ${suite.name}`;
82
- }
83
-
84
45
  /**
85
- *
86
- * @param {import('test-results-parser').ITestSuite} suite
87
- * @returns {string}
88
- */
89
- #getSuiteResultsText(suite) {
90
- const suite_results = this.getSuiteResults(suite);
91
- return `${this.bold('Results')}: ${suite_results}`;
92
- }
93
-
94
- /**
95
- *
96
- * @param {import('test-results-parser').ITestSuite} suite
97
- * @returns {string}
98
- */
99
- getSuiteResults(suite) {
100
- return `${suite.passed} / ${suite.total} Passed (${getPercentage(suite.passed, suite.total)}%)`;
101
- }
102
-
103
- /**
104
- *
105
- * @param {import('..').ITarget} target
106
- * @param {import('test-results-parser').ITestSuite} suite
107
- */
108
- #getSuiteDurationText(target, suite) {
109
- const duration = this.getSuiteDuration(target, suite);
110
- return `${this.bold('Duration')}: ${duration}`
111
- }
112
-
113
- /**
114
- *
115
- * @param {import('..').ITarget} target
116
- * @param {import('test-results-parser').ITestSuite} suite
117
- */
118
- getSuiteDuration(target, suite) {
119
- return getPrettyDuration(suite.duration, target.inputs.duration);
120
- }
121
-
122
- /**
123
- *
124
- * @param {import('test-results-parser').ITestSuite} suite
46
+ * @param {string} text
47
+ * @param {string} url
125
48
  * @returns {string}
126
49
  */
127
- getSuiteMetaDataText(suite) {
128
- if (!suite || !suite.metadata) {
129
- return;
130
- }
131
-
132
- const texts = [];
133
-
134
- // webdriver io
135
- if (suite.metadata.device && typeof suite.metadata.device === 'string') {
136
- texts.push(`${suite.metadata.device}`);
137
- }
138
-
139
- if (suite.metadata.platform && suite.metadata.platform.name && suite.metadata.platform.version) {
140
- texts.push(`${suite.metadata.platform.name} ${suite.metadata.platform.version}`);
50
+ link(text, url) {
51
+ if (url) {
52
+ if (!text) {
53
+ text = url;
54
+ }
55
+ return `[${text}](${url})`;
141
56
  }
142
-
143
- if (suite.metadata.browser && suite.metadata.browser.name && suite.metadata.browser.version) {
144
- texts.push(`${suite.metadata.browser.name} ${suite.metadata.browser.version}`);
145
- }
146
-
147
- // playwright
148
- if (suite.metadata.hostname && typeof suite.metadata.hostname === 'string') {
149
- texts.push(`${suite.metadata.hostname}`);
150
- }
151
-
152
- return texts.join(' • ');
57
+ return url;
153
58
  }
154
59
 
155
60
  /**
@@ -6,7 +6,10 @@ class ChatPlatform extends BasePlatform {
6
6
  * @param {string|number} text
7
7
  */
8
8
  bold(text) {
9
- return `<b>${text}</b>`;
9
+ if (text) {
10
+ return `<b>${text}</b>`;
11
+ }
12
+ return text;
10
13
  }
11
14
 
12
15
  break() {
@@ -6,7 +6,10 @@ class SlackPlatform extends BasePlatform {
6
6
  * @param {string|number} text
7
7
  */
8
8
  bold(text) {
9
- return `*${text}*`;
9
+ if (text) {
10
+ return `*${text}*`;
11
+ }
12
+ return text;
10
13
  }
11
14
 
12
15
  /**
@@ -26,6 +29,16 @@ class SlackPlatform extends BasePlatform {
26
29
  }
27
30
  return text;
28
31
  }
32
+
33
+ link(text, url) {
34
+ if (url) {
35
+ if (!text) {
36
+ text = url;
37
+ }
38
+ return `<${url}|${text}>`;
39
+ }
40
+ return text;
41
+ }
29
42
  }
30
43
 
31
44
  module.exports = { SlackPlatform }
@@ -1,5 +1,6 @@
1
1
  const { getPlatform } = require('../platforms');
2
2
  const { STATUS } = require('../helpers/constants');
3
+ const { getPercentage, getPrettyDuration } = require('../helpers/helper');
3
4
 
4
5
  class BaseTarget {
5
6
 
@@ -34,12 +35,124 @@ class BaseTarget {
34
35
  * @type {import('../platforms/base.platform').BasePlatform}
35
36
  */
36
37
  this.platform = getPlatform(this.name);
38
+
37
39
  }
38
40
 
39
41
  async run({ result }) {
40
42
  // throw new Error('Not implemented');
41
43
  }
42
44
 
45
+ /**
46
+ *
47
+ * @param {import('..').ITarget} target
48
+ * @param {import('test-results-parser').ITestSuite} suite
49
+ */
50
+ getSuiteSummaryText(target, suite) {
51
+ const suite_title = this.getSuiteTitle(suite);
52
+ const suite_results_text = this.#getSuiteResultsText(suite);
53
+ const duration_text = this.#getSuiteDurationText(target, suite);
54
+
55
+ const texts = [
56
+ this.platform.bold(suite_title),
57
+ this.platform.break(),
58
+ this.platform.break(),
59
+ suite_results_text,
60
+ this.platform.break(),
61
+ duration_text,
62
+ ];
63
+
64
+ const metadata_text = this.getSuiteMetaDataText(suite);
65
+
66
+ if (metadata_text) {
67
+ texts.push(this.platform.break());
68
+ texts.push(this.platform.break());
69
+ texts.push(metadata_text);
70
+ }
71
+
72
+ return texts.join('');
73
+ }
74
+
75
+ /**
76
+ *
77
+ * @param {import('test-results-parser').ITestSuite} suite
78
+ * @returns {string}
79
+ */
80
+ getSuiteTitle(suite) {
81
+ const emoji = suite.status === 'PASS' ? '✅' : suite.total === suite.skipped ? '⏭️' : '❌';
82
+ return `${emoji} ${suite.name}`;
83
+ }
84
+
85
+ /**
86
+ *
87
+ * @param {import('test-results-parser').ITestSuite} suite
88
+ * @returns {string}
89
+ */
90
+ #getSuiteResultsText(suite) {
91
+ const suite_results = this.getSuiteResults(suite);
92
+ return `${this.platform.bold('Results')}: ${suite_results}`;
93
+ }
94
+
95
+ /**
96
+ *
97
+ * @param {import('test-results-parser').ITestSuite} suite
98
+ * @returns {string}
99
+ */
100
+ getSuiteResults(suite) {
101
+ return `${suite.passed} / ${suite.total} Passed (${getPercentage(suite.passed, suite.total)}%)`;
102
+ }
103
+
104
+ /**
105
+ *
106
+ * @param {import('..').ITarget} target
107
+ * @param {import('test-results-parser').ITestSuite} suite
108
+ */
109
+ #getSuiteDurationText(target, suite) {
110
+ const duration = this.getSuiteDuration(target, suite);
111
+ return `${this.platform.bold('Duration')}: ${duration}`
112
+ }
113
+
114
+ /**
115
+ *
116
+ * @param {import('..').ITarget} target
117
+ * @param {import('test-results-parser').ITestSuite} suite
118
+ */
119
+ getSuiteDuration(target, suite) {
120
+ return getPrettyDuration(suite.duration, target.inputs.duration);
121
+ }
122
+
123
+ /**
124
+ *
125
+ * @param {import('test-results-parser').ITestSuite} suite
126
+ * @returns {string}
127
+ */
128
+ getSuiteMetaDataText(suite) {
129
+ if (!suite || !suite.metadata) {
130
+ return;
131
+ }
132
+
133
+ const texts = [];
134
+
135
+ // webdriver io
136
+ if (suite.metadata.device && typeof suite.metadata.device === 'string') {
137
+ texts.push(`${suite.metadata.device}`);
138
+ }
139
+
140
+ if (suite.metadata.platform && suite.metadata.platform.name && suite.metadata.platform.version) {
141
+ texts.push(`${suite.metadata.platform.name} ${suite.metadata.platform.version}`);
142
+ }
143
+
144
+ if (suite.metadata.browser && suite.metadata.browser.name && suite.metadata.browser.version) {
145
+ texts.push(`${suite.metadata.browser.name} ${suite.metadata.browser.version}`);
146
+ }
147
+
148
+ // playwright
149
+ if (suite.metadata.hostname && typeof suite.metadata.hostname === 'string') {
150
+ texts.push(`${suite.metadata.hostname}`);
151
+ }
152
+
153
+ return texts.join(' • ');
154
+ }
155
+
43
156
  }
44
157
 
45
- module.exports = { BaseTarget};
158
+ module.exports = { BaseTarget };
@@ -1,11 +1,11 @@
1
1
  const request = require('phin-retry');
2
2
  const { getTitleText, getResultText, truncate, getPrettyDuration } = require('../helpers/helper');
3
3
  const extension_manager = require('../extensions');
4
- const { HOOK, STATUS, TARGET } = require('../helpers/constants');
4
+ const { HOOK, STATUS } = require('../helpers/constants');
5
5
  const PerformanceTestResult = require('performance-results-parser/src/models/PerformanceTestResult');
6
6
  const { getValidMetrics, getMetricValuesText } = require('../helpers/performance');
7
7
  const logger = require('../utils/logger');
8
- const { getPlatform } = require('../platforms');
8
+ const { BaseTarget } = require('./base.target');
9
9
 
10
10
  async function run({ result, target }) {
11
11
  setTargetInputs(target);
@@ -101,8 +101,9 @@ function setSuiteBlock({ result, target, payload }) {
101
101
  }
102
102
 
103
103
  function getSuiteSummary({ target, suite }) {
104
- const platform = getPlatform(TARGET.CHAT);
105
- const text = platform.getSuiteSummaryText(target, suite);
104
+ const tg = new ChatTarget({ target });
105
+ // const platform = getPlatform(TARGET.CHAT);
106
+ const text = tg.getSuiteSummaryText(target, suite);
106
107
  return text;
107
108
  }
108
109
 
@@ -260,6 +261,12 @@ async function handleErrors({ target, errors }) {
260
261
  });
261
262
  }
262
263
 
264
+ class ChatTarget extends BaseTarget {
265
+ constructor({ target }) {
266
+ super({ target });
267
+ }
268
+ }
269
+
263
270
  module.exports = {
264
271
  run,
265
272
  handleErrors,
@@ -1,5 +1,6 @@
1
1
  const { BaseTarget } = require('./base.target');
2
2
  const path = require('path');
3
+ const ctx = require('../utils/context.utils');
3
4
 
4
5
  const DEFAULT_INPUTS = {};
5
6
 
@@ -18,9 +19,9 @@ class CustomTarget extends BaseTarget {
18
19
  if (typeof this.inputs.load === 'string') {
19
20
  const cwd = process.cwd();
20
21
  const target_runner = require(path.join(cwd, this.inputs.load));
21
- await target_runner.run({ target: this.target, result });
22
+ await target_runner.run({ target: this.target, result, ctx });
22
23
  } else if (typeof this.inputs.load === 'function') {
23
- await this.inputs.load({ target: this.target, result });
24
+ await this.inputs.load({ target: this.target, result, ctx });
24
25
  } else {
25
26
  throw `Invalid 'load' input in custom target - ${this.inputs.load}`;
26
27
  }
@@ -0,0 +1,64 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const logger = require('../utils/logger');
4
+ const { BaseTarget } = require('./base.target');
5
+ const context = require('../utils/context.utils');
6
+
7
+ const DEFAULT_INPUTS = {
8
+ output_file: process.env.GITHUB_OUTPUT, // Path to output file, defaults to GITHUB_OUTPUT env var
9
+ key: 'testbeats' // Key name for the output
10
+ };
11
+
12
+ const default_options = {
13
+ condition: 'passOrFail'
14
+ };
15
+
16
+ class GitHubOutputTarget extends BaseTarget {
17
+ constructor({ target }) {
18
+ super({ target });
19
+ }
20
+
21
+ async run({ result, target }) {
22
+ this.result = result;
23
+ this.setTargetInputs(target);
24
+
25
+ logger.info(`🔔 Writing results to GitHub Actions outputs...`);
26
+ return await this.writeToGitHubOutput({ target, result });
27
+ }
28
+
29
+ setTargetInputs(target) {
30
+ target.inputs = Object.assign({}, DEFAULT_INPUTS, target.inputs);
31
+ }
32
+
33
+ async writeToGitHubOutput({ target, result }) {
34
+ const outputFile = target.inputs.output_file || process.env.GITHUB_OUTPUT;
35
+
36
+ if (!outputFile) {
37
+ throw new Error('GitHub output file path is required. Set GITHUB_OUTPUT environment variable or provide output_file in target inputs.');
38
+ }
39
+
40
+ // Ensure the directory exists
41
+ const outputDir = path.dirname(outputFile);
42
+ if (!fs.existsSync(outputDir)) {
43
+ fs.mkdirSync(outputDir, { recursive: true });
44
+ }
45
+
46
+ const lines = []
47
+ lines.push(`${target.inputs.key}_results=${JSON.stringify(result)}`)
48
+ lines.push(`${target.inputs.key}_stores=${JSON.stringify(context.stores)}`)
49
+ const outputContent = lines.join('\n');
50
+
51
+ fs.appendFileSync(outputFile, outputContent);
52
+
53
+ logger.info(`✅ Successfully wrote results to ${outputFile}`);
54
+ return { success: true, key: target.inputs.key };
55
+ }
56
+
57
+ async handleErrors({ target, errors }) {
58
+ logger.error('GitHub Output target errors:', errors);
59
+ }
60
+ }
61
+
62
+ module.exports = {
63
+ GitHubOutputTarget
64
+ };