deflake 1.0.6 → 1.0.8
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/cli.js +89 -32
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -307,7 +307,7 @@ function extractFailureLocation(logText) {
|
|
|
307
307
|
return null;
|
|
308
308
|
}
|
|
309
309
|
|
|
310
|
-
function printDetailedFix(fixText, location, sourceCode = null) {
|
|
310
|
+
function printDetailedFix(fixText, location, sourceCode = null, isApplied = false) {
|
|
311
311
|
const C = {
|
|
312
312
|
RESET: "\x1b[0m",
|
|
313
313
|
BRIGHT: "\x1b[1m",
|
|
@@ -332,32 +332,85 @@ function printDetailedFix(fixText, location, sourceCode = null) {
|
|
|
332
332
|
} catch (e) { }
|
|
333
333
|
|
|
334
334
|
console.log("\n" + C.GRAY + "─".repeat(50) + C.RESET);
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
335
|
+
|
|
336
|
+
if (isApplied) {
|
|
337
|
+
// --- APPLIED VIEW ---
|
|
338
|
+
console.log(`${C.GREEN}${C.BRIGHT}✅ FIX APPLIED:${C.RESET}`);
|
|
339
|
+
if (location) {
|
|
340
|
+
// Label is default color, Value is colored
|
|
341
|
+
const fileLabel = location.specFile || location.rootFile;
|
|
342
|
+
let lineLabel = location.testLine || location.rootLine;
|
|
343
|
+
|
|
344
|
+
if (fileLabel) {
|
|
345
|
+
console.log(`${C.BRIGHT}📄 File:${C.RESET} ${fileLabel}:${lineLabel}`);
|
|
346
|
+
}
|
|
339
347
|
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
348
|
+
|
|
349
|
+
if (explanation) { // Highlight the reason as requested by user
|
|
350
|
+
console.log(`\n${C.BRIGHT}ℹ️ Reason:${C.RESET} ${explanation}`);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
console.log(C.GRAY + "─".repeat(20) + C.RESET);
|
|
354
|
+
|
|
355
|
+
// --- OLD CODE (Context) ---
|
|
356
|
+
if (sourceCode && location && location.rootLine) {
|
|
357
|
+
console.log(`${C.RED}🔴 OLD:${C.RESET}`);
|
|
358
|
+
try {
|
|
359
|
+
const lines = sourceCode.split('\n');
|
|
360
|
+
const centerIdx = parseInt(location.rootLine) - 1;
|
|
361
|
+
// Show a small window around the error
|
|
362
|
+
const start = Math.max(0, centerIdx - 2);
|
|
363
|
+
const end = Math.min(lines.length - 1, centerIdx + 2);
|
|
364
|
+
|
|
365
|
+
for (let i = start; i <= end; i++) {
|
|
366
|
+
let prefix = (i === centerIdx) ? "> " : " ";
|
|
367
|
+
let line = lines[i];
|
|
368
|
+
if (i === centerIdx) line = `${C.RED}${line}${C.RESET}`;
|
|
369
|
+
else line = `${C.GRAY}${line}${C.RESET}`;
|
|
370
|
+
console.log(prefix + line);
|
|
371
|
+
}
|
|
372
|
+
} catch (e) { }
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// --- NEW CODE ---
|
|
376
|
+
console.log(`\n${C.GREEN}🟢 NEW:${C.RESET}`);
|
|
377
|
+
fixCode.split('\n').forEach(line => {
|
|
378
|
+
let colored = line
|
|
379
|
+
.replace(/(\/\/.*)/g, `${C.GRAY}$1${C.RESET}`)
|
|
380
|
+
.replace(/\b(const|let|var|await|async|function|return)\b/g, `${C.YELLOW}$1${C.RESET}`)
|
|
381
|
+
.replace(/('.*?')|(".*?")|(`.*?`)/g, `${C.GREEN}$1${C.RESET}`)
|
|
382
|
+
.replace(/(\.click|\.fill|\.locator)/g, `${C.CYAN}$1${C.RESET}`);
|
|
383
|
+
console.log(" " + colored);
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
} else {
|
|
387
|
+
// --- SUGGESTION VIEW (Default) ---
|
|
388
|
+
if (location) {
|
|
389
|
+
if (location.rootFile && location.rootLine) {
|
|
390
|
+
console.log(`💥 Runtime Error: ${C.RED}${location.rootFile}:${location.rootLine}${C.RESET}`);
|
|
391
|
+
}
|
|
392
|
+
if (location.specFile) {
|
|
393
|
+
let targetLabel = location.specFile;
|
|
394
|
+
if (location.testLine) targetLabel += `:${location.testLine}`;
|
|
395
|
+
console.log(`🎯 Fix Target: ${C.CYAN}${targetLabel} (Definition)${C.RESET}`);
|
|
396
|
+
}
|
|
345
397
|
}
|
|
398
|
+
console.log(C.GRAY + "─".repeat(50) + C.RESET);
|
|
399
|
+
|
|
400
|
+
console.log(`${C.GREEN}${C.BRIGHT}✨ DEFLAKE SUGGESTION:${C.RESET}`);
|
|
401
|
+
if (explanation) console.log(`${C.GRAY}// ${explanation}${C.RESET}`);
|
|
402
|
+
|
|
403
|
+
// Print code with simple coloring
|
|
404
|
+
fixCode.split('\n').forEach(line => {
|
|
405
|
+
let colored = line
|
|
406
|
+
.replace(/(\/\/.*)/g, `${C.GRAY}$1${C.RESET}`)
|
|
407
|
+
.replace(/\b(const|let|var|await|async|function|return)\b/g, `${C.YELLOW}$1${C.RESET}`)
|
|
408
|
+
.replace(/('.*?')|(".*?")|(`.*?`)/g, `${C.GREEN}$1${C.RESET}`)
|
|
409
|
+
.replace(/(\.click|\.fill|\.locator)/g, `${C.CYAN}$1${C.RESET}`);
|
|
410
|
+
console.log(" " + colored);
|
|
411
|
+
});
|
|
346
412
|
}
|
|
347
|
-
console.log(C.GRAY + "─".repeat(50) + C.RESET);
|
|
348
413
|
|
|
349
|
-
console.log(`${C.GREEN}${C.BRIGHT}✨ DEFLAKE SUGGESTION:${C.RESET}`);
|
|
350
|
-
if (explanation) console.log(`${C.GRAY}// ${explanation}${C.RESET}`);
|
|
351
|
-
|
|
352
|
-
// Print code with simple coloring
|
|
353
|
-
fixCode.split('\n').forEach(line => {
|
|
354
|
-
let colored = line
|
|
355
|
-
.replace(/(\/\/.*)/g, `${C.GRAY}$1${C.RESET}`)
|
|
356
|
-
.replace(/\b(const|let|var|await|async|function|return)\b/g, `${C.YELLOW}$1${C.RESET}`)
|
|
357
|
-
.replace(/('.*?')|(".*?")|(`.*?`)/g, `${C.GREEN}$1${C.RESET}`)
|
|
358
|
-
.replace(/(\.click|\.fill|\.locator)/g, `${C.CYAN}$1${C.RESET}`);
|
|
359
|
-
console.log(" " + colored);
|
|
360
|
-
});
|
|
361
414
|
console.log(C.GRAY + "─".repeat(50) + C.RESET);
|
|
362
415
|
}
|
|
363
416
|
|
|
@@ -658,11 +711,6 @@ async function analyzeFailures(artifacts, fullLog, client) {
|
|
|
658
711
|
process.stdout.write(`\r⏳ Analyzing ${art.name}... `);
|
|
659
712
|
const result = await runHealer(specificLog, art.htmlPath, argv.apiUrl, art.name);
|
|
660
713
|
|
|
661
|
-
if (result && result.status === 'error' && result.detail === 'QUOTA_EXCEEDED') {
|
|
662
|
-
console.log(`\n${C.RED}🛑 Quota exceeded! Stopping.${C.RESET}`);
|
|
663
|
-
break;
|
|
664
|
-
}
|
|
665
|
-
|
|
666
714
|
if (result && result.status === 'success') {
|
|
667
715
|
results.push(result);
|
|
668
716
|
|
|
@@ -670,15 +718,18 @@ async function analyzeFailures(artifacts, fullLog, client) {
|
|
|
670
718
|
if (argv.fix) {
|
|
671
719
|
await applySelfHealing(result);
|
|
672
720
|
}
|
|
721
|
+
} else {
|
|
722
|
+
console.log(`\n ${C.RED}❌ Analysis failed for ${art.name}:${C.RESET} ${result?.detail || 'Check server status'}`);
|
|
673
723
|
}
|
|
674
724
|
}
|
|
675
|
-
|
|
725
|
+
process.stdout.write("\r✅ Analysis complete. \n");
|
|
676
726
|
|
|
677
727
|
// GROUPING & PRINTING
|
|
678
728
|
const groups = {};
|
|
679
729
|
for (const res of results) {
|
|
680
|
-
|
|
681
|
-
const
|
|
730
|
+
// Use a unique key for grouping. If location is missing, use testName to ensure it shows up.
|
|
731
|
+
const locId = res.location ? `${res.location.rootFile}:${res.location.rootLine}` : `unknown-${res.testName}`;
|
|
732
|
+
const key = `${locId}|${JSON.stringify(res.fix)}`;
|
|
682
733
|
if (!groups[key]) {
|
|
683
734
|
groups[key] = { location: res.location, sourceCode: res.sourceCode, fix: res.fix, tests: [] };
|
|
684
735
|
}
|
|
@@ -692,7 +743,13 @@ async function analyzeFailures(artifacts, fullLog, client) {
|
|
|
692
743
|
});
|
|
693
744
|
|
|
694
745
|
for (const key of sortedKeys) {
|
|
695
|
-
printDetailedFix(groups[key].fix, groups[key].location, groups[key].sourceCode);
|
|
746
|
+
printDetailedFix(groups[key].fix, groups[key].location, groups[key].sourceCode, argv.fix);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
if (results.length > 0 && sortedKeys.length === 0) {
|
|
750
|
+
console.log(`${C.YELLOW}⚠️ Note: Some suggestions were found but could not be grouped for display.${C.RESET}`);
|
|
751
|
+
} else if (results.length === 0) {
|
|
752
|
+
console.log(`${C.GRAY}ℹ️ DeFlake analyzed the logs but couldn't find a confident fix for these errors.${C.RESET}`);
|
|
696
753
|
}
|
|
697
754
|
}
|
|
698
755
|
|