| export declare function identifyFlakyTests(filePath: string): Promise<void>; |
| "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 }); | ||
| exports.identifyFlakyTests = void 0; | ||
| const fs_1 = __importDefault(require("fs")); | ||
| const path_1 = __importDefault(require("path")); | ||
| function identifyFlakyTests(filePath) { | ||
| return __awaiter(this, void 0, void 0, function* () { | ||
| try { | ||
| const resolvedFilePath = path_1.default.resolve(filePath); | ||
| if (!fs_1.default.existsSync(resolvedFilePath)) { | ||
| console.error(`The file ${resolvedFilePath} does not exist.`); | ||
| return; | ||
| } | ||
| const fileContent = fs_1.default.readFileSync(resolvedFilePath, 'utf8'); | ||
| const report = JSON.parse(fileContent); | ||
| const flakyTests = report.results.tests.filter((test) => test.flaky === true); | ||
| if (flakyTests.length > 0) { | ||
| console.log(`Found ${flakyTests.length} flaky test(s):`); | ||
| flakyTests.forEach((test) => { | ||
| console.log(`- Test Name: ${test.name}, Retries: ${test.retries}`); | ||
| }); | ||
| } | ||
| else { | ||
| console.log(`No flaky tests found in ${resolvedFilePath}.`); | ||
| } | ||
| } | ||
| catch (error) { | ||
| console.error('Error identifying flaky tests:', error); | ||
| } | ||
| }); | ||
| } | ||
| exports.identifyFlakyTests = identifyFlakyTests; |
| export declare function mergeReports(directory: string, output: string, outputDir: string, keepReports: boolean): Promise<void>; |
| "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 }); | ||
| exports.mergeReports = void 0; | ||
| const fs_1 = __importDefault(require("fs")); | ||
| const path_1 = __importDefault(require("path")); | ||
| function mergeReports(directory, output, outputDir, keepReports) { | ||
| return __awaiter(this, void 0, void 0, function* () { | ||
| try { | ||
| const directoryPath = path_1.default.resolve(directory); | ||
| const outputFileName = output; | ||
| const resolvedOutputDir = outputDir ? path_1.default.resolve(outputDir) : directoryPath; | ||
| const outputPath = path_1.default.join(resolvedOutputDir, outputFileName); | ||
| console.log("Merging CTRF reports..."); | ||
| const files = fs_1.default.readdirSync(directoryPath); | ||
| files.forEach((file) => { | ||
| console.log('Found CTRF report file:', file); | ||
| }); | ||
| const ctrfReportFiles = files.filter((file) => { | ||
| try { | ||
| const filePath = path_1.default.join(directoryPath, file); | ||
| const fileContent = fs_1.default.readFileSync(filePath, 'utf8'); | ||
| const jsonData = JSON.parse(fileContent); | ||
| return jsonData.hasOwnProperty('results'); | ||
| } | ||
| catch (error) { | ||
| console.error(`Error reading JSON file '${file}':`, error); | ||
| return false; | ||
| } | ||
| }); | ||
| if (ctrfReportFiles.length === 0) { | ||
| console.log('No CTRF reports found in the specified directory.'); | ||
| return; | ||
| } | ||
| if (!fs_1.default.existsSync(resolvedOutputDir)) { | ||
| fs_1.default.mkdirSync(resolvedOutputDir, { recursive: true }); | ||
| console.log(`Created output directory: ${resolvedOutputDir}`); | ||
| } | ||
| const mergedReport = ctrfReportFiles | ||
| .map((file) => { | ||
| console.log("Merging report:", file); | ||
| const filePath = path_1.default.join(directoryPath, file); | ||
| const fileContent = fs_1.default.readFileSync(filePath, 'utf8'); | ||
| return JSON.parse(fileContent); | ||
| }) | ||
| .reduce((acc, curr) => { | ||
| if (!acc.results) { | ||
| return curr; | ||
| } | ||
| acc.results.summary.tests += curr.results.summary.tests; | ||
| acc.results.summary.passed += curr.results.summary.passed; | ||
| acc.results.summary.failed += curr.results.summary.failed; | ||
| acc.results.summary.skipped += curr.results.summary.skipped; | ||
| acc.results.summary.pending += curr.results.summary.pending; | ||
| acc.results.summary.other += curr.results.summary.other; | ||
| acc.results.tests.push(...curr.results.tests); | ||
| acc.results.summary.start = Math.min(acc.results.summary.start, curr.results.summary.start); | ||
| acc.results.summary.stop = Math.max(acc.results.summary.stop, curr.results.summary.stop); | ||
| return acc; | ||
| }, { results: null }); | ||
| fs_1.default.writeFileSync(outputPath, JSON.stringify(mergedReport, null, 2)); | ||
| if (!keepReports) { | ||
| ctrfReportFiles.forEach((file) => { | ||
| const filePath = path_1.default.join(directoryPath, file); | ||
| if (file !== outputFileName) { | ||
| fs_1.default.unlinkSync(filePath); | ||
| } | ||
| }); | ||
| } | ||
| console.log('CTRF reports merged successfully.'); | ||
| console.log(`Merged report saved to: ${outputPath}`); | ||
| } | ||
| catch (error) { | ||
| console.error('Error merging CTRF reports:', error); | ||
| } | ||
| }); | ||
| } | ||
| exports.mergeReports = mergeReports; |
+1
-1
@@ -1,2 +0,2 @@ | ||
| #!/usr/bin/env node | ||
| #!/usr/bin/env ts-node | ||
| export {}; |
+14
-74
@@ -1,2 +0,2 @@ | ||
| #!/usr/bin/env node | ||
| #!/usr/bin/env ts-node | ||
| "use strict"; | ||
@@ -16,6 +16,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| const fs_1 = __importDefault(require("fs")); | ||
| const path_1 = __importDefault(require("path")); | ||
| const yargs_1 = __importDefault(require("yargs/yargs")); | ||
| const helpers_1 = require("yargs/helpers"); | ||
| const merge_1 = require("./merge"); | ||
| const flaky_1 = require("./flaky"); | ||
| const argv = (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv)) | ||
@@ -47,76 +47,16 @@ .command('merge <directory>', 'Merge CTRF reports into a single report', (yargs) => { | ||
| }, (argv) => __awaiter(void 0, void 0, void 0, function* () { | ||
| try { | ||
| if (!argv.directory) { | ||
| throw new Error('The "directory" argument is required.'); | ||
| } | ||
| const directoryPath = path_1.default.resolve(argv.directory); | ||
| const outputFileName = argv.output; | ||
| const outputDir = argv['output-dir'] ? path_1.default.resolve(argv['output-dir']) : directoryPath; | ||
| const keepReports = argv['keep-reports']; | ||
| const outputPath = path_1.default.join(outputDir, outputFileName); | ||
| console.log("Merging CTRF reports..."); | ||
| const files = fs_1.default.readdirSync(directoryPath); | ||
| files.forEach((file) => { | ||
| console.log('Found CTRF report file:', file); | ||
| }); | ||
| const ctrfReportFiles = files.filter((file) => { | ||
| try { | ||
| const filePath = path_1.default.join(directoryPath, file); | ||
| const fileContent = fs_1.default.readFileSync(filePath, 'utf8'); | ||
| const jsonData = JSON.parse(fileContent); | ||
| return jsonData.hasOwnProperty('results'); | ||
| } | ||
| catch (error) { | ||
| console.error(`Error reading JSON file '${file}':`, error); | ||
| return false; | ||
| } | ||
| }); | ||
| if (ctrfReportFiles.length === 0) { | ||
| console.log('No CTRF reports found in the specified directory.'); | ||
| return; | ||
| } | ||
| if (!fs_1.default.existsSync(outputDir)) { | ||
| fs_1.default.mkdirSync(outputDir, { recursive: true }); | ||
| console.log(`Created output directory: ${outputDir}`); | ||
| } | ||
| const mergedReport = ctrfReportFiles | ||
| .map((file) => { | ||
| console.log("Merging report:", file); | ||
| const filePath = path_1.default.join(directoryPath, file); | ||
| const fileContent = fs_1.default.readFileSync(filePath, 'utf8'); | ||
| return JSON.parse(fileContent); | ||
| }) | ||
| .reduce((acc, curr) => { | ||
| if (!acc.results) { | ||
| return curr; | ||
| } | ||
| acc.results.summary.tests += curr.results.summary.tests; | ||
| acc.results.summary.passed += curr.results.summary.passed; | ||
| acc.results.summary.failed += curr.results.summary.failed; | ||
| acc.results.summary.skipped += curr.results.summary.skipped; | ||
| acc.results.summary.pending += curr.results.summary.pending; | ||
| acc.results.summary.other += curr.results.summary.other; | ||
| acc.results.tests.push(...curr.results.tests); | ||
| acc.results.summary.start = Math.min(acc.results.summary.start, curr.results.summary.start); | ||
| acc.results.summary.stop = Math.max(acc.results.summary.stop, curr.results.summary.stop); | ||
| return acc; | ||
| }, { results: null }); | ||
| fs_1.default.writeFileSync(outputPath, JSON.stringify(mergedReport, null, 2)); | ||
| if (!keepReports) { | ||
| ctrfReportFiles.forEach((file) => { | ||
| const filePath = path_1.default.join(directoryPath, file); | ||
| if (file !== outputFileName) { | ||
| fs_1.default.unlinkSync(filePath); | ||
| } | ||
| }); | ||
| } | ||
| console.log('CTRF reports merged successfully.'); | ||
| console.log(`Merged report saved to: ${outputPath}`); | ||
| } | ||
| catch (error) { | ||
| console.error('Error merging CTRF reports:', error); | ||
| } | ||
| yield (0, merge_1.mergeReports)(argv.directory, argv.output, argv['output-dir'], argv['keep-reports']); | ||
| })) | ||
| .command('flaky <file>', 'Identify flaky tests from a CTRF report file', (yargs) => { | ||
| return yargs | ||
| .positional('file', { | ||
| describe: 'CTRF report file', | ||
| type: 'string', | ||
| demandOption: true, | ||
| }); | ||
| }, (argv) => __awaiter(void 0, void 0, void 0, function* () { | ||
| yield (0, flaky_1.identifyFlakyTests)(argv.file); | ||
| })) | ||
| .help() | ||
| .demandCommand(1, 'You need at least one command before moving on') | ||
| .argv; |
+1
-1
| { | ||
| "name": "ctrf", | ||
| "version": "0.0.6", | ||
| "version": "0.0.7", | ||
| "description": "", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
+21
-4
@@ -32,3 +32,5 @@ # CTRF CLI | ||
| | `merge` | Merge multiple CTRF reports into a single report. | | ||
| | `flaky` | Output flaky test name and retries. | | ||
| ## Merge | ||
@@ -46,3 +48,3 @@ | ||
| ## Options | ||
| ### Options | ||
@@ -67,10 +69,25 @@ -o, --output `filename`: Output file name for the merged report. Default is ctrf-report.json. | ||
| ## Example | ||
| ## Flaky | ||
| Merge all CTRF reports in the ctrf directory into a single report named merged-report.json and save it in the output directory, keeping the original reports: | ||
| The flaky command is useful for identifying tests marked as flaky in your CTRF report. Flaky tests are tests that pass or fail inconsistently and may require special attention or retries to determine their reliability. | ||
| Usage | ||
| To output flaky tests, use the following command: | ||
| ```sh | ||
| npx ctrf merge ctrf --output merged-report.json --output-dir output --keep-reports | ||
| npx ctrf flaky <file-path> | ||
| ``` | ||
| Replace <file-path> with the path to the CTRF report file you want to analyze. | ||
| ### Output | ||
| The command will output the names of the flaky tests and the number of retries each test has undergone. For example: | ||
| ```zsh | ||
| Processing report: reports/sample-report.json | ||
| Found 1 flaky test(s) in reports/sample-report.json: | ||
| - Test Name: Test 1, Retries: 2 | ||
| ``` | ||
| ## What is CTRF? | ||
@@ -77,0 +94,0 @@ |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
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
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
15374
43.59%9
80%197
61.48%103
19.77%3
50%1
Infinity%