@testrevolution/bugbug-cli 12.34.1 → 12.35.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 +1 -1
- package/src/__tests__/commands.spec.js +27 -0
- package/src/commands/remote.js +12 -5
- package/src/settings.js +2 -0
- package/test-report.xml +37 -0
- package/src/utils/testReports.js +0 -65
package/package.json
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
const axios = require('axios');
|
|
2
|
+
const fs = require('fs');
|
|
2
3
|
|
|
4
|
+
const { join } = require('path');
|
|
3
5
|
const {
|
|
4
6
|
config: configCommand,
|
|
5
7
|
help: helpCommand,
|
|
@@ -581,6 +583,31 @@ describe('commands module', () => {
|
|
|
581
583
|
});
|
|
582
584
|
});
|
|
583
585
|
|
|
586
|
+
it.each(['test', 'suite'])('result %s command should call API and generate JUnit report', async (type) => {
|
|
587
|
+
// Arrange
|
|
588
|
+
const reportFile = 'report data';
|
|
589
|
+
jest.spyOn(fs, 'writeFileSync').mockImplementation();
|
|
590
|
+
const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation();
|
|
591
|
+
axios
|
|
592
|
+
.mockResolvedValueOnce(apiMocks.getResultTestRunSuccess)
|
|
593
|
+
.mockResolvedValueOnce({ data: reportFile });
|
|
594
|
+
const id = '95a37d6a-a7a5-42ae-8fe3-336a120b807b';
|
|
595
|
+
const args = {
|
|
596
|
+
_: ['remote', 'result', type, id],
|
|
597
|
+
noprogress: true,
|
|
598
|
+
'with-details': true,
|
|
599
|
+
reporter: settings.REPORTER_TYPE.junit,
|
|
600
|
+
'output-path': 'test-report.xml',
|
|
601
|
+
};
|
|
602
|
+
|
|
603
|
+
// Act
|
|
604
|
+
await remoteCommand(args);
|
|
605
|
+
|
|
606
|
+
// Assert
|
|
607
|
+
expect(fs.writeFileSync).toHaveBeenCalledWith(join(process.cwd(), 'test-report.xml'), reportFile, expect.any(Object));
|
|
608
|
+
expect(consoleLogSpy).toHaveBeenCalledWith(`JUnit report generated at ${join(process.cwd(), 'test-report.xml')}`);
|
|
609
|
+
});
|
|
610
|
+
|
|
584
611
|
it('result test command should call API and print errorCode when failed', async () => {
|
|
585
612
|
const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation();
|
|
586
613
|
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
|
package/src/commands/remote.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const fs = require('node:fs');
|
|
2
|
+
const { join } = require('node:path');
|
|
1
3
|
const { format } = require('util');
|
|
2
4
|
const validator = require('validator');
|
|
3
5
|
|
|
@@ -14,9 +16,6 @@ const {
|
|
|
14
16
|
printTestRunInfo,
|
|
15
17
|
printSuiteRunInfo,
|
|
16
18
|
} = require('../utils/print');
|
|
17
|
-
const {
|
|
18
|
-
generateJunitReport,
|
|
19
|
-
} = require('../utils/testReports');
|
|
20
19
|
const help = require('./help');
|
|
21
20
|
const { sentry } = require('../utils/sentry');
|
|
22
21
|
|
|
@@ -54,8 +53,16 @@ const getResult = async (type, id, extraParams) => {
|
|
|
54
53
|
if (result) {
|
|
55
54
|
switch (reporter) {
|
|
56
55
|
case settings.REPORTER_TYPE.junit: {
|
|
57
|
-
|
|
58
|
-
await
|
|
56
|
+
spinner.info('Generating JUnit report...');
|
|
57
|
+
const report = await apiCall(
|
|
58
|
+
format(settings.API_ROUTING[`${type}RunReport`].path, id),
|
|
59
|
+
settings.API_ROUTING[`${type}RunReport`].method,
|
|
60
|
+
{},
|
|
61
|
+
{},
|
|
62
|
+
extraParams.triggeredBy,
|
|
63
|
+
);
|
|
64
|
+
fs.writeFileSync(join(process.cwd(), outputPath), report.data, { flag: 'w+' });
|
|
65
|
+
spinner.info(`JUnit report generated at ${join(process.cwd(), outputPath)}`);
|
|
59
66
|
break;
|
|
60
67
|
}
|
|
61
68
|
default: {
|
package/src/settings.js
CHANGED
|
@@ -42,6 +42,8 @@ const API_ROUTING = {
|
|
|
42
42
|
testRun: { method: 'POST', path: `${API_VERSION}/testruns/` },
|
|
43
43
|
testStatus: { method: 'GET', path: `${API_VERSION}/testruns/%s/status/` },
|
|
44
44
|
testStop: { method: 'POST', path: `${API_VERSION}/testruns/%s/stop/` },
|
|
45
|
+
testRunReport: { method: 'GET', path: `${API_VERSION}/testruns/%s/report/junit/` },
|
|
46
|
+
suiteRunReport: { method: 'GET', path: `${API_VERSION}/suiteruns/%s/report/junit/` },
|
|
45
47
|
};
|
|
46
48
|
|
|
47
49
|
const API_POLLING_MODIFIED_INTERVAL = 120000; // 120 seconds
|
package/test-report.xml
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<?xml version='1.0' encoding='utf-8'?>
|
|
2
|
+
<testsuites>
|
|
3
|
+
<testsuite errors="0" failures="0" id="08deed80-07d1-4987-aaa3-e14a1f906a29" name="Test_Tic Tac Toe simple [OK]" skipped="0" tests="1" time="7.00" sequence="#3" timestamp="2025-10-28T13:08:49.533959+00:00">
|
|
4
|
+
<properties>
|
|
5
|
+
<property name="report_id" value="ca971f23-d2e1-4401-bf12-5cd2e968ce3a" />
|
|
6
|
+
<property name="generated_at" value="2025-10-28T13:08:57.329443+00:00" />
|
|
7
|
+
<property name="generated_by" value="admin@testrevolution.io" />
|
|
8
|
+
<property name="auto_retry_attempt" value="0" />
|
|
9
|
+
<property name="browser_height" value="786" />
|
|
10
|
+
<property name="browser_name" value="Chrome" />
|
|
11
|
+
<property name="browser_version" value="136.0.0.0" />
|
|
12
|
+
<property name="browser_width" value="1366" />
|
|
13
|
+
<property name="extension_version" value="12.33.2" />
|
|
14
|
+
<property name="finished" value="2025-10-28T13:08:56.534381+00:00" />
|
|
15
|
+
<property name="os_name" value="Linux" />
|
|
16
|
+
<property name="profile_name" value="Default" />
|
|
17
|
+
<property name="run_mode" value="cloud" />
|
|
18
|
+
<property name="sequence" value="#3" />
|
|
19
|
+
<property name="screen_size_type" value="desktop" />
|
|
20
|
+
<property name="test_id" value="d998ade4-93bc-4d94-bab8-a73a290f8490" />
|
|
21
|
+
<property name="triggered_by" value="cli" />
|
|
22
|
+
<property name="report_format_version" value="1.0" />
|
|
23
|
+
</properties>
|
|
24
|
+
<testcase name="Tic Tac Toe simple [OK]" classname="TestSuite_Single" time="7.00" test_run_id="08deed80-07d1-4987-aaa3-e14a1f906a29" sequence="#3">
|
|
25
|
+
<system-out>=== Test Steps Execution (summary) ===
|
|
26
|
+
Total steps: 9
|
|
27
|
+
Passed: 9
|
|
28
|
+
Failed: 0
|
|
29
|
+
|
|
30
|
+
First 3 steps:
|
|
31
|
+
1. OK goto (2.36s)
|
|
32
|
+
2. OK click (1.22s)
|
|
33
|
+
3. OK click (0.27s)
|
|
34
|
+
</system-out>
|
|
35
|
+
</testcase>
|
|
36
|
+
</testsuite>
|
|
37
|
+
</testsuites>
|
package/src/utils/testReports.js
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
const { getJunitXml } = require('junit-xml');
|
|
2
|
-
const fs = require('node:fs');
|
|
3
|
-
const path = require('node:path');
|
|
4
|
-
|
|
5
|
-
const settings = require('../settings');
|
|
6
|
-
const { getSecondsFromDuration } = require('./helper');
|
|
7
|
-
|
|
8
|
-
const getTestInJunitFormat = (testRun) => {
|
|
9
|
-
const errorCode = testRun.errorCode ?? 'MISSING_ERROR_CODE';
|
|
10
|
-
const stepInfo = testRun.details?.[0]?.step;
|
|
11
|
-
const errorDetails = stepInfo
|
|
12
|
-
? {
|
|
13
|
-
message: `Error ${errorCode} occurred in step: ${stepInfo.type} (${stepInfo.id})`,
|
|
14
|
-
stack: errorCode,
|
|
15
|
-
}
|
|
16
|
-
: {
|
|
17
|
-
message: `Error ${errorCode} occurred`,
|
|
18
|
-
stack: errorCode,
|
|
19
|
-
};
|
|
20
|
-
const errorsList = errorDetails ? [errorDetails] : [];
|
|
21
|
-
|
|
22
|
-
return {
|
|
23
|
-
id: testRun.id,
|
|
24
|
-
name: testRun.name,
|
|
25
|
-
time: getSecondsFromDuration(testRun.duration),
|
|
26
|
-
classname: null,
|
|
27
|
-
errors: testRun.status === settings.STATUS_ERROR ? errorsList : [],
|
|
28
|
-
failures: testRun.status === settings.STATUS_FAILED ? errorsList : [],
|
|
29
|
-
};
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const getSuiteInJunitFormat = (suiteRun) => ({
|
|
33
|
-
id: suiteRun.id,
|
|
34
|
-
name: suiteRun.name,
|
|
35
|
-
time: getSecondsFromDuration(suiteRun.duration),
|
|
36
|
-
testCases: suiteRun.details.map((testRun) => getTestInJunitFormat(testRun)),
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
const generateJunitReport = async (type, result, outputPath) => {
|
|
40
|
-
const testReport = {};
|
|
41
|
-
testReport.name = 'BugBug Report';
|
|
42
|
-
testReport.time = getSecondsFromDuration(result.duration);
|
|
43
|
-
testReport.suites = [];
|
|
44
|
-
|
|
45
|
-
if (type === settings.TYPE_TEST) {
|
|
46
|
-
testReport.suites.push(
|
|
47
|
-
getSuiteInJunitFormat({
|
|
48
|
-
name: 'Single Test Run',
|
|
49
|
-
duration: result.duration,
|
|
50
|
-
details: [result],
|
|
51
|
-
}),
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (type === settings.TYPE_SUITE) {
|
|
56
|
-
testReport.suites.push(getSuiteInJunitFormat(result));
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const junitReport = getJunitXml(testReport);
|
|
60
|
-
fs.writeFileSync(path.join(process.cwd(), outputPath), junitReport, { flag: 'w+' });
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
module.exports = {
|
|
64
|
-
generateJunitReport,
|
|
65
|
-
};
|