deflake 1.2.32 → 1.2.34
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 +30 -43
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -117,7 +117,7 @@ async function analyzeAndFix(artifacts, client, argv, capturedOutput = '') {
|
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
// Strip ANSI escape codes from captured output — they break regex matching
|
|
120
|
-
const cleanOutput = capturedOutput.replace(/\x1b\[[0-9;]*
|
|
120
|
+
const cleanOutput = capturedOutput.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '');
|
|
121
121
|
|
|
122
122
|
console.log(`${C.BRIGHT}🔍 Analyzing ${artifacts.length} failure(s)...${C.RESET}\n`);
|
|
123
123
|
let count = 0;
|
|
@@ -261,13 +261,9 @@ async function applyFix(res, loc) {
|
|
|
261
261
|
}
|
|
262
262
|
|
|
263
263
|
function extractRelevantOutput(fullOutput, artifactName) {
|
|
264
|
-
//
|
|
265
|
-
// Each Playwright failure ends with: "Error Context: test-results/<artifact-name>/error-context.md"
|
|
266
|
-
// We find that line, then walk backwards to capture the full error + stack trace.
|
|
267
|
-
|
|
264
|
+
// Find the Error Context line for this artifact, then grab 30 lines before it
|
|
268
265
|
const lines = fullOutput.split('\n');
|
|
269
266
|
|
|
270
|
-
// Find the Error Context line that matches this artifact
|
|
271
267
|
let anchorIdx = -1;
|
|
272
268
|
for (let i = 0; i < lines.length; i++) {
|
|
273
269
|
if (lines[i].includes('Error Context:') && lines[i].includes(artifactName)) {
|
|
@@ -277,7 +273,7 @@ function extractRelevantOutput(fullOutput, artifactName) {
|
|
|
277
273
|
}
|
|
278
274
|
|
|
279
275
|
if (anchorIdx === -1) {
|
|
280
|
-
// Fallback:
|
|
276
|
+
// Fallback: partial match on artifact name parts
|
|
281
277
|
const nameParts = artifactName.split('-').filter(p => p.length > 3);
|
|
282
278
|
for (let i = 0; i < lines.length; i++) {
|
|
283
279
|
if (lines[i].includes('Error Context:') && nameParts.some(part => lines[i].includes(part))) {
|
|
@@ -289,16 +285,8 @@ function extractRelevantOutput(fullOutput, artifactName) {
|
|
|
289
285
|
|
|
290
286
|
if (anchorIdx === -1) return '';
|
|
291
287
|
|
|
292
|
-
//
|
|
293
|
-
|
|
294
|
-
let startIdx = anchorIdx;
|
|
295
|
-
for (let i = anchorIdx; i >= 0; i--) {
|
|
296
|
-
if (lines[i].match(/^\s*\d+\)\s+\[/)) {
|
|
297
|
-
startIdx = i;
|
|
298
|
-
break;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
288
|
+
// Grab 30 lines before the anchor — guaranteed to include the full stack trace
|
|
289
|
+
const startIdx = Math.max(0, anchorIdx - 30);
|
|
302
290
|
return lines.slice(startIdx, anchorIdx + 1).join('\n');
|
|
303
291
|
}
|
|
304
292
|
|
|
@@ -306,36 +294,35 @@ function extractLoc(text) {
|
|
|
306
294
|
if (!text) return null;
|
|
307
295
|
|
|
308
296
|
// === MULTI-FRAMEWORK LOCATION EXTRACTION ===
|
|
309
|
-
//
|
|
310
|
-
|
|
311
|
-
// Strategy 1: Absolute path inside parentheses (most precise)
|
|
312
|
-
// Format: at FunctionName (/absolute/path/file.ts:75:35)
|
|
313
|
-
let m = text.match(/\(([^()]*?[\\/][^()]+\.(?:ts|js|tsx|jsx|mjs|cjs)):(\d+)(?::(\d+))?\)/);
|
|
314
|
-
if (m) return { path: path.resolve(m[1]), line: parseInt(m[2]) };
|
|
297
|
+
// Returns the LAST match (closest to the Error Context anchor)
|
|
298
|
+
// to avoid picking up stack traces from previous error blocks.
|
|
315
299
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
if (m) return { path: path.resolve(m[1]), line: parseInt(m[2]) };
|
|
300
|
+
const patterns = [
|
|
301
|
+
// Strategy 1: Absolute path in parens — at Func (/path/file.ts:75:35)
|
|
302
|
+
/\(([^()]*?[\\/][^()]+\.(?:ts|js|tsx|jsx|mjs|cjs)):(\d+)(?::(\d+))?\)/g,
|
|
303
|
+
// Strategy 2: Absolute path — at /path/file.ts:75:35
|
|
304
|
+
/at\s+(\/[^\s]+\.(?:ts|js|tsx|jsx)):(\d+)(?::(\d+))?/g,
|
|
305
|
+
// Strategy 3: Relative path — at ../pages/file.ts:75
|
|
306
|
+
/at\s+(\.\.?\/[^\s]+\.(?:ts|js|tsx|jsx)):(\d+)(?::(\d+))?/g,
|
|
307
|
+
];
|
|
325
308
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
309
|
+
let lastMatch = null;
|
|
310
|
+
for (const pattern of patterns) {
|
|
311
|
+
let m;
|
|
312
|
+
while ((m = pattern.exec(text)) !== null) {
|
|
313
|
+
lastMatch = { path: path.resolve(m[1]), line: parseInt(m[2]) };
|
|
314
|
+
}
|
|
315
|
+
if (lastMatch) return lastMatch;
|
|
316
|
+
}
|
|
333
317
|
|
|
334
|
-
// Strategy
|
|
335
|
-
|
|
336
|
-
|
|
318
|
+
// Strategy 4: Generic — any path-like /dir/file.ts:line
|
|
319
|
+
const generic = /((?:[\w@.-]+\/)+[\w.-]+\.(?:ts|js|tsx|jsx)):(\d+)/g;
|
|
320
|
+
let m;
|
|
321
|
+
while ((m = generic.exec(text)) !== null) {
|
|
322
|
+
lastMatch = { path: path.resolve(m[1]), line: parseInt(m[2]) };
|
|
323
|
+
}
|
|
337
324
|
|
|
338
|
-
return
|
|
325
|
+
return lastMatch;
|
|
339
326
|
}
|
|
340
327
|
|
|
341
328
|
async function runDoctor() {
|