@fasttest-ai/qa-agent 0.1.3 → 0.3.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/bin/qa-agent-ci.js +3 -0
- package/dist/actions.d.ts +3 -0
- package/dist/actions.js +38 -4
- package/dist/actions.js.map +1 -1
- package/dist/browser.d.ts +30 -0
- package/dist/browser.js +120 -6
- package/dist/browser.js.map +1 -1
- package/dist/cli.d.ts +19 -0
- package/dist/cli.js +182 -0
- package/dist/cli.js.map +1 -0
- package/dist/cloud.d.ts +134 -6
- package/dist/cloud.js +150 -21
- package/dist/cloud.js.map +1 -1
- package/dist/config.d.ts +21 -0
- package/dist/config.js +49 -0
- package/dist/config.js.map +1 -0
- package/dist/healer.d.ts +1 -1
- package/dist/healer.js +56 -68
- package/dist/healer.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +893 -54
- package/dist/index.js.map +1 -1
- package/dist/runner.d.ts +3 -0
- package/dist/runner.js +245 -19
- package/dist/runner.js.map +1 -1
- package/dist/variables.d.ts +30 -0
- package/dist/variables.js +104 -0
- package/dist/variables.js.map +1 -0
- package/package.json +8 -4
package/dist/healer.js
CHANGED
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
* After a successful heal the pattern is stored in the Cloud DB so
|
|
12
12
|
* future failures with the same signature are fixed instantly.
|
|
13
13
|
*/
|
|
14
|
-
import * as actions from "./actions.js";
|
|
15
14
|
// ---------------------------------------------------------------------------
|
|
16
15
|
// Strategy confidence map
|
|
17
16
|
// ---------------------------------------------------------------------------
|
|
@@ -30,34 +29,36 @@ const CONFIDENCE = {
|
|
|
30
29
|
* Returns the first working selector with its confidence score.
|
|
31
30
|
*/
|
|
32
31
|
export async function healSelector(page, cloud, originalSelector, failureType, errorMessage, pageUrl) {
|
|
33
|
-
// 1. Check Cloud for a stored pattern first
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
32
|
+
// 1. Check Cloud for a stored pattern first (only if cloud is available)
|
|
33
|
+
if (cloud) {
|
|
34
|
+
try {
|
|
35
|
+
const classification = await cloud.post("/qa/healing/classify", {
|
|
36
|
+
failure_type: failureType,
|
|
37
|
+
selector: originalSelector,
|
|
38
|
+
page_url: pageUrl,
|
|
39
|
+
error_message: errorMessage,
|
|
40
|
+
});
|
|
41
|
+
if (classification.is_real_bug) {
|
|
42
|
+
return { healed: false, error: classification.reason ?? "Classified as real bug" };
|
|
43
|
+
}
|
|
44
|
+
if (classification.pattern) {
|
|
45
|
+
// Validate the stored pattern still works
|
|
46
|
+
const found = await testSelector(page, classification.pattern.healed_value);
|
|
47
|
+
if (found) {
|
|
48
|
+
return {
|
|
49
|
+
healed: true,
|
|
50
|
+
newSelector: classification.pattern.healed_value,
|
|
51
|
+
strategy: classification.pattern.strategy,
|
|
52
|
+
confidence: classification.pattern.confidence,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
54
55
|
}
|
|
55
56
|
}
|
|
57
|
+
catch {
|
|
58
|
+
// Non-fatal — continue with local strategies
|
|
59
|
+
}
|
|
56
60
|
}
|
|
57
|
-
|
|
58
|
-
// Non-fatal — continue with local strategies
|
|
59
|
-
}
|
|
60
|
-
// 2. Try local repair strategies in order
|
|
61
|
+
// 2. Try local repair strategies in order (no cloud needed)
|
|
61
62
|
const strategies = [
|
|
62
63
|
{ name: "data_testid", fn: () => tryDataTestId(page, originalSelector) },
|
|
63
64
|
{ name: "aria", fn: () => tryAria(page, originalSelector) },
|
|
@@ -67,8 +68,10 @@ export async function healSelector(page, cloud, originalSelector, failureType, e
|
|
|
67
68
|
for (const strategy of strategies) {
|
|
68
69
|
const candidate = await strategy.fn();
|
|
69
70
|
if (candidate) {
|
|
70
|
-
// Report the pattern to Cloud for future reuse
|
|
71
|
-
|
|
71
|
+
// Report the pattern to Cloud for future reuse (if connected)
|
|
72
|
+
if (cloud) {
|
|
73
|
+
await storePatternQuietly(cloud, failureType, originalSelector, candidate, strategy.name, CONFIDENCE[strategy.name] ?? 0.8, pageUrl);
|
|
74
|
+
}
|
|
72
75
|
return {
|
|
73
76
|
healed: true,
|
|
74
77
|
newSelector: candidate,
|
|
@@ -77,40 +80,17 @@ export async function healSelector(page, cloud, originalSelector, failureType, e
|
|
|
77
80
|
};
|
|
78
81
|
}
|
|
79
82
|
}
|
|
80
|
-
// 3. AI
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const suggestions = await cloud.post("/qa/healing/ai-suggest", {
|
|
84
|
-
original_selector: originalSelector,
|
|
85
|
-
page_snapshot: JSON.stringify(snapshot),
|
|
86
|
-
error_message: errorMessage,
|
|
87
|
-
page_url: pageUrl,
|
|
88
|
-
});
|
|
89
|
-
for (const suggestion of suggestions.suggestions ?? []) {
|
|
90
|
-
const found = await testSelector(page, suggestion.selector);
|
|
91
|
-
if (found) {
|
|
92
|
-
await storePatternQuietly(cloud, failureType, originalSelector, suggestion.selector, "ai", suggestion.confidence, pageUrl);
|
|
93
|
-
return {
|
|
94
|
-
healed: true,
|
|
95
|
-
newSelector: suggestion.selector,
|
|
96
|
-
strategy: "ai",
|
|
97
|
-
confidence: suggestion.confidence,
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
catch {
|
|
103
|
-
// Non-fatal
|
|
104
|
-
}
|
|
105
|
-
return { healed: false, error: "All healing strategies exhausted" };
|
|
83
|
+
// 3. No AI strategy here — the caller (index.ts) will fall back to
|
|
84
|
+
// the host AI with a page snapshot + prompt if local strategies fail.
|
|
85
|
+
return { healed: false, error: "Local healing strategies exhausted" };
|
|
106
86
|
}
|
|
107
87
|
// ---------------------------------------------------------------------------
|
|
108
88
|
// Strategy implementations
|
|
109
89
|
// ---------------------------------------------------------------------------
|
|
110
90
|
async function testSelector(page, selector) {
|
|
111
91
|
try {
|
|
112
|
-
const
|
|
113
|
-
return
|
|
92
|
+
const count = await page.locator(selector).count();
|
|
93
|
+
return count > 0;
|
|
114
94
|
}
|
|
115
95
|
catch {
|
|
116
96
|
return false;
|
|
@@ -225,20 +205,28 @@ async function tryStructural(page, original) {
|
|
|
225
205
|
// ---------------------------------------------------------------------------
|
|
226
206
|
/**
|
|
227
207
|
* Extract a meaningful name from a CSS selector.
|
|
228
|
-
*
|
|
208
|
+
* Handles common patterns: attribute selectors, IDs, classes, name attrs.
|
|
229
209
|
*/
|
|
230
210
|
function extractName(selector) {
|
|
231
|
-
//
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
//
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
//
|
|
240
|
-
|
|
241
|
-
|
|
211
|
+
// 1. Try attribute selectors: [data-testid="value"], [name="value"], etc.
|
|
212
|
+
const attrMatch = selector.match(/\[(?:data-testid|data-test|data-test-id|id|name|aria-label)\s*[~|^$*]?=\s*["']([^"']+)["']\]/);
|
|
213
|
+
if (attrMatch)
|
|
214
|
+
return attrMatch[1];
|
|
215
|
+
// 2. Extract from #id
|
|
216
|
+
const idMatch = selector.match(/#([\w-]+)/);
|
|
217
|
+
if (idMatch)
|
|
218
|
+
return idMatch[1];
|
|
219
|
+
// 3. Extract from .class (use the last/most-specific class)
|
|
220
|
+
const classMatches = [...selector.matchAll(/\.([\w-]+)/g)];
|
|
221
|
+
if (classMatches.length > 0)
|
|
222
|
+
return classMatches[classMatches.length - 1][1];
|
|
223
|
+
// 4. Extract from [name="value"]
|
|
224
|
+
const nameMatch = selector.match(/\[name=["']([^"']+)["']\]/);
|
|
225
|
+
if (nameMatch)
|
|
226
|
+
return nameMatch[1];
|
|
227
|
+
// 5. Last resort: first word that looks like an identifier (3+ chars)
|
|
228
|
+
const wordMatch = selector.match(/[a-zA-Z][\w-]{2,}/);
|
|
229
|
+
return wordMatch?.[0] ?? null;
|
|
242
230
|
}
|
|
243
231
|
async function storePatternQuietly(cloud, failureType, originalValue, healedValue, strategy, confidence, pageUrl) {
|
|
244
232
|
try {
|
package/dist/healer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"healer.js","sourceRoot":"","sources":["../src/healer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;
|
|
1
|
+
{"version":3,"file":"healer.js","sourceRoot":"","sources":["../src/healer.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* FastTest Agent — MCP server (stdio transport).
|
|
4
4
|
*
|
|
5
5
|
* This is the ONLY MCP server in the architecture.
|
|
6
6
|
* Flow: Claude Code → MCP → Local Skill → HTTPS → Cloud API
|
|
7
7
|
*
|
|
8
8
|
* Exposes:
|
|
9
|
-
* -
|
|
10
|
-
* -
|
|
9
|
+
* - 21 browser tools (Playwright, runs locally)
|
|
10
|
+
* - Local-first tools (test, explore, heal — host AI drives via structured prompts)
|
|
11
|
+
* - Cloud tools (save_suite, update_suite, run, status, cancel, etc. — require setup)
|
|
11
12
|
*/
|
|
12
13
|
export {};
|