playwright-intelligence-engine 2.0.4 → 2.1.0
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/dist/cli/index.d.ts.map +1 -1
- package/dist/core/version.d.ts +3 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +887 -225
- package/dist/intelligence/batch-repair-workflow.d.ts +52 -0
- package/dist/intelligence/batch-repair-workflow.d.ts.map +1 -0
- package/dist/intelligence/locator-disambiguation-engine.d.ts +4 -2
- package/dist/intelligence/locator-disambiguation-engine.d.ts.map +1 -1
- package/dist/repair/source-mapper.d.ts.map +1 -1
- package/dist/selector/repair-candidate-ranker.d.ts +2 -2
- package/dist/selector/repair-candidate-ranker.d.ts.map +1 -1
- package/dist/trace/archive-reader.d.ts +2 -0
- package/dist/trace/archive-reader.d.ts.map +1 -1
- package/dist/trace/snapshot-resolver.d.ts +7 -0
- package/dist/trace/snapshot-resolver.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/cli/index.ts +263 -27
- package/src/core/version.ts +2 -2
- package/src/index.ts +1 -0
- package/src/intelligence/batch-repair-workflow.ts +476 -0
- package/src/intelligence/locator-disambiguation-engine.ts +54 -3
- package/src/repair/source-mapper.ts +26 -1
- package/src/selector/repair-candidate-ranker.ts +3 -2
- package/src/trace/archive-reader.ts +18 -3
- package/src/trace/snapshot-resolver.ts +32 -0
|
@@ -24,6 +24,8 @@ export interface TraceEntryDiscovery {
|
|
|
24
24
|
/** All streams, ordered with explicit failure streams first. */
|
|
25
25
|
traceEntryNames?: string[] | undefined;
|
|
26
26
|
networkEntryNames?: string[] | undefined;
|
|
27
|
+
hasFailure?: boolean | undefined;
|
|
28
|
+
failureScore?: number | undefined;
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
export class ArchiveReader {
|
|
@@ -52,16 +54,23 @@ export class ArchiveReader {
|
|
|
52
54
|
const text = entry.getData().toString('utf8');
|
|
53
55
|
const lines = text.split(/\r?\n/);
|
|
54
56
|
let failureScore = 0;
|
|
57
|
+
let hasRealError = false;
|
|
55
58
|
for (const line of lines) {
|
|
56
59
|
if (!line.includes('"type":"')) continue;
|
|
57
|
-
if (line.includes('"type":"after"') && line.includes('"error"'))
|
|
58
|
-
|
|
60
|
+
if (line.includes('"type":"after"') && line.includes('"error"')) {
|
|
61
|
+
failureScore += 100;
|
|
62
|
+
hasRealError = true;
|
|
63
|
+
}
|
|
64
|
+
if (line.includes('"type":"error"') && (line.includes('"message"') || line.includes('"error"'))) {
|
|
65
|
+
failureScore += 80;
|
|
66
|
+
hasRealError = true;
|
|
67
|
+
}
|
|
59
68
|
if (line.includes('"type":"log"')) failureScore += 1;
|
|
60
69
|
}
|
|
61
70
|
if (path.basename(entry.entryName).toLowerCase() === 'test.trace' && failureScore > 0) {
|
|
62
71
|
failureScore += 10;
|
|
63
72
|
}
|
|
64
|
-
return { entry, failureScore };
|
|
73
|
+
return { entry, failureScore, hasRealError };
|
|
65
74
|
})
|
|
66
75
|
.sort((a, b) => b.failureScore - a.failureScore || b.entry.header.size - a.entry.header.size);
|
|
67
76
|
|
|
@@ -88,11 +97,17 @@ export class ArchiveReader {
|
|
|
88
97
|
bestNetwork = prefixMatch ? prefixMatch.entryName : networkCandidates.sort((a, b) => b.header.size - a.header.size)[0]?.entryName;
|
|
89
98
|
}
|
|
90
99
|
|
|
100
|
+
const topCandidate = traceCandidates[0];
|
|
101
|
+
const hasFailure = Boolean(topCandidate?.hasRealError);
|
|
102
|
+
const topFailureScore = topCandidate?.failureScore ?? 0;
|
|
103
|
+
|
|
91
104
|
return {
|
|
92
105
|
traceEntryName: bestTrace,
|
|
93
106
|
networkEntryName: bestNetwork,
|
|
94
107
|
traceEntryNames: orderedTraceNames,
|
|
95
108
|
networkEntryNames,
|
|
109
|
+
hasFailure,
|
|
110
|
+
failureScore: topFailureScore,
|
|
96
111
|
};
|
|
97
112
|
} catch {
|
|
98
113
|
return {};
|
|
@@ -3,6 +3,13 @@ export type NodeSnapshot =
|
|
|
3
3
|
| number
|
|
4
4
|
| [string, Record<string, string>, ...NodeSnapshot[]];
|
|
5
5
|
|
|
6
|
+
export interface BoundingBox {
|
|
7
|
+
x: number;
|
|
8
|
+
y: number;
|
|
9
|
+
width: number;
|
|
10
|
+
height: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
6
13
|
export interface ResolvedElement {
|
|
7
14
|
tag: string;
|
|
8
15
|
attributes: Record<string, string>;
|
|
@@ -10,6 +17,7 @@ export interface ResolvedElement {
|
|
|
10
17
|
children: ResolvedElement[];
|
|
11
18
|
role?: string | undefined;
|
|
12
19
|
accessibleName?: string | undefined;
|
|
20
|
+
boundingBox?: BoundingBox | undefined;
|
|
13
21
|
}
|
|
14
22
|
|
|
15
23
|
export type SnapshotCompleteness = 'COMPLETE' | 'PARTIAL' | 'UNAVAILABLE';
|
|
@@ -115,6 +123,17 @@ export class SnapshotResolver {
|
|
|
115
123
|
inputValue ??
|
|
116
124
|
textAccumulator.trim();
|
|
117
125
|
|
|
126
|
+
let boundingBox: BoundingBox | undefined;
|
|
127
|
+
const boxAttr = attributes['data-bbox'] ?? attributes['__playwright_box_'] ?? attributes['data-box'];
|
|
128
|
+
if (boxAttr) {
|
|
129
|
+
try {
|
|
130
|
+
const parts = boxAttr.split(',').map(Number);
|
|
131
|
+
if (parts.length === 4 && parts.every((p) => !isNaN(p))) {
|
|
132
|
+
boundingBox = { x: parts[0]!, y: parts[1]!, width: parts[2]!, height: parts[3]! };
|
|
133
|
+
}
|
|
134
|
+
} catch {}
|
|
135
|
+
}
|
|
136
|
+
|
|
118
137
|
return {
|
|
119
138
|
tag,
|
|
120
139
|
attributes,
|
|
@@ -122,6 +141,7 @@ export class SnapshotResolver {
|
|
|
122
141
|
children,
|
|
123
142
|
role,
|
|
124
143
|
accessibleName: accessibleName || undefined,
|
|
144
|
+
boundingBox,
|
|
125
145
|
};
|
|
126
146
|
}
|
|
127
147
|
|
|
@@ -222,6 +242,17 @@ export class SnapshotResolver {
|
|
|
222
242
|
inputValue ??
|
|
223
243
|
textAccumulator.trim();
|
|
224
244
|
|
|
245
|
+
let boundingBox: BoundingBox | undefined;
|
|
246
|
+
const boxAttr = attributes['data-bbox'] ?? attributes['__playwright_box_'] ?? attributes['data-box'];
|
|
247
|
+
if (boxAttr) {
|
|
248
|
+
try {
|
|
249
|
+
const parts = boxAttr.split(',').map(Number);
|
|
250
|
+
if (parts.length === 4 && parts.every((p) => !isNaN(p))) {
|
|
251
|
+
boundingBox = { x: parts[0]!, y: parts[1]!, width: parts[2]!, height: parts[3]! };
|
|
252
|
+
}
|
|
253
|
+
} catch {}
|
|
254
|
+
}
|
|
255
|
+
|
|
225
256
|
return {
|
|
226
257
|
tag,
|
|
227
258
|
attributes,
|
|
@@ -229,6 +260,7 @@ export class SnapshotResolver {
|
|
|
229
260
|
children,
|
|
230
261
|
role,
|
|
231
262
|
accessibleName: accessibleName || undefined,
|
|
263
|
+
boundingBox,
|
|
232
264
|
};
|
|
233
265
|
}
|
|
234
266
|
|