junit-to-ctrf
Advanced tools
+8
-2
@@ -42,7 +42,13 @@ #!/usr/bin/env node | ||
| description: 'Environment properties', | ||
| }) | ||
| .option('use-suite-name', { | ||
| alias: 'u', | ||
| type: 'boolean', | ||
| default: true, | ||
| description: 'Use suite name in the test name', | ||
| }); | ||
| }, (argv) => __awaiter(void 0, void 0, void 0, function* () { | ||
| try { | ||
| const { path, output, tool, env } = argv; | ||
| yield (0, convert_1.convertJUnitToCTRF)(path, output, tool, env); | ||
| const { path, output, tool, env, useSuiteName } = argv; | ||
| yield (0, convert_1.convertJUnitToCTRF)(path, output, tool, env, useSuiteName); | ||
| console.log('Conversion completed successfully.'); | ||
@@ -49,0 +55,0 @@ } |
@@ -1,1 +0,1 @@ | ||
| export declare function convertJUnitToCTRF(junitPath: string, outputPath?: string, toolName?: string, envProps?: string[]): Promise<void>; | ||
| export declare function convertJUnitToCTRF(junitPath: string, outputPath?: string, toolName?: string, envProps?: string[], useSuiteName?: boolean): Promise<void>; |
+32
-15
@@ -28,5 +28,12 @@ "use strict"; | ||
| suite.testcase.forEach((testCase) => { | ||
| var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; | ||
| const { classname, name, time } = testCase.$; | ||
| const failure = testCase.failure ? testCase.failure[0] : undefined; | ||
| const error = testCase.error ? testCase.error[0] : undefined; | ||
| const hasFailure = testCase.failure !== undefined; | ||
| const failureTrace = hasFailure ? (((_a = testCase.failure[0]) === null || _a === void 0 ? void 0 : _a._) || '') : undefined; | ||
| const failureMessage = hasFailure ? (((_c = (_b = testCase.failure[0]) === null || _b === void 0 ? void 0 : _b.$) === null || _c === void 0 ? void 0 : _c.message) || '') : undefined; | ||
| const failureType = hasFailure ? (((_e = (_d = testCase.failure[0]) === null || _d === void 0 ? void 0 : _d.$) === null || _e === void 0 ? void 0 : _e.type) || '') : undefined; | ||
| const hasError = testCase.error !== undefined; | ||
| const errorTrace = hasError ? (((_f = testCase.error[0]) === null || _f === void 0 ? void 0 : _f._) || '') : undefined; | ||
| const errorMessage = hasError ? (((_h = (_g = testCase.error[0]) === null || _g === void 0 ? void 0 : _g.$) === null || _h === void 0 ? void 0 : _h.message) || '') : undefined; | ||
| const errorType = hasError ? (((_k = (_j = testCase.error[0]) === null || _j === void 0 ? void 0 : _j.$) === null || _k === void 0 ? void 0 : _k.type) || '') : undefined; | ||
| const skipped = testCase.skipped !== undefined; | ||
@@ -38,4 +45,10 @@ testCases.push({ | ||
| time, | ||
| failure: failure ? (typeof failure === 'string' ? failure : failure._) : undefined, | ||
| error: error ? (typeof error === 'string' ? error : error._) : undefined, | ||
| hasFailure, | ||
| failureTrace, | ||
| failureMessage, | ||
| failureType, | ||
| hasError, | ||
| errorTrace, | ||
| errorMessage, | ||
| errorType, | ||
| skipped, | ||
@@ -69,8 +82,8 @@ }); | ||
| } | ||
| function convertToCTRFTest(testCase) { | ||
| function convertToCTRFTest(testCase, useSuiteName) { | ||
| let status = 'other'; | ||
| if (testCase.failure) { | ||
| if (testCase.hasFailure) { | ||
| status = 'failed'; | ||
| } | ||
| else if (testCase.error) { | ||
| else if (testCase.hasError) { | ||
| status = 'failed'; | ||
@@ -84,13 +97,17 @@ } | ||
| } | ||
| const durationMs = Math.round(parseFloat(testCase.time) * 1000); | ||
| const durationMs = Math.round(parseFloat(testCase.time || '0') * 1000); | ||
| const testName = useSuiteName | ||
| ? `${testCase.suite}: ${testCase.name}` | ||
| : testCase.name; | ||
| return { | ||
| name: `${testCase.suite}: ${testCase.name}`, | ||
| name: testName, | ||
| status, | ||
| duration: durationMs, | ||
| message: testCase.failure || testCase.error ? (testCase.failure || testCase.error) : undefined, | ||
| trace: testCase.failure || testCase.error ? (testCase.failure || testCase.error) : undefined, | ||
| message: testCase.failureMessage || testCase.errorMessage || undefined, | ||
| trace: testCase.failureTrace || testCase.errorTrace || undefined, | ||
| suite: testCase.suite || '', | ||
| }; | ||
| } | ||
| function createCTRFReport(testCases, toolName, envProps) { | ||
| const ctrfTests = testCases.map(convertToCTRFTest); | ||
| function createCTRFReport(testCases, toolName, envProps, useSuiteName) { | ||
| const ctrfTests = testCases.map(testCase => convertToCTRFTest(testCase, !!useSuiteName)); | ||
| const passed = ctrfTests.filter(test => test.status === 'passed').length; | ||
@@ -126,7 +143,7 @@ const failed = ctrfTests.filter(test => test.status === 'failed').length; | ||
| } | ||
| function convertJUnitToCTRF(junitPath, outputPath, toolName, envProps) { | ||
| function convertJUnitToCTRF(junitPath, outputPath, toolName, envProps, useSuiteName) { | ||
| return __awaiter(this, void 0, void 0, function* () { | ||
| const testCases = yield parseJUnitReport(junitPath); | ||
| const envPropsObj = envProps ? Object.fromEntries(envProps.map(prop => prop.split('='))) : {}; | ||
| const ctrfReport = createCTRFReport(testCases, toolName, envPropsObj); | ||
| const ctrfReport = createCTRFReport(testCases, toolName, envPropsObj, useSuiteName); | ||
| const defaultOutputPath = path_1.default.join('ctrf', 'ctrf-report.json'); | ||
@@ -133,0 +150,0 @@ const finalOutputPath = path_1.default.resolve(outputPath || defaultOutputPath); |
+1
-1
| { | ||
| "name": "junit-to-ctrf", | ||
| "version": "0.0.5", | ||
| "version": "0.0.7", | ||
| "description": "", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
+9
-0
@@ -25,4 +25,7 @@ # Convert JUnit XML to CTRF JSON | ||
| `-u`, `--use-suite-name` <useSuiteName>: Use suite name in the test name, defaults to true. | ||
| `-e`, `--env` <envProperties>: Environment properties to include in the CTRF report. Accepts multiple properties in the format KEY=value. | ||
| ## Examples | ||
@@ -62,2 +65,8 @@ | ||
| ### Exclude Suite Name | ||
| ```sh | ||
| npx junit-to-ctrf path/to/junit.xml -u false | ||
| ``` | ||
| ### Full Command | ||
@@ -64,0 +73,0 @@ |
| #!/usr/bin/env node | ||
| export {}; |
| #!/usr/bin/env node | ||
| "use strict"; | ||
| var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
| function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
| return new (P || (P = Promise))(function (resolve, reject) { | ||
| function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
| function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
| function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
| step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
| }); | ||
| }; | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| const yargs_1 = __importDefault(require("yargs/yargs")); | ||
| const helpers_1 = require("yargs/helpers"); | ||
| const argv = (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv)) | ||
| .command('results <path>', 'Send test results summary to Teams', (yargs) => { | ||
| return yargs | ||
| .positional('path', { | ||
| describe: 'Path to the CTRF file', | ||
| type: 'string', | ||
| demandOption: true, | ||
| }) | ||
| .option('onFailOnly', { | ||
| alias: 'f', | ||
| type: 'boolean', | ||
| description: 'Send message only if there are failed tests', | ||
| default: false, | ||
| }); | ||
| }, (argv) => __awaiter(void 0, void 0, void 0, function* () { | ||
| try { | ||
| console.log('No failed tests. Message not sent.'); | ||
| console.log('Results message sent to Teams.'); | ||
| } | ||
| catch (error) { | ||
| console.error('Error:', error.message); | ||
| } | ||
| })) | ||
| .command('fail-details <path>', 'Send failed test results to Teams', (yargs) => { | ||
| return yargs.positional('path', { | ||
| describe: 'Path to the CTRF file', | ||
| type: 'string', | ||
| demandOption: true, | ||
| }); | ||
| }, (argv) => __awaiter(void 0, void 0, void 0, function* () { | ||
| try { | ||
| // await sendTeamsMessage(message); | ||
| console.log('Coming soon!'); | ||
| } | ||
| catch (error) { | ||
| console.error('Error:', error.message); | ||
| } | ||
| })) | ||
| .command('flaky <path>', 'Send flaky test results to Teams', (yargs) => { | ||
| return yargs.positional('path', { | ||
| describe: 'Path to the CTRF file', | ||
| type: 'string', | ||
| demandOption: true, | ||
| }); | ||
| }, (argv) => __awaiter(void 0, void 0, void 0, function* () { | ||
| try { | ||
| console.log('Flaky tests message sent to Teams.'); | ||
| console.log('No flaky tests detected. No message sent.'); | ||
| } | ||
| catch (error) { | ||
| console.error('Error:', error.message); | ||
| } | ||
| })) | ||
| .help() | ||
| .argv; |
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
91
10.98%14117
-6.79%7
-22.22%215
-19.17%