deflake 1.2.9 → 1.2.12

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.
Files changed (2) hide show
  1. package/cli.js +50 -20
  2. package/package.json +1 -1
package/cli.js CHANGED
@@ -715,7 +715,6 @@ async function runDoctor(argv) {
715
715
  }
716
716
 
717
717
  async function applySelfHealing(result) {
718
-
719
718
  if (!result.location || !result.location.fullRootPath || !result.fix) return;
720
719
 
721
720
  try {
@@ -727,28 +726,55 @@ async function applySelfHealing(result) {
727
726
  return;
728
727
  }
729
728
 
730
- let fixCode = result.fix;
729
+ let patches = [];
731
730
  try {
732
731
  const parsed = JSON.parse(result.fix);
733
- if (parsed.code) fixCode = parsed.code;
734
- } catch (e) { }
732
+ if (parsed.patches && Array.isArray(parsed.patches)) {
733
+ patches = parsed.patches;
734
+ } else if (parsed.code) {
735
+ patches = [{
736
+ file: filePath,
737
+ line: targetLine,
738
+ action: 'REPLACE',
739
+ new_line: parsed.code
740
+ }];
741
+ }
742
+ } catch (e) {
743
+ // Fallback for raw string fixes
744
+ patches = [{
745
+ file: filePath,
746
+ line: targetLine,
747
+ action: 'REPLACE',
748
+ new_line: result.fix
749
+ }];
750
+ }
735
751
 
736
- const lines = fs.readFileSync(filePath, 'utf8').split('\n');
737
- const originalLineIndex = targetLine - 1;
752
+ for (const patch of patches) {
753
+ const pFile = patch.file || filePath;
754
+ const pLine = parseInt(patch.line || targetLine);
755
+ const pAction = patch.action || 'REPLACE';
756
+ let pNew = patch.new_line;
738
757
 
739
- if (originalLineIndex < 0 || originalLineIndex >= lines.length) {
740
- console.error(` ❌ [Self-Healing] Line ${targetLine} out of bounds in ${filePath}`);
741
- return;
742
- }
758
+ if (!fs.existsSync(pFile)) continue;
743
759
 
744
- // Apply fix: Replace the entire line or the specific locator
745
- // For robustness, we replace the whole line but keep indentation
746
- const originalLine = lines[originalLineIndex];
747
- const indentation = originalLine.match(/^\s*/)[0];
748
- lines[originalLineIndex] = indentation + fixCode.trim();
760
+ const lines = fs.readFileSync(pFile, 'utf8').split('\n');
761
+ const originalLineIndex = pLine - 1;
749
762
 
750
- fs.writeFileSync(filePath, lines.join('\n'));
751
- console.log(` ✅ ${C.GREEN}[Self-Healing] Successfully patched:${C.RESET} ${path.basename(filePath)}:${targetLine}`);
763
+ if (originalLineIndex < 0 || originalLineIndex >= lines.length) continue;
764
+
765
+ const originalLine = lines[originalLineIndex];
766
+ const indentation = originalLine.match(/^\s*/)[0];
767
+
768
+ if (pAction === 'INSERT_AFTER') {
769
+ lines.splice(pLine, 0, indentation + pNew.trim());
770
+ fs.writeFileSync(pFile, lines.join('\n'));
771
+ console.log(` ✅ ${C.GREEN}[Self-Healing] Successfully inserted at:${C.RESET} ${path.basename(pFile)}:${pLine}`);
772
+ } else {
773
+ lines[originalLineIndex] = indentation + pNew.trim();
774
+ fs.writeFileSync(pFile, lines.join('\n'));
775
+ console.log(` ✅ ${C.GREEN}[Self-Healing] Successfully patched:${C.RESET} ${path.basename(pFile)}:${pLine}`);
776
+ }
777
+ }
752
778
  } catch (error) {
753
779
  console.error(` ❌ ${C.RED}[Self-Healing] Error patching file:${C.RESET} ${error.message}`);
754
780
  }
@@ -981,6 +1007,7 @@ async function runCommand(cmd, args) {
981
1007
 
982
1008
  async function main() {
983
1009
  const command = argv._ || [];
1010
+ let finalExitCode = 0;
984
1011
 
985
1012
  // If 'doctor' or 'migrate' was called, don't proceed to wrapper logic
986
1013
  if (command.includes('doctor') || command.includes('migrate')) return;
@@ -1001,20 +1028,22 @@ async function main() {
1001
1028
  const artifacts = detectAllArtifacts(null, argv.html);
1002
1029
  const fixesApplied = await analyzeFailures(artifacts, output, client);
1003
1030
 
1031
+ let outcomeCode = code;
1004
1032
  // AUTO-VERIFICATION
1005
1033
  if (fixesApplied > 0 && argv.fix) {
1006
1034
  console.log(`\n${C.BRIGHT}💉 Fixes applied. Re-running tests to verify...${C.RESET}`);
1007
1035
  const secondRun = await runCommand(cmd, args);
1036
+ outcomeCode = secondRun.code;
1008
1037
  if (secondRun.code === 0) {
1009
1038
  console.log(`\n${C.GREEN}${C.BRIGHT}✅ All tests passed after DeFlake healing!${C.RESET}`);
1010
1039
  } else {
1011
1040
  console.log(`\n${C.YELLOW}⚠️ Some tests still failing after fixes. Check the report for details.${C.RESET}`);
1012
1041
  }
1013
1042
  }
1014
- process.exit(code);
1043
+ finalExitCode = outcomeCode;
1015
1044
  } else {
1016
1045
  console.log("\n🟢 Command passed successfully.");
1017
- process.exit(0);
1046
+ finalExitCode = 0;
1018
1047
  }
1019
1048
  } else {
1020
1049
  const artifacts = detectAllArtifacts(argv.log, argv.html);
@@ -1023,10 +1052,11 @@ async function main() {
1023
1052
  }
1024
1053
 
1025
1054
  // FINAL REPORT TRIGGER
1026
- // We wait until the very end so verification runs (if any) are reflected
1027
1055
  if (argv.report) {
1028
1056
  showFrameworkReport();
1029
1057
  }
1058
+
1059
+ process.exit(finalExitCode);
1030
1060
  }
1031
1061
 
1032
1062
  // main() call is now handled by the check above
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deflake",
3
- "version": "1.2.9",
3
+ "version": "1.2.12",
4
4
  "description": "AI-powered self-healing tool for Playwright, Cypress, and WebdriverIO tests.",
5
5
  "main": "client.js",
6
6
  "bin": {