@yasserkhanorg/e2e-agents 0.3.2
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/LICENSE +168 -0
- package/README.md +620 -0
- package/dist/agent/analysis.d.ts +62 -0
- package/dist/agent/analysis.d.ts.map +1 -0
- package/dist/agent/analysis.js +292 -0
- package/dist/agent/blast_radius.d.ts +4 -0
- package/dist/agent/blast_radius.d.ts.map +1 -0
- package/dist/agent/blast_radius.js +37 -0
- package/dist/agent/cache_utils.d.ts +38 -0
- package/dist/agent/cache_utils.d.ts.map +1 -0
- package/dist/agent/cache_utils.js +67 -0
- package/dist/agent/config.d.ts +148 -0
- package/dist/agent/config.d.ts.map +1 -0
- package/dist/agent/config.js +640 -0
- package/dist/agent/dependency_graph.d.ts +14 -0
- package/dist/agent/dependency_graph.d.ts.map +1 -0
- package/dist/agent/dependency_graph.js +227 -0
- package/dist/agent/feedback.d.ts +55 -0
- package/dist/agent/feedback.d.ts.map +1 -0
- package/dist/agent/feedback.js +257 -0
- package/dist/agent/flags.d.ts +23 -0
- package/dist/agent/flags.d.ts.map +1 -0
- package/dist/agent/flags.js +171 -0
- package/dist/agent/flow_catalog.d.ts +25 -0
- package/dist/agent/flow_catalog.d.ts.map +1 -0
- package/dist/agent/flow_catalog.js +106 -0
- package/dist/agent/flow_mapping.d.ts +10 -0
- package/dist/agent/flow_mapping.d.ts.map +1 -0
- package/dist/agent/flow_mapping.js +84 -0
- package/dist/agent/framework.d.ts +13 -0
- package/dist/agent/framework.d.ts.map +1 -0
- package/dist/agent/framework.js +149 -0
- package/dist/agent/gap_suggestions.d.ts +14 -0
- package/dist/agent/gap_suggestions.d.ts.map +1 -0
- package/dist/agent/gap_suggestions.js +101 -0
- package/dist/agent/generator.d.ts +10 -0
- package/dist/agent/generator.d.ts.map +1 -0
- package/dist/agent/generator.js +115 -0
- package/dist/agent/git.d.ts +11 -0
- package/dist/agent/git.d.ts.map +1 -0
- package/dist/agent/git.js +90 -0
- package/dist/agent/handoff.d.ts +22 -0
- package/dist/agent/handoff.d.ts.map +1 -0
- package/dist/agent/handoff.js +180 -0
- package/dist/agent/impact-analyzer.d.ts +114 -0
- package/dist/agent/impact-analyzer.d.ts.map +1 -0
- package/dist/agent/impact-analyzer.js +557 -0
- package/dist/agent/index.d.ts +21 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +38 -0
- package/dist/agent/model-router.d.ts +57 -0
- package/dist/agent/model-router.d.ts.map +1 -0
- package/dist/agent/model-router.js +154 -0
- package/dist/agent/operational_insights.d.ts +41 -0
- package/dist/agent/operational_insights.d.ts.map +1 -0
- package/dist/agent/operational_insights.js +126 -0
- package/dist/agent/pipeline.d.ts +23 -0
- package/dist/agent/pipeline.d.ts.map +1 -0
- package/dist/agent/pipeline.js +609 -0
- package/dist/agent/plan.d.ts +91 -0
- package/dist/agent/plan.d.ts.map +1 -0
- package/dist/agent/plan.js +331 -0
- package/dist/agent/playwright_report.d.ts +8 -0
- package/dist/agent/playwright_report.d.ts.map +1 -0
- package/dist/agent/playwright_report.js +126 -0
- package/dist/agent/report-generator.d.ts +24 -0
- package/dist/agent/report-generator.d.ts.map +1 -0
- package/dist/agent/report-generator.js +250 -0
- package/dist/agent/report.d.ts +81 -0
- package/dist/agent/report.d.ts.map +1 -0
- package/dist/agent/report.js +147 -0
- package/dist/agent/runner.d.ts +7 -0
- package/dist/agent/runner.d.ts.map +1 -0
- package/dist/agent/runner.js +576 -0
- package/dist/agent/selectors.d.ts +10 -0
- package/dist/agent/selectors.d.ts.map +1 -0
- package/dist/agent/selectors.js +75 -0
- package/dist/agent/spec-bridge.d.ts +101 -0
- package/dist/agent/spec-bridge.d.ts.map +1 -0
- package/dist/agent/spec-bridge.js +273 -0
- package/dist/agent/spec-builder.d.ts +102 -0
- package/dist/agent/spec-builder.d.ts.map +1 -0
- package/dist/agent/spec-builder.js +273 -0
- package/dist/agent/subsystem_risk.d.ts +23 -0
- package/dist/agent/subsystem_risk.d.ts.map +1 -0
- package/dist/agent/subsystem_risk.js +207 -0
- package/dist/agent/telemetry.d.ts +84 -0
- package/dist/agent/telemetry.d.ts.map +1 -0
- package/dist/agent/telemetry.js +220 -0
- package/dist/agent/test_path.d.ts +2 -0
- package/dist/agent/test_path.d.ts.map +1 -0
- package/dist/agent/test_path.js +23 -0
- package/dist/agent/tests.d.ts +18 -0
- package/dist/agent/tests.d.ts.map +1 -0
- package/dist/agent/tests.js +106 -0
- package/dist/agent/traceability.d.ts +22 -0
- package/dist/agent/traceability.d.ts.map +1 -0
- package/dist/agent/traceability.js +183 -0
- package/dist/agent/traceability_capture.d.ts +18 -0
- package/dist/agent/traceability_capture.d.ts.map +1 -0
- package/dist/agent/traceability_capture.js +313 -0
- package/dist/agent/traceability_ingest.d.ts +21 -0
- package/dist/agent/traceability_ingest.d.ts.map +1 -0
- package/dist/agent/traceability_ingest.js +237 -0
- package/dist/agent/utils.d.ts +13 -0
- package/dist/agent/utils.d.ts.map +1 -0
- package/dist/agent/utils.js +152 -0
- package/dist/agent/validators/selector-validator.d.ts +74 -0
- package/dist/agent/validators/selector-validator.d.ts.map +1 -0
- package/dist/agent/validators/selector-validator.js +165 -0
- package/dist/anthropic_provider.d.ts +65 -0
- package/dist/anthropic_provider.d.ts.map +1 -0
- package/dist/anthropic_provider.js +332 -0
- package/dist/api.d.ts +48 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +113 -0
- package/dist/base_provider.d.ts +53 -0
- package/dist/base_provider.d.ts.map +1 -0
- package/dist/base_provider.js +81 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +843 -0
- package/dist/custom_provider.d.ts +20 -0
- package/dist/custom_provider.d.ts.map +1 -0
- package/dist/custom_provider.js +276 -0
- package/dist/e2e-test-gen/index.d.ts +51 -0
- package/dist/e2e-test-gen/index.d.ts.map +1 -0
- package/dist/e2e-test-gen/index.js +57 -0
- package/dist/e2e-test-gen/spec_parser.d.ts +142 -0
- package/dist/e2e-test-gen/spec_parser.d.ts.map +1 -0
- package/dist/e2e-test-gen/spec_parser.js +786 -0
- package/dist/e2e-test-gen/types.d.ts +185 -0
- package/dist/e2e-test-gen/types.d.ts.map +1 -0
- package/dist/e2e-test-gen/types.js +4 -0
- package/dist/esm/agent/analysis.js +287 -0
- package/dist/esm/agent/blast_radius.js +34 -0
- package/dist/esm/agent/cache_utils.js +63 -0
- package/dist/esm/agent/config.js +637 -0
- package/dist/esm/agent/dependency_graph.js +224 -0
- package/dist/esm/agent/feedback.js +253 -0
- package/dist/esm/agent/flags.js +160 -0
- package/dist/esm/agent/flow_catalog.js +103 -0
- package/dist/esm/agent/flow_mapping.js +81 -0
- package/dist/esm/agent/framework.js +145 -0
- package/dist/esm/agent/gap_suggestions.js +98 -0
- package/dist/esm/agent/generator.js +112 -0
- package/dist/esm/agent/git.js +87 -0
- package/dist/esm/agent/handoff.js +177 -0
- package/dist/esm/agent/impact-analyzer.js +548 -0
- package/dist/esm/agent/index.js +22 -0
- package/dist/esm/agent/model-router.js +150 -0
- package/dist/esm/agent/operational_insights.js +123 -0
- package/dist/esm/agent/pipeline.js +605 -0
- package/dist/esm/agent/plan.js +324 -0
- package/dist/esm/agent/playwright_report.js +123 -0
- package/dist/esm/agent/report-generator.js +247 -0
- package/dist/esm/agent/report.js +144 -0
- package/dist/esm/agent/runner.js +572 -0
- package/dist/esm/agent/selectors.js +71 -0
- package/dist/esm/agent/spec-bridge.js +267 -0
- package/dist/esm/agent/spec-builder.js +267 -0
- package/dist/esm/agent/subsystem_risk.js +204 -0
- package/dist/esm/agent/telemetry.js +216 -0
- package/dist/esm/agent/test_path.js +20 -0
- package/dist/esm/agent/tests.js +101 -0
- package/dist/esm/agent/traceability.js +180 -0
- package/dist/esm/agent/traceability_capture.js +310 -0
- package/dist/esm/agent/traceability_ingest.js +234 -0
- package/dist/esm/agent/utils.js +138 -0
- package/dist/esm/agent/validators/selector-validator.js +160 -0
- package/dist/esm/anthropic_provider.js +324 -0
- package/dist/esm/api.js +105 -0
- package/dist/esm/base_provider.js +77 -0
- package/dist/esm/cli.js +841 -0
- package/dist/esm/custom_provider.js +272 -0
- package/dist/esm/e2e-test-gen/index.js +50 -0
- package/dist/esm/e2e-test-gen/spec_parser.js +782 -0
- package/dist/esm/e2e-test-gen/types.js +3 -0
- package/dist/esm/index.js +16 -0
- package/dist/esm/logger.js +89 -0
- package/dist/esm/mcp-server.js +465 -0
- package/dist/esm/ollama_provider.js +300 -0
- package/dist/esm/openai_provider.js +242 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/plan-and-test-constants.js +126 -0
- package/dist/esm/provider_factory.js +336 -0
- package/dist/esm/provider_interface.js +23 -0
- package/dist/esm/provider_utils.js +96 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/logger.d.ts +23 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +93 -0
- package/dist/mcp-server.d.ts +35 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +469 -0
- package/dist/ollama_provider.d.ts +65 -0
- package/dist/ollama_provider.d.ts.map +1 -0
- package/dist/ollama_provider.js +308 -0
- package/dist/openai_provider.d.ts +23 -0
- package/dist/openai_provider.d.ts.map +1 -0
- package/dist/openai_provider.js +250 -0
- package/dist/plan-and-test-constants.d.ts +110 -0
- package/dist/plan-and-test-constants.d.ts.map +1 -0
- package/dist/plan-and-test-constants.js +132 -0
- package/dist/provider_factory.d.ts +99 -0
- package/dist/provider_factory.d.ts.map +1 -0
- package/dist/provider_factory.js +341 -0
- package/dist/provider_interface.d.ts +358 -0
- package/dist/provider_interface.d.ts.map +1 -0
- package/dist/provider_interface.js +28 -0
- package/dist/provider_utils.d.ts +39 -0
- package/dist/provider_utils.d.ts.map +1 -0
- package/dist/provider_utils.js +103 -0
- package/package.json +101 -0
- package/schemas/gap.schema.json +18 -0
- package/schemas/impact.schema.json +418 -0
- package/schemas/plan.schema.json +285 -0
- package/schemas/subsystem-risk-map.schema.json +62 -0
- package/schemas/traceability-input.schema.json +122 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
3
|
+
// See LICENSE.txt for license information.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.hasGlobChars = hasGlobChars;
|
|
6
|
+
exports.globToRegExp = globToRegExp;
|
|
7
|
+
exports.matchGlob = matchGlob;
|
|
8
|
+
exports.safeReadTextFile = safeReadTextFile;
|
|
9
|
+
exports.normalizePath = normalizePath;
|
|
10
|
+
exports.toRelativePosix = toRelativePosix;
|
|
11
|
+
exports.isPathWithinRoot = isPathWithinRoot;
|
|
12
|
+
exports.fileExtension = fileExtension;
|
|
13
|
+
exports.baseNameWithoutExt = baseNameWithoutExt;
|
|
14
|
+
exports.tokenize = tokenize;
|
|
15
|
+
exports.uniqueTokens = uniqueTokens;
|
|
16
|
+
exports.titleCase = titleCase;
|
|
17
|
+
const fs_1 = require("fs");
|
|
18
|
+
const path_1 = require("path");
|
|
19
|
+
const MAX_READ_BYTES = 1024 * 1024; // 1MB
|
|
20
|
+
const STOP_WORDS = new Set([
|
|
21
|
+
'index',
|
|
22
|
+
'component',
|
|
23
|
+
'components',
|
|
24
|
+
'page',
|
|
25
|
+
'pages',
|
|
26
|
+
'screen',
|
|
27
|
+
'screens',
|
|
28
|
+
'view',
|
|
29
|
+
'views',
|
|
30
|
+
'route',
|
|
31
|
+
'routes',
|
|
32
|
+
'feature',
|
|
33
|
+
'features',
|
|
34
|
+
'module',
|
|
35
|
+
'modules',
|
|
36
|
+
'flow',
|
|
37
|
+
'flows',
|
|
38
|
+
'test',
|
|
39
|
+
'tests',
|
|
40
|
+
'spec',
|
|
41
|
+
'specs',
|
|
42
|
+
'hooks',
|
|
43
|
+
'hook',
|
|
44
|
+
'context',
|
|
45
|
+
'state',
|
|
46
|
+
'store',
|
|
47
|
+
]);
|
|
48
|
+
const GLOB_CHARS = /[*?[\]{}()!]/;
|
|
49
|
+
function hasGlobChars(value) {
|
|
50
|
+
return GLOB_CHARS.test(value);
|
|
51
|
+
}
|
|
52
|
+
function globToRegExp(pattern) {
|
|
53
|
+
const normalized = normalizePath(pattern);
|
|
54
|
+
let regex = '^';
|
|
55
|
+
let i = 0;
|
|
56
|
+
while (i < normalized.length) {
|
|
57
|
+
const char = normalized[i];
|
|
58
|
+
if (char === '*') {
|
|
59
|
+
const next = normalized[i + 1];
|
|
60
|
+
if (next === '*') {
|
|
61
|
+
regex += '.*';
|
|
62
|
+
i += 2;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
regex += '[^/]*';
|
|
66
|
+
i += 1;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (char === '?') {
|
|
70
|
+
regex += '[^/]';
|
|
71
|
+
i += 1;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if ('\\.[]{}()+-^$|'.includes(char)) {
|
|
75
|
+
regex += `\\${char}`;
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
regex += char;
|
|
79
|
+
}
|
|
80
|
+
i += 1;
|
|
81
|
+
}
|
|
82
|
+
regex += '$';
|
|
83
|
+
return new RegExp(regex);
|
|
84
|
+
}
|
|
85
|
+
function matchGlob(pathValue, pattern) {
|
|
86
|
+
const normalizedPath = normalizePath(pathValue);
|
|
87
|
+
const normalizedPattern = normalizePath(pattern);
|
|
88
|
+
if (!hasGlobChars(normalizedPattern)) {
|
|
89
|
+
if (normalizedPattern.endsWith('/')) {
|
|
90
|
+
return normalizedPath.startsWith(normalizedPattern);
|
|
91
|
+
}
|
|
92
|
+
return normalizedPath === normalizedPattern || normalizedPath.startsWith(`${normalizedPattern}/`);
|
|
93
|
+
}
|
|
94
|
+
const regex = globToRegExp(normalizedPattern);
|
|
95
|
+
return regex.test(normalizedPath);
|
|
96
|
+
}
|
|
97
|
+
function safeReadTextFile(path) {
|
|
98
|
+
try {
|
|
99
|
+
const stats = (0, fs_1.statSync)(path);
|
|
100
|
+
if (stats.size > MAX_READ_BYTES) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
return (0, fs_1.readFileSync)(path, 'utf-8');
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function normalizePath(pathValue) {
|
|
110
|
+
return pathValue.split('\\').join('/');
|
|
111
|
+
}
|
|
112
|
+
function toRelativePosix(root, filePath) {
|
|
113
|
+
const relative = path_1.posix.relative(normalizePath(root), normalizePath(filePath));
|
|
114
|
+
return relative.startsWith('../') ? normalizePath(filePath) : relative;
|
|
115
|
+
}
|
|
116
|
+
function isPathWithinRoot(root, target) {
|
|
117
|
+
const rootAbs = (0, path_1.resolve)(root);
|
|
118
|
+
const targetAbs = (0, path_1.resolve)(target);
|
|
119
|
+
const rel = (0, path_1.relative)(rootAbs, targetAbs);
|
|
120
|
+
return rel === '' || (!rel.startsWith('..') && !rel.includes(`..${path_1.posix.sep}`) && !rel.includes('..\\'));
|
|
121
|
+
}
|
|
122
|
+
function fileExtension(pathValue) {
|
|
123
|
+
return (0, path_1.extname)(pathValue).replace('.', '').toLowerCase();
|
|
124
|
+
}
|
|
125
|
+
function baseNameWithoutExt(pathValue) {
|
|
126
|
+
const base = (0, path_1.basename)(pathValue);
|
|
127
|
+
const ext = (0, path_1.extname)(base);
|
|
128
|
+
return ext ? base.slice(0, -ext.length) : base;
|
|
129
|
+
}
|
|
130
|
+
function splitCamelCase(value) {
|
|
131
|
+
return value.replace(/([a-z])([A-Z])/g, '$1 $2');
|
|
132
|
+
}
|
|
133
|
+
function tokenize(value) {
|
|
134
|
+
const normalized = splitCamelCase(value)
|
|
135
|
+
.replace(/[_\-.]/g, ' ')
|
|
136
|
+
.replace(/[^a-zA-Z0-9\s]/g, ' ')
|
|
137
|
+
.toLowerCase();
|
|
138
|
+
return normalized
|
|
139
|
+
.split(/\s+/)
|
|
140
|
+
.map((token) => token.trim())
|
|
141
|
+
.filter((token) => token.length > 2 && !STOP_WORDS.has(token));
|
|
142
|
+
}
|
|
143
|
+
function uniqueTokens(tokens) {
|
|
144
|
+
return Array.from(new Set(tokens.filter(Boolean)));
|
|
145
|
+
}
|
|
146
|
+
function titleCase(value) {
|
|
147
|
+
return value
|
|
148
|
+
.split(/[\s_-]+/)
|
|
149
|
+
.filter(Boolean)
|
|
150
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
151
|
+
.join(' ');
|
|
152
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 3: Selector Enforcement
|
|
3
|
+
* Validates selectors against whitelist and comments out invalid ones
|
|
4
|
+
*/
|
|
5
|
+
export interface ValidationResult {
|
|
6
|
+
isValid: boolean;
|
|
7
|
+
confidence: number;
|
|
8
|
+
reason?: string;
|
|
9
|
+
suggestedComment?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ValidatedSelector {
|
|
12
|
+
selector: string;
|
|
13
|
+
isWhitelisted: boolean;
|
|
14
|
+
confidence: number;
|
|
15
|
+
originalCode: string;
|
|
16
|
+
validatedCode: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* SelectorValidator: Enforces whitelist matching on generated selectors
|
|
20
|
+
* Comments out unobserved selectors instead of letting tests fail randomly
|
|
21
|
+
*/
|
|
22
|
+
export declare class SelectorValidator {
|
|
23
|
+
private whitelist;
|
|
24
|
+
private semanticWhitelist;
|
|
25
|
+
private minConfidence;
|
|
26
|
+
constructor(globalSelectors: {
|
|
27
|
+
[semantic: string]: Array<{
|
|
28
|
+
selector: string;
|
|
29
|
+
confidence: number;
|
|
30
|
+
}>;
|
|
31
|
+
}, minConfidence?: number);
|
|
32
|
+
/**
|
|
33
|
+
* Validate a selector against the whitelist
|
|
34
|
+
*/
|
|
35
|
+
validateSelector(selector: string): ValidationResult;
|
|
36
|
+
/**
|
|
37
|
+
* Validate and comment out invalid selectors in generated test code
|
|
38
|
+
*/
|
|
39
|
+
validateTestCode(code: string): ValidatedSelector[];
|
|
40
|
+
/**
|
|
41
|
+
* Apply validation to test code, commenting out unwhitelisted selectors
|
|
42
|
+
*/
|
|
43
|
+
applyValidation(code: string): string;
|
|
44
|
+
/**
|
|
45
|
+
* Get validation summary
|
|
46
|
+
*/
|
|
47
|
+
getSummary(code: string): {
|
|
48
|
+
total: number;
|
|
49
|
+
whitelisted: number;
|
|
50
|
+
coverage: number;
|
|
51
|
+
unobserved: string[];
|
|
52
|
+
};
|
|
53
|
+
private normalizeSelector;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* APIFallbackResolver: Provides fallback strategies when UI selectors fail
|
|
57
|
+
* Converts test methods to API calls when UI elements aren't available
|
|
58
|
+
*/
|
|
59
|
+
export declare class APIFallbackResolver {
|
|
60
|
+
private apiMapping;
|
|
61
|
+
/**
|
|
62
|
+
* Check if a test should fall back to API testing
|
|
63
|
+
*/
|
|
64
|
+
shouldFallback(selector: string, confidence: number): boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Generate API-based fallback for unobserved selector
|
|
67
|
+
*/
|
|
68
|
+
generateAPIFallback(selector: string, action: string): string;
|
|
69
|
+
/**
|
|
70
|
+
* Wrap unobserved test in try-catch with API fallback
|
|
71
|
+
*/
|
|
72
|
+
wrapWithFallback(testCode: string): string;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=selector-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selector-validator.d.ts","sourceRoot":"","sources":["../../../src/agent/validators/selector-validator.ts"],"names":[],"mappings":"AAGA;;;GAGG;AAEH,MAAM,WAAW,gBAAgB;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,qBAAa,iBAAiB;IAC1B,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,iBAAiB,CAAoC;IAC7D,OAAO,CAAC,aAAa,CAAS;gBAG1B,eAAe,EAAE;QAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAA;SAAC,CAAC,CAAA;KAAC,EACpF,aAAa,GAAE,MAAW;IAkB9B;;OAEG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB;IA6BpD;;OAEG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,EAAE;IAuBnD;;OAEG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAcrC;;OAEG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG;QACtB,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,EAAE,CAAC;KACxB;IAeD,OAAO,CAAC,iBAAiB;CAI5B;AAED;;;GAGG;AACH,qBAAa,mBAAmB;IAC5B,OAAO,CAAC,UAAU,CAOf;IAEH;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO;IAI7D;;OAEG;IACH,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IAmB7D;;OAEG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;CAS7C"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
3
|
+
// See LICENSE.txt for license information.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.APIFallbackResolver = exports.SelectorValidator = void 0;
|
|
6
|
+
/**
|
|
7
|
+
* SelectorValidator: Enforces whitelist matching on generated selectors
|
|
8
|
+
* Comments out unobserved selectors instead of letting tests fail randomly
|
|
9
|
+
*/
|
|
10
|
+
class SelectorValidator {
|
|
11
|
+
constructor(globalSelectors, minConfidence = 50) {
|
|
12
|
+
this.whitelist = new Set();
|
|
13
|
+
this.semanticWhitelist = new Map();
|
|
14
|
+
this.minConfidence = minConfidence;
|
|
15
|
+
// Build flat whitelist from semantic map
|
|
16
|
+
for (const [semantic, elements] of Object.entries(globalSelectors)) {
|
|
17
|
+
for (const elem of elements) {
|
|
18
|
+
if (elem.confidence >= minConfidence) {
|
|
19
|
+
this.whitelist.add(elem.selector);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
this.semanticWhitelist.set(semantic, elements.map((e) => e.selector));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Validate a selector against the whitelist
|
|
27
|
+
*/
|
|
28
|
+
validateSelector(selector) {
|
|
29
|
+
if (this.whitelist.has(selector)) {
|
|
30
|
+
return {
|
|
31
|
+
isValid: true,
|
|
32
|
+
confidence: 100,
|
|
33
|
+
reason: 'Found in whitelist',
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
// Check for similar selectors (lenient matching)
|
|
37
|
+
const normalized = this.normalizeSelector(selector);
|
|
38
|
+
for (const whitelisted of this.whitelist) {
|
|
39
|
+
if (this.normalizeSelector(whitelisted).includes(normalized)) {
|
|
40
|
+
return {
|
|
41
|
+
isValid: true,
|
|
42
|
+
confidence: 75,
|
|
43
|
+
reason: 'Found similar whitelisted selector',
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
isValid: false,
|
|
49
|
+
confidence: 0,
|
|
50
|
+
reason: 'Not found in whitelist',
|
|
51
|
+
suggestedComment: `// UNOBSERVED SELECTOR - Not found in UI map. Use test.fixme() if needed.`,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Validate and comment out invalid selectors in generated test code
|
|
56
|
+
*/
|
|
57
|
+
validateTestCode(code) {
|
|
58
|
+
const results = [];
|
|
59
|
+
const selectorRegex = /page\.(getByTestId|getByLabel|getByRole|locator)\(['"`]([^'"`]+)['"`]\)/g;
|
|
60
|
+
let match;
|
|
61
|
+
while ((match = selectorRegex.exec(code)) !== null) {
|
|
62
|
+
const [fullMatch, , selector] = match;
|
|
63
|
+
const validation = this.validateSelector(selector);
|
|
64
|
+
results.push({
|
|
65
|
+
selector,
|
|
66
|
+
isWhitelisted: validation.isValid,
|
|
67
|
+
confidence: validation.confidence,
|
|
68
|
+
originalCode: fullMatch,
|
|
69
|
+
validatedCode: validation.isValid
|
|
70
|
+
? fullMatch
|
|
71
|
+
: `// ${validation.suggestedComment}\n // ${fullMatch}`,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return results;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Apply validation to test code, commenting out unwhitelisted selectors
|
|
78
|
+
*/
|
|
79
|
+
applyValidation(code) {
|
|
80
|
+
let validated = code;
|
|
81
|
+
const results = this.validateTestCode(code);
|
|
82
|
+
// Apply in reverse order to preserve indices
|
|
83
|
+
for (const result of results.reverse()) {
|
|
84
|
+
if (!result.isWhitelisted) {
|
|
85
|
+
validated = validated.replace(result.originalCode, result.validatedCode);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return validated;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Get validation summary
|
|
92
|
+
*/
|
|
93
|
+
getSummary(code) {
|
|
94
|
+
const results = this.validateTestCode(code);
|
|
95
|
+
const unobserved = results.filter((r) => !r.isWhitelisted).map((r) => r.selector);
|
|
96
|
+
return {
|
|
97
|
+
total: results.length,
|
|
98
|
+
whitelisted: results.filter((r) => r.isWhitelisted).length,
|
|
99
|
+
coverage: results.length > 0
|
|
100
|
+
? Math.round((results.filter((r) => r.isWhitelisted).length / results.length) * 100)
|
|
101
|
+
: 100,
|
|
102
|
+
unobserved,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
normalizeSelector(selector) {
|
|
106
|
+
// Normalize selector for lenient matching
|
|
107
|
+
return selector.toLowerCase().replace(/[^a-z0-9-_]/g, '');
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
exports.SelectorValidator = SelectorValidator;
|
|
111
|
+
/**
|
|
112
|
+
* APIFallbackResolver: Provides fallback strategies when UI selectors fail
|
|
113
|
+
* Converts test methods to API calls when UI elements aren't available
|
|
114
|
+
*/
|
|
115
|
+
class APIFallbackResolver {
|
|
116
|
+
constructor() {
|
|
117
|
+
this.apiMapping = new Map([
|
|
118
|
+
// UI action -> API endpoint mapping
|
|
119
|
+
['click.*button.*submit', 'POST /api/v4/posts'],
|
|
120
|
+
['fill.*search', 'GET /api/v4/users'],
|
|
121
|
+
['click.*profile', 'GET /api/v4/users/me'],
|
|
122
|
+
['navigate.*channel', 'GET /api/v4/channels'],
|
|
123
|
+
['click.*settings', 'PATCH /api/v4/users/me'],
|
|
124
|
+
]);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Check if a test should fall back to API testing
|
|
128
|
+
*/
|
|
129
|
+
shouldFallback(selector, confidence) {
|
|
130
|
+
return confidence < 50;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Generate API-based fallback for unobserved selector
|
|
134
|
+
*/
|
|
135
|
+
generateAPIFallback(selector, action) {
|
|
136
|
+
// Find matching API endpoint
|
|
137
|
+
let endpoint = 'GET /api/v4/';
|
|
138
|
+
for (const [pattern, api] of this.apiMapping) {
|
|
139
|
+
if (new RegExp(pattern, 'i').test(action)) {
|
|
140
|
+
endpoint = api;
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return `
|
|
145
|
+
// UI selector not found - falling back to API
|
|
146
|
+
const response = await fetch(\`\${baseUrl}${endpoint.split(' ')[1]}\`, {
|
|
147
|
+
method: '${endpoint.split(' ')[0]}',
|
|
148
|
+
headers: {'Authorization': \`Bearer \${token}\`},
|
|
149
|
+
});
|
|
150
|
+
expect(response.ok).toBe(true);`;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Wrap unobserved test in try-catch with API fallback
|
|
154
|
+
*/
|
|
155
|
+
wrapWithFallback(testCode) {
|
|
156
|
+
return `
|
|
157
|
+
try {
|
|
158
|
+
${testCode}
|
|
159
|
+
} catch (error) {
|
|
160
|
+
// UI element not found - using API fallback
|
|
161
|
+
${this.generateAPIFallback('unknown', testCode)}
|
|
162
|
+
}`;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
exports.APIFallbackResolver = APIFallbackResolver;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { AnthropicConfig, GenerateOptions, ImageInput, LLMResponse, ProviderCapabilities } from './provider_interface.js';
|
|
2
|
+
import { BaseProvider } from './base_provider.js';
|
|
3
|
+
/**
|
|
4
|
+
* Anthropic Provider - Claude AI models
|
|
5
|
+
*
|
|
6
|
+
* Features:
|
|
7
|
+
* - Highest quality AI (98% accuracy in testing)
|
|
8
|
+
* - Vision support (analyze screenshots, compare UI)
|
|
9
|
+
* - Fast response times (<1 second)
|
|
10
|
+
* - 200K token context window
|
|
11
|
+
* - Prompt caching (reduces costs by 90% on repeated prompts)
|
|
12
|
+
*
|
|
13
|
+
* Costs (Claude Sonnet 4.5):
|
|
14
|
+
* - Input: $3 per 1M tokens
|
|
15
|
+
* - Output: $15 per 1M tokens
|
|
16
|
+
* - Cached input: $0.30 per 1M tokens
|
|
17
|
+
* - Estimated: ~$30-80/month for autonomous testing
|
|
18
|
+
*
|
|
19
|
+
* Use cases:
|
|
20
|
+
* - Vision tasks (screenshot comparison)
|
|
21
|
+
* - Complex failure diagnosis
|
|
22
|
+
* - High-stakes production testing
|
|
23
|
+
* - When quality is paramount
|
|
24
|
+
*
|
|
25
|
+
* Models:
|
|
26
|
+
* - claude-sonnet-4-5-20250929 (recommended - best balance)
|
|
27
|
+
* - claude-opus-4-5-20251101 (highest quality, slower, more expensive)
|
|
28
|
+
* - claude-haiku-4-0-20250430 (fastest, cheapest, lower quality)
|
|
29
|
+
*/
|
|
30
|
+
export declare class AnthropicProvider extends BaseProvider {
|
|
31
|
+
name: string;
|
|
32
|
+
private client;
|
|
33
|
+
private model;
|
|
34
|
+
capabilities: ProviderCapabilities;
|
|
35
|
+
constructor(config: AnthropicConfig);
|
|
36
|
+
generateText(prompt: string, options?: GenerateOptions): Promise<LLMResponse>;
|
|
37
|
+
analyzeImage(images: ImageInput[], prompt: string, options?: GenerateOptions): Promise<LLMResponse>;
|
|
38
|
+
streamText(prompt: string, options?: GenerateOptions): AsyncGenerator<string, void, unknown>;
|
|
39
|
+
private extractTextFromResponse;
|
|
40
|
+
/**
|
|
41
|
+
* SECURITY: Type-safe usage extraction
|
|
42
|
+
* Avoids unsafe `as any` casts
|
|
43
|
+
*/
|
|
44
|
+
private extractUsageFromResponse;
|
|
45
|
+
/**
|
|
46
|
+
* SECURITY: Extract status code safely
|
|
47
|
+
*/
|
|
48
|
+
private extractStatusCode;
|
|
49
|
+
/**
|
|
50
|
+
* Check if API key is valid and service is accessible
|
|
51
|
+
*/
|
|
52
|
+
checkHealth(): Promise<{
|
|
53
|
+
healthy: boolean;
|
|
54
|
+
message: string;
|
|
55
|
+
}>;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Helper to check Anthropic setup
|
|
59
|
+
*/
|
|
60
|
+
export declare function checkAnthropicSetup(apiKey: string): Promise<{
|
|
61
|
+
valid: boolean;
|
|
62
|
+
message: string;
|
|
63
|
+
estimatedMonthlyCost: string;
|
|
64
|
+
}>;
|
|
65
|
+
//# sourceMappingURL=anthropic_provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic_provider.d.ts","sourceRoot":"","sources":["../src/anthropic_provider.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACR,eAAe,EACf,eAAe,EACf,UAAU,EACV,WAAW,EACX,oBAAoB,EACvB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAC,YAAY,EAAC,MAAM,oBAAoB,CAAC;AAehD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,iBAAkB,SAAQ,YAAY;IAC/C,IAAI,SAAe;IACnB,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,KAAK,CAAS;IAEtB,YAAY,EAAE,oBAAoB,CAShC;gBAEU,MAAM,EAAE,eAAe;IA2B7B,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC;IA4D7E,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC;IAgHlG,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC;IA4CnG,OAAO,CAAC,uBAAuB;IAU/B;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IAchC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAWzB;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAC,CAAC;CAyBpE;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IAC/D,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,oBAAoB,EAAE,MAAM,CAAC;CAChC,CAAC,CAyBD"}
|