@testrevolution/bugbug-cli 12.0.0 → 12.20.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@testrevolution/bugbug-cli",
3
3
  "description": "BugBug CLI",
4
- "version": "12.0.0",
4
+ "version": "12.20.0",
5
5
  "keywords": [
6
6
  "automation",
7
7
  "cli",
@@ -19,7 +19,7 @@
19
19
  },
20
20
  "dependencies": {
21
21
  "@sentry/node": "^8.55.0",
22
- "axios": "^1.8.4",
22
+ "axios": "^1.10.0",
23
23
  "console-table-printer": "^2.12.1",
24
24
  "dotenv": "^16.4.7",
25
25
  "jest-junit": "^16.0.0",
@@ -41,16 +41,16 @@
41
41
  "node": ">= 20.12.2"
42
42
  },
43
43
  "devDependencies": {
44
- "@babel/eslint-parser": "^7.25.9",
45
- "@babel/plugin-proposal-throw-expressions": "^7.25.9",
44
+ "@babel/eslint-parser": "^7.27.1",
45
+ "@babel/plugin-proposal-throw-expressions": "^7.27.1",
46
46
  "babel-plugin-rewire": "^1.2.0",
47
47
  "cross-env": "^7.0.3",
48
48
  "eslint": "^8.57.1",
49
49
  "eslint-config-airbnb-base": "^15.0.0",
50
- "eslint-plugin-import": "^2.31.0",
51
- "eslint-plugin-jest": "^28.11.0",
50
+ "eslint-plugin-import": "^2.32.0",
51
+ "eslint-plugin-jest": "^29.0.1",
52
52
  "eslint-plugin-node": "^11.1.0",
53
- "jest": "^29.7.0"
53
+ "jest": "^30.0.3"
54
54
  },
55
55
  "author": "TestRevolution sp. z o.o."
56
56
  }
@@ -0,0 +1,230 @@
1
+ const { parseTimeFromDuration, getSecondsFromDuration } = require('../utils/helper');
2
+
3
+ describe('timeParser', () => {
4
+ describe('parseTimeFromDuration', () => {
5
+ it('should parse full duration with microseconds', () => {
6
+ // Arrange
7
+ const duration = '00:01:15.704622';
8
+
9
+ // Act
10
+ const result = parseTimeFromDuration(duration);
11
+
12
+ // Assert
13
+ expect(result).toEqual({
14
+ hours: '00',
15
+ minutes: '01',
16
+ secondsWithMs: '15.704622',
17
+ seconds: '15',
18
+ microseconds: '704622',
19
+ });
20
+ });
21
+
22
+ it('should parse duration without microseconds', () => {
23
+ // Arrange
24
+ const duration = '01:30:45';
25
+
26
+ // Act
27
+ const result = parseTimeFromDuration(duration);
28
+
29
+ // Assert
30
+ expect(result).toEqual({
31
+ hours: '01',
32
+ minutes: '30',
33
+ secondsWithMs: '45',
34
+ seconds: '45',
35
+ microseconds: '0',
36
+ });
37
+ });
38
+
39
+ it('should parse duration with zero microseconds', () => {
40
+ // Arrange
41
+ const duration = '00:00:30.0';
42
+
43
+ // Act
44
+ const result = parseTimeFromDuration(duration);
45
+
46
+ // Assert
47
+ expect(result).toEqual({
48
+ hours: '00',
49
+ minutes: '00',
50
+ secondsWithMs: '30.0',
51
+ seconds: '30',
52
+ microseconds: '0',
53
+ });
54
+ });
55
+
56
+ it('should handle empty string', () => {
57
+ // Arrange
58
+ const duration = '';
59
+
60
+ // Act
61
+ const result = parseTimeFromDuration(duration);
62
+
63
+ // Assert
64
+ expect(result).toEqual({
65
+ hours: '00',
66
+ minutes: '0',
67
+ secondsWithMs: '0.0',
68
+ seconds: '0',
69
+ microseconds: '0',
70
+ });
71
+ });
72
+
73
+ it('should handle null or undefined', () => {
74
+ // Arrange & Act
75
+ const resultNull = parseTimeFromDuration(null);
76
+ const resultUndefined = parseTimeFromDuration(undefined);
77
+
78
+ // Assert
79
+ expect(resultNull).toEqual({
80
+ hours: '00',
81
+ minutes: '0',
82
+ secondsWithMs: '0.0',
83
+ seconds: '0',
84
+ microseconds: '0',
85
+ });
86
+ expect(resultUndefined).toEqual({
87
+ hours: '00',
88
+ minutes: '0',
89
+ secondsWithMs: '0.0',
90
+ seconds: '0',
91
+ microseconds: '0',
92
+ });
93
+ });
94
+
95
+ it('should handle short microseconds', () => {
96
+ // Arrange
97
+ const duration = '00:01:15.5';
98
+
99
+ // Act
100
+ const result = parseTimeFromDuration(duration);
101
+
102
+ // Assert
103
+ expect(result).toEqual({
104
+ hours: '00',
105
+ minutes: '01',
106
+ secondsWithMs: '15.5',
107
+ seconds: '15',
108
+ microseconds: '5',
109
+ });
110
+ });
111
+ });
112
+
113
+ describe('getSecondsFromDuration', () => {
114
+ it('should convert duration with microseconds to total float seconds', () => {
115
+ // Arrange
116
+ const duration = '00:01:15.704622';
117
+
118
+ // Act
119
+ const result = getSecondsFromDuration(duration);
120
+
121
+ // Assert
122
+ // 1 minute = 60 seconds, + 15 seconds = 75 seconds
123
+ // 75 * 1,000,000 = 75,000,000 microseconds
124
+ // + 704,622 microseconds = 75,704,622
125
+ expect(result).toBe(75.704622);
126
+ });
127
+
128
+ it('should convert duration without microseconds', () => {
129
+ // Arrange
130
+ const duration = '01:30:45';
131
+
132
+ // Act
133
+ const result = getSecondsFromDuration(duration);
134
+
135
+ // Assert
136
+ expect(result).toBe(5445);
137
+ });
138
+
139
+ it('should handle zero duration', () => {
140
+ // Arrange
141
+ const duration = '00:00:00.0';
142
+
143
+ // Act
144
+ const result = getSecondsFromDuration(duration);
145
+
146
+ // Assert
147
+ expect(result).toBe(0);
148
+ });
149
+
150
+ it('should pad short microseconds to 6 digits', () => {
151
+ // Arrange
152
+ const duration = '00:00:01.5';
153
+
154
+ // Act
155
+ const result = getSecondsFromDuration(duration);
156
+
157
+ // Assert
158
+ expect(result).toBe(1.5);
159
+ });
160
+
161
+ it('should truncate microseconds longer than 6 digits', () => {
162
+ // Arrange
163
+ const duration = '00:00:01.1234567890';
164
+
165
+ // Act
166
+ const result = getSecondsFromDuration(duration);
167
+
168
+ // Assert
169
+ expect(result).toBe(1.123456);
170
+ });
171
+
172
+ it('should handle missing microseconds with default padding', () => {
173
+ // Arrange
174
+ const duration = '00:00:05';
175
+
176
+ // Act
177
+ const result = getSecondsFromDuration(duration);
178
+
179
+ // Assert
180
+ expect(result).toBe(5);
181
+ });
182
+
183
+ it('should handle large durations', () => {
184
+ // Arrange
185
+ const duration = '23:59:59.999999';
186
+
187
+ // Act
188
+ const result = getSecondsFromDuration(duration);
189
+
190
+ // Assert
191
+ expect(result).toBe(86399.999999);
192
+ });
193
+
194
+ it('should handle empty string', () => {
195
+ // Arrange
196
+ const duration = '';
197
+
198
+ // Act
199
+ const result = getSecondsFromDuration(duration);
200
+
201
+ // Assert
202
+ expect(result).toBe(0);
203
+ });
204
+
205
+ it('should handle null or undefined', () => {
206
+ // Arrange & Act
207
+ const resultNull = getSecondsFromDuration(null);
208
+ const resultUndefined = getSecondsFromDuration(undefined);
209
+
210
+ // Assert
211
+ expect(resultNull).toBe(0);
212
+ expect(resultUndefined).toBe(0);
213
+ });
214
+
215
+ it('should handle malformed duration strings gracefully', () => {
216
+ // Arrange
217
+ const duration = 'invalid:time:format';
218
+
219
+ // Act
220
+ const parseResult = parseTimeFromDuration(duration);
221
+ const millisecondsResult = getSecondsFromDuration(duration);
222
+
223
+ // Assert
224
+ expect(parseResult.hours).toBe('invalid');
225
+ expect(parseResult.minutes).toBe('time');
226
+ expect(parseResult.seconds).toBe('format');
227
+ expect(millisecondsResult).toBeNaN();
228
+ });
229
+ });
230
+ });
@@ -28,7 +28,7 @@ const getUnknownOptions = async (args, knownKeys) => {
28
28
  const printErrorResponse = async (spinner, error) => {
29
29
  if (
30
30
  error.response?.status === 400
31
- && error.response?.data[0]?.message) {
31
+ && error.response?.data[0]?.message) {
32
32
  spinner.fail(error.response.data[0].message);
33
33
  } else {
34
34
  spinner.fail(error.toString());
@@ -45,28 +45,36 @@ const overrideSettings = async (args) => {
45
45
 
46
46
  const parseTimeFromDuration = (duration) => {
47
47
  const [hours, minutes = '0', secondsWithMs = '0.0'] = (duration || '').split(':');
48
- const [seconds, milliSeconds] = secondsWithMs.split('.');
48
+ const [seconds, microseconds = '0'] = secondsWithMs.split('.');
49
49
  return {
50
- hours: hours || '00', minutes, secondsWithMs, seconds, milliSeconds,
50
+ hours: hours || '00',
51
+ minutes,
52
+ secondsWithMs,
53
+ seconds,
54
+ microseconds,
51
55
  };
52
56
  };
53
57
 
54
- const getMillisecondsFromDuration = (duration) => {
58
+ const getSecondsFromDuration = (duration) => {
55
59
  const {
56
- hours, minutes, seconds, milliSeconds,
60
+ hours, minutes, seconds, microseconds,
57
61
  } = parseTimeFromDuration(duration);
58
- return (
59
- parseInt(hours, 10) * 3600
60
- + parseInt(minutes, 10) * 60
61
- + parseInt(seconds, 10)
62
- ) * 1000 + parseInt(milliSeconds, 10);
62
+ const totalSeconds = parseInt(hours, 10) * 3600
63
+ + parseInt(minutes, 10) * 60
64
+ + parseInt(seconds, 10);
65
+
66
+ const paddedMicroseconds = (microseconds || '0').padEnd(6, '0').substring(0, 6);
67
+ const fractionalSeconds = parseInt(paddedMicroseconds, 10) / 1_000_000;
68
+
69
+ return totalSeconds + fractionalSeconds;
63
70
  };
64
71
 
65
72
  module.exports = {
66
73
  getExitCode,
74
+ getSecondsFromDuration,
67
75
  getUnknownOptions,
68
76
  overrideSettings,
77
+ parseTimeFromDuration,
69
78
  parseVariables,
70
79
  printErrorResponse,
71
- getMillisecondsFromDuration,
72
80
  };
@@ -3,7 +3,7 @@ const fs = require('node:fs');
3
3
  const path = require('node:path');
4
4
 
5
5
  const settings = require('../settings');
6
- const { getMillisecondsFromDuration } = require('./helper');
6
+ const { getSecondsFromDuration } = require('./helper');
7
7
 
8
8
  const getTestInJunitFormat = (testRun) => {
9
9
  const errorDetails = testRun.errorCode ? {
@@ -14,7 +14,7 @@ const getTestInJunitFormat = (testRun) => {
14
14
  return {
15
15
  id: testRun.id,
16
16
  name: testRun.name,
17
- time: getMillisecondsFromDuration(testRun.duration),
17
+ time: getSecondsFromDuration(testRun.duration),
18
18
  classname: null,
19
19
  errors: testRun.status === settings.STATUS_ERROR ? [errorDetails] : [],
20
20
  failures: testRun.status === settings.STATUS_FAILED ? [errorDetails] : [],
@@ -24,14 +24,14 @@ const getTestInJunitFormat = (testRun) => {
24
24
  const getSuiteInJunitFormat = (suiteRun) => ({
25
25
  id: suiteRun.id,
26
26
  name: suiteRun.name,
27
- time: getMillisecondsFromDuration(suiteRun.duration),
27
+ time: getSecondsFromDuration(suiteRun.duration),
28
28
  testCases: suiteRun.details.map((testRun) => getTestInJunitFormat(testRun)),
29
29
  });
30
30
 
31
31
  const generateJunitReport = async (type, result, outputPath) => {
32
32
  const testReport = {};
33
33
  testReport.name = 'BugBug Report';
34
- testReport.time = getMillisecondsFromDuration(result.duration);
34
+ testReport.time = getSecondsFromDuration(result.duration);
35
35
  testReport.suites = [];
36
36
 
37
37
  if (type === settings.TYPE_TEST) {