deflake 1.2.47 → 1.2.49
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 +25 -3
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -375,6 +375,7 @@ async function analyzeAndFix(artifacts, client, argv, capturedOutput = '', backu
|
|
|
375
375
|
|
|
376
376
|
console.log(`${C.BRIGHT}🔍 Analyzing ${artifacts.length} failure(s)...${C.RESET}\n`);
|
|
377
377
|
let count = 0;
|
|
378
|
+
const fixedFiles = new Set(); // Dedup: track files already fixed to avoid cascading mutations
|
|
378
379
|
for (let i = 0; i < artifacts.length; i++) {
|
|
379
380
|
const art = artifacts[i];
|
|
380
381
|
console.log(`${C.CYAN}━━━ [${i+1}/${artifacts.length}] ${art.name} ━━━${C.RESET}`);
|
|
@@ -404,6 +405,14 @@ async function analyzeAndFix(artifacts, client, argv, capturedOutput = '', backu
|
|
|
404
405
|
// Step 1: Location extraction
|
|
405
406
|
if (loc) {
|
|
406
407
|
console.log(` ${C.GRAY}📍 Location:${C.RESET} ${path.basename(loc.path)}:${loc.line} ${C.GRAY}(from ${locSource})${C.RESET}`);
|
|
408
|
+
|
|
409
|
+
// Dedup: skip if this EXACT file:line was already fixed by a previous artifact
|
|
410
|
+
const fileKey = `${loc.path}:${loc.line}`;
|
|
411
|
+
if (fixedFiles.has(fileKey)) {
|
|
412
|
+
console.log(` ${C.GREEN}⏭️ Already fixed by a previous artifact — skipping duplicate${C.RESET}`);
|
|
413
|
+
console.log('');
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
407
416
|
} else {
|
|
408
417
|
console.log(` ${C.YELLOW}📍 Location: Could not extract from any source${C.RESET}`);
|
|
409
418
|
}
|
|
@@ -455,9 +464,16 @@ async function analyzeAndFix(artifacts, client, argv, capturedOutput = '', backu
|
|
|
455
464
|
if (p.new_line && p.action === 'REPLACE') {
|
|
456
465
|
const validation = validateSelectorAgainstAxTree(p.new_line, content);
|
|
457
466
|
if (!validation.valid) {
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
467
|
+
// On last retry: allow getByRole/getByText through (dynamic elements not in initial AX tree)
|
|
468
|
+
const isLastRetry = retryIdx === MAX_VALIDATION_RETRIES - 1;
|
|
469
|
+
const isAccessibilitySelector = /getBy(Role|Text|Label|Placeholder)/.test(p.new_line);
|
|
470
|
+
if (isLastRetry && isAccessibilitySelector) {
|
|
471
|
+
console.log(` ${C.YELLOW}🔍 Validation SOFT-PASS for line ${p.line}: ${validation.reason} (last retry, allowing accessibility selector)${C.RESET}`);
|
|
472
|
+
} else {
|
|
473
|
+
allValid = false;
|
|
474
|
+
rejections.push(`Line ${p.line}: "${p.new_line.trim()}" → REJECTED: ${validation.reason}`);
|
|
475
|
+
console.log(` ${C.YELLOW}🔍 Validation FAILED for line ${p.line}: ${validation.reason}${C.RESET}`);
|
|
476
|
+
}
|
|
461
477
|
} else {
|
|
462
478
|
console.log(` ${C.GREEN}🔍 Validation OK for line ${p.line}: ${validation.reason}${C.RESET}`);
|
|
463
479
|
}
|
|
@@ -520,6 +536,7 @@ async function analyzeAndFix(artifacts, client, argv, capturedOutput = '', backu
|
|
|
520
536
|
console.log(` ${C.BRIGHT}💉 Applying patches...${C.RESET}`);
|
|
521
537
|
if (await applyFix(res, fixLoc, backups)) {
|
|
522
538
|
count++;
|
|
539
|
+
fixedFiles.add(`${fixLoc.path}:${fixLoc.line}`); // Track: don't fix this exact location again
|
|
523
540
|
console.log(` ${C.GREEN}${C.BRIGHT}✅ Fix applied to ${path.basename(fixLoc.path)}:${fixLoc.line}${C.RESET}`);
|
|
524
541
|
} else {
|
|
525
542
|
console.log(` ${C.YELLOW}⚠️ Patches could not be applied (see details above)${C.RESET}`);
|
|
@@ -601,6 +618,11 @@ async function applyFix(res, loc, backups = new Map()) {
|
|
|
601
618
|
console.log(` ${C.GRAY}⏭️ Skipped (already present): ${p.new_line.trim().substring(0, 60)}...${C.RESET}`);
|
|
602
619
|
continue;
|
|
603
620
|
}
|
|
621
|
+
// Safety: block constructor patterns (this.xxx =) from being inserted into spec/test files
|
|
622
|
+
if (/\.(spec|test)\.(ts|js)$/.test(filePath) && /^\s*this\.\w+\s*=/.test(p.new_line)) {
|
|
623
|
+
console.log(` ${C.YELLOW}⏭️ Blocked: constructor assignment in spec file (${p.new_line.trim().substring(0, 50)})${C.RESET}`);
|
|
624
|
+
continue;
|
|
625
|
+
}
|
|
604
626
|
if (p.action === 'INSERT_AFTER') {
|
|
605
627
|
// SAFETY: Detect if we'd insert at class scope (outside any method)
|
|
606
628
|
// Pattern: line is '}' (end of constructor/method) and next non-blank line starts a new method
|