@taodigital/agents 0.0.0-stage → 1.2.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/README.md +99 -2
- package/dist/api-test-agent.d.ts +126 -0
- package/dist/api-test-agent.js +267 -0
- package/dist/artifact-intel-agent.d.ts +11 -0
- package/dist/artifact-intel-agent.js +152 -0
- package/dist/coverage-gap-agent.d.ts +25 -0
- package/dist/coverage-gap-agent.js +269 -0
- package/dist/coverage-map-agent.d.ts +15 -0
- package/dist/coverage-map-agent.js +255 -0
- package/dist/crawl-diff-agent.d.ts +27 -0
- package/dist/crawl-diff-agent.js +412 -0
- package/dist/data-agent.d.ts +101 -0
- package/dist/data-agent.js +2284 -0
- package/dist/document-agent.d.ts +10 -0
- package/dist/document-agent.js +32 -0
- package/dist/enhancement-agent.d.ts +48 -0
- package/dist/enhancement-agent.js +342 -0
- package/dist/field-detector-agent.d.ts +35 -0
- package/dist/field-detector-agent.js +220 -0
- package/dist/flow-agent.d.ts +130 -0
- package/dist/flow-agent.js +169 -0
- package/dist/github-agent.d.ts +18 -0
- package/dist/github-agent.js +39 -0
- package/dist/github-write-agent.d.ts +67 -0
- package/dist/github-write-agent.js +249 -0
- package/dist/grouping-agent.d.ts +18 -0
- package/dist/grouping-agent.js +338 -0
- package/dist/healing-agent.d.ts +73 -0
- package/dist/healing-agent.js +137 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +67 -0
- package/dist/integration-test-agent.d.ts +118 -0
- package/dist/integration-test-agent.js +165 -0
- package/dist/label-assignment-agent.d.ts +15 -0
- package/dist/label-assignment-agent.js +97 -0
- package/dist/llm-config.d.ts +38 -0
- package/dist/llm-config.js +287 -0
- package/dist/llm-mock.d.ts +77 -0
- package/dist/llm-mock.js +192 -0
- package/dist/llm.d.ts +58 -0
- package/dist/llm.js +438 -0
- package/dist/nlp-agent.d.ts +208 -0
- package/dist/nlp-agent.js +340 -0
- package/dist/orchestrator.d.ts +285 -0
- package/dist/orchestrator.js +141 -0
- package/dist/plan-agent.d.ts +4 -0
- package/dist/plan-agent.js +200 -0
- package/dist/repo-scan-agent.d.ts +189 -0
- package/dist/repo-scan-agent.js +2032 -0
- package/dist/requirements-agent.d.ts +59 -0
- package/dist/requirements-agent.js +641 -0
- package/dist/scenario-agent.d.ts +20 -0
- package/dist/scenario-agent.js +123 -0
- package/dist/script-agent.d.ts +447 -0
- package/dist/script-agent.js +11813 -0
- package/dist/security-test-agent.d.ts +111 -0
- package/dist/security-test-agent.js +141 -0
- package/dist/skill-file-agent.d.ts +264 -0
- package/dist/skill-file-agent.js +3470 -0
- package/dist/step-coverage.d.ts +46 -0
- package/dist/step-coverage.js +288 -0
- package/dist/step-utils.d.ts +2 -0
- package/dist/step-utils.js +62 -0
- package/dist/test-case-agent.d.ts +206 -0
- package/dist/test-case-agent.js +2141 -0
- package/dist/test-import-agent.d.ts +148 -0
- package/dist/test-import-agent.js +3235 -0
- package/dist/test-script-agent.d.ts +16 -0
- package/dist/test-script-agent.js +48 -0
- package/dist/token-pricing.d.ts +14 -0
- package/dist/token-pricing.js +62 -0
- package/dist/types.d.ts +232 -0
- package/dist/types.js +7 -0
- package/dist/visual-agent.d.ts +114 -0
- package/dist/visual-agent.js +261 -0
- package/package.json +26 -4
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateScenarios = generateScenarios;
|
|
4
|
+
const app_brain_1 = require("@taodigital/app-brain");
|
|
5
|
+
const llm_js_1 = require("./llm.js");
|
|
6
|
+
const llm_config_js_1 = require("./llm-config.js");
|
|
7
|
+
const core_1 = require("@taodigital/core");
|
|
8
|
+
const SYSTEM = `You are a senior BDD practitioner converting software requirements into precise Gherkin scenarios.
|
|
9
|
+
|
|
10
|
+
Rules:
|
|
11
|
+
- Generate EXACTLY the requested number of scenarios per requirement tailored to the requirement TYPE:
|
|
12
|
+
- functional/nonfunctional: happy path, validation errors, edge cases, integration
|
|
13
|
+
- security: authentication, authorization, injection attacks, data exposure
|
|
14
|
+
- accessibility: screen reader, keyboard nav, color contrast, ARIA labels
|
|
15
|
+
- performance: load time, concurrent users, large data sets, timeouts
|
|
16
|
+
- data: data integrity, boundary values, null handling, format validation
|
|
17
|
+
- Tag scenarios appropriately: @negative, @edge, @security, @accessibility, @performance, @nonfunctional
|
|
18
|
+
- Each scenario MUST use proper Given/When/Then/And/But structure
|
|
19
|
+
- Given: pre-conditions and context (what is already true)
|
|
20
|
+
- When: a single user action or system event
|
|
21
|
+
- Then: observable, verifiable outcome — use exact text, not "it works"
|
|
22
|
+
- And/But: continue Given/When/Then (not standalone)
|
|
23
|
+
- Titles: imperative, specific — "User submits form with invalid email" not "Test login"
|
|
24
|
+
- No emojis, pronouns, or vague assertions
|
|
25
|
+
- Each scenario must trace directly to the provided requirement title, acceptance criteria, business rules, or project context. Do not introduce unrelated features.
|
|
26
|
+
- CRITICAL — use specific values from Business Rules directly in Given/And/Then steps. Never paraphrase or generalise constraints. Examples:
|
|
27
|
+
- If a rule says "VIN: 17 alphanumeric chars excluding O, I, U, Q, 0, 1, 9", write 'And the VIN field contains "1HGBH41JXMN109186"' (valid) or 'And the VIN field contains "1HGBH41JXMN10918O"' (invalid — contains excluded letter O), NOT 'And an invalid VIN is entered'.
|
|
28
|
+
- If a rule says "Password: 3-8 characters", write 'And the password field contains "ab"' (too short) or 'And the password field contains "abc123xy9"' (too long — 9 chars), NOT 'And an invalid password is entered'.
|
|
29
|
+
- Quote exact values, lengths, character sets, and boundary numbers in the step text.
|
|
30
|
+
|
|
31
|
+
Return ONLY valid JSON:
|
|
32
|
+
{
|
|
33
|
+
"scenarios": [
|
|
34
|
+
{
|
|
35
|
+
"title": "string",
|
|
36
|
+
"description": "string (optional — brief context note)",
|
|
37
|
+
"gherkin": "Scenario: Title\\n Given ...\\n When ...\\n Then ..."
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}`;
|
|
41
|
+
async function generateScenarios(opts) {
|
|
42
|
+
const llmCfg = await (0, llm_config_js_1.getTaskAgentLLMConfig)(opts.tenantId, 'testGeneration');
|
|
43
|
+
if (!llmCfg)
|
|
44
|
+
return [];
|
|
45
|
+
const { reqId, title, actor, acceptanceCriteria, businessRules } = opts.requirement;
|
|
46
|
+
// ZETA-085: honour the caller-supplied count so exactly N scenarios are generated.
|
|
47
|
+
const requestedCount = Math.max(1, Math.min(10, Math.floor(opts.count ?? 4)));
|
|
48
|
+
// Load project context in parallel: workspace domain + skill files + artifact search
|
|
49
|
+
const knowledgeQuery = [title, acceptanceCriteria?.[0]].filter(Boolean).join(' ');
|
|
50
|
+
const [domainCtx, skillFiles, knowledgeChunks] = await Promise.all([
|
|
51
|
+
(0, llm_config_js_1.getWorkspaceDomainContext)(opts.tenantId, opts.projectId),
|
|
52
|
+
app_brain_1.AppBrain.listSkillFiles(opts.tenantId, opts.projectId, [
|
|
53
|
+
'BUSINESS_DOMAIN', 'API_CONTRACT', 'ERROR_CATALOGUE', 'INTERACTION_PATTERNS',
|
|
54
|
+
]).catch(() => []),
|
|
55
|
+
app_brain_1.AppBrain.searchKnowledge(opts.tenantId, opts.projectId, knowledgeQuery, 5).catch(() => []),
|
|
56
|
+
]);
|
|
57
|
+
// Build optional project context block from skill files + artifact chunks
|
|
58
|
+
const projectCtxParts = [];
|
|
59
|
+
for (const sf of skillFiles) {
|
|
60
|
+
if (sf?.content?.trim()) {
|
|
61
|
+
projectCtxParts.push(`## ${sf.kind}\n${sf.content.trim()}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
for (const chunk of knowledgeChunks) {
|
|
65
|
+
if (chunk?.content?.trim() && chunk.source !== 'SKILL_FILE') {
|
|
66
|
+
projectCtxParts.push(`## Artifact: ${chunk.label ?? 'context'}\n${chunk.content.trim()}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const projectCtx = projectCtxParts.length
|
|
70
|
+
? `PROJECT CONTEXT (use to write accurate, specific scenarios):\n\n${projectCtxParts.join('\n\n')}`
|
|
71
|
+
: '';
|
|
72
|
+
const { type, priority } = opts.requirement;
|
|
73
|
+
const userPrompt = [
|
|
74
|
+
domainCtx,
|
|
75
|
+
projectCtx,
|
|
76
|
+
`Requirement: ${reqId} — ${title}`,
|
|
77
|
+
actor ? `Actor: ${actor}` : '',
|
|
78
|
+
type ? `Type: ${type} — focus scenarios on ${type} concerns` : '',
|
|
79
|
+
priority ? `Priority: ${priority}` : '',
|
|
80
|
+
acceptanceCriteria?.length
|
|
81
|
+
? `Acceptance Criteria:\n${acceptanceCriteria.map((c) => `- ${c}`).join('\n')}`
|
|
82
|
+
: '',
|
|
83
|
+
businessRules?.length
|
|
84
|
+
? `Business Rules (embed the exact values, lengths, and character constraints from these rules directly in the scenario steps — do not paraphrase):\n${businessRules.map((r) => `- ${r}`).join('\n')}`
|
|
85
|
+
: '',
|
|
86
|
+
'',
|
|
87
|
+
`Generate exactly ${requestedCount} Gherkin scenarios for this requirement. Use @tags appropriate to the type: ${type ?? 'functional'}.`,
|
|
88
|
+
].filter(Boolean).join('\n');
|
|
89
|
+
try {
|
|
90
|
+
// ZETA-086: use temperature=0 + deterministic seed so repeated calls for the same
|
|
91
|
+
// requirement produce consistent scenarios.
|
|
92
|
+
const seed = (0, llm_js_1.deterministicSeed)(`${opts.tenantId}:${reqId}:${title}:${requestedCount}`);
|
|
93
|
+
const effectiveSystem = await (0, core_1.getAgentPrompt)('scenario-bdd', undefined, opts.tenantId) ?? SYSTEM;
|
|
94
|
+
const { text } = await (0, llm_js_1.askTracked)(effectiveSystem, userPrompt, llmCfg, 4096, undefined, { temperature: 0, seed });
|
|
95
|
+
const json = text.match(/\{[\s\S]*\}/)?.[0];
|
|
96
|
+
if (!json)
|
|
97
|
+
return [];
|
|
98
|
+
const parsed = JSON.parse(json);
|
|
99
|
+
const scenarios = (parsed.scenarios ?? []).filter((s) => s.title && s.gherkin).slice(0, requestedCount);
|
|
100
|
+
// ZETA-085: pad with deterministic fallback scenarios if the LLM returned fewer than requested.
|
|
101
|
+
const acList = acceptanceCriteria?.length ? acceptanceCriteria : [title];
|
|
102
|
+
while (scenarios.length < requestedCount) {
|
|
103
|
+
const index = scenarios.length + 1;
|
|
104
|
+
const ac = acList[(index - 1) % acList.length] ?? title;
|
|
105
|
+
const scenarioTitle = `${title} - coverage path ${index}`;
|
|
106
|
+
scenarios.push({
|
|
107
|
+
title: scenarioTitle,
|
|
108
|
+
description: `Deterministic supplemental scenario for ${reqId}.`,
|
|
109
|
+
gherkin: [
|
|
110
|
+
`Scenario: ${scenarioTitle}`,
|
|
111
|
+
actor ? ` Given ${actor} is using the application` : ' Given the application is available',
|
|
112
|
+
` And requirement ${reqId} is in scope`,
|
|
113
|
+
` When the behavior "${title}" is exercised for "${ac}"`,
|
|
114
|
+
` Then the observable result satisfies requirement ${reqId}`,
|
|
115
|
+
].join('\n'),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return scenarios;
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return [];
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ZeTa-AI Test Script Generation Agent — v2 (ZeTa Framework Standard v1)
|
|
3
|
+
*
|
|
4
|
+
* Architecture: deterministic scaffolding layer + model-filled body layer.
|
|
5
|
+
*
|
|
6
|
+
* The LLM fills four slots per script:
|
|
7
|
+
* locatorsBody — locator constants/selectors (no class wrapper)
|
|
8
|
+
* pageObjectBody — action methods (no class wrapper)
|
|
9
|
+
* testDataBody — VALID/INVALID/EDGE data constants
|
|
10
|
+
* specBody — test functions / step defs (no describe/class wrapper)
|
|
11
|
+
*
|
|
12
|
+
* Everything else (imports, BasePage, class declaration, describe, beforeEach,
|
|
13
|
+
* tags, TC-ref title format, JUnit reporter) is a fixed template per stack.
|
|
14
|
+
*
|
|
15
|
+
* Locator priority (§2.4): data-testid > role+name > label/aria-label > exact text > placeholder > CSS.
|
|
16
|
+
* Forbidden patterns (§5.2): sleep(), Thread.sleep(), cy.wait(number), positional XPath, inlined credentials.
|
|
17
|
+
*
|
|
18
|
+
* Supported stacks: playwright-ts · playwright-js · playwright-py · playwright-java
|
|
19
|
+
* cypress-ts · cypress-js · selenium-py · selenium-java · gherkin
|
|
20
|
+
*/
|
|
21
|
+
import { type StepCoverageResult } from './step-coverage.js';
|
|
22
|
+
export declare const SCRIPT_GEN_CONCURRENCY: number;
|
|
23
|
+
export declare const SCRIPT_GEN_MAX_TOKENS: number;
|
|
24
|
+
export type ScriptGenerationReadiness = {
|
|
25
|
+
ready: boolean;
|
|
26
|
+
missing: string[];
|
|
27
|
+
message: string;
|
|
28
|
+
details: {
|
|
29
|
+
caseCount: number;
|
|
30
|
+
screenCount: number;
|
|
31
|
+
targetType: 'API' | 'NATIVE' | 'WEB';
|
|
32
|
+
nativePlatforms: string[];
|
|
33
|
+
nativeBuildPlatforms: string[];
|
|
34
|
+
casesMissingApproval: string[];
|
|
35
|
+
casesMissingData: string[];
|
|
36
|
+
casesMissingScreen: string[];
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
export declare class ScriptGenerationBlockedError extends Error {
|
|
40
|
+
readonly code = "SCRIPT_CONTEXT_INCOMPLETE";
|
|
41
|
+
readonly statusCode = 422;
|
|
42
|
+
readonly readiness: ScriptGenerationReadiness;
|
|
43
|
+
constructor(readiness: ScriptGenerationReadiness);
|
|
44
|
+
}
|
|
45
|
+
export declare function evaluateScriptGenerationReadiness(input: {
|
|
46
|
+
appUrl?: string | null;
|
|
47
|
+
appType?: string | null;
|
|
48
|
+
nativeBuilds?: Array<{
|
|
49
|
+
platform?: string | null;
|
|
50
|
+
fileFormat?: string | null;
|
|
51
|
+
}>;
|
|
52
|
+
screens?: any[];
|
|
53
|
+
cases?: any[];
|
|
54
|
+
contextPhase?: string | null;
|
|
55
|
+
}): ScriptGenerationReadiness;
|
|
56
|
+
export declare function getScriptGenerationReadiness(opts: {
|
|
57
|
+
tenantId: string;
|
|
58
|
+
projectId: string;
|
|
59
|
+
testCaseId?: string;
|
|
60
|
+
suiteId?: string;
|
|
61
|
+
packType?: string;
|
|
62
|
+
caseIds?: string[];
|
|
63
|
+
}): Promise<ScriptGenerationReadiness>;
|
|
64
|
+
export declare function assertScriptGenerationReady(opts: Parameters<typeof getScriptGenerationReadiness>[0]): Promise<ScriptGenerationReadiness>;
|
|
65
|
+
export declare function mapWithConcurrency<T, R>(items: readonly T[], limit: number, mapper: (item: T, index: number) => Promise<R>): Promise<R[]>;
|
|
66
|
+
export declare const ZETA_BASE_PAGES: Record<string, string>;
|
|
67
|
+
export declare const ZETA_JAVA_V2_DRIVER_FACTORY = "// ZeTa Framework Standard v2 \u2014 DriverFactory (Selenium Java / TestNG)\npackage io.zeta.core;\n\nimport io.github.bonigarcia.wdm.WebDriverManager;\nimport org.openqa.selenium.WebDriver;\nimport org.openqa.selenium.chrome.ChromeDriver;\nimport org.openqa.selenium.chrome.ChromeOptions;\n\npublic final class DriverFactory {\n private static final ThreadLocal<WebDriver> DRIVER_THREAD_LOCAL = new ThreadLocal<>();\n private DriverFactory() {}\n\n /** Call from @BeforeMethod. Browser: -Dzeta.browser=chrome. Headless: -Dzeta.headless=true */\n public static void initDriver() {\n WebDriverManager.chromedriver().setup();\n ChromeOptions opts = new ChromeOptions();\n boolean headless = Boolean.parseBoolean(System.getProperty(\"zeta.headless\", \"true\"));\n if (headless) opts.addArguments(\"--headless=new\", \"--no-sandbox\", \"--disable-dev-shm-usage\");\n opts.addArguments(\"--window-size=1280,800\");\n DRIVER_THREAD_LOCAL.set(new ChromeDriver(opts));\n }\n\n /** Return the WebDriver for the current thread. */\n public static WebDriver getDriver() {\n WebDriver d = DRIVER_THREAD_LOCAL.get();\n if (d == null) throw new IllegalStateException(\"Call initDriver() in @BeforeMethod first.\");\n return d;\n }\n\n /** Call from @AfterMethod(alwaysRun = true). */\n public static void quitDriver() {\n WebDriver d = DRIVER_THREAD_LOCAL.get();\n if (d != null) { try { d.quit(); } finally { DRIVER_THREAD_LOCAL.remove(); } }\n }\n}";
|
|
68
|
+
interface LintResult {
|
|
69
|
+
ok: boolean;
|
|
70
|
+
violations: string[];
|
|
71
|
+
warnings?: string[];
|
|
72
|
+
}
|
|
73
|
+
export declare function lintScript(code: string, language?: string, expectedLocatorCount?: number): LintResult;
|
|
74
|
+
export declare function stepToPlaywrightLine(step: unknown, indent?: string): string;
|
|
75
|
+
/**
|
|
76
|
+
* Resolved file placement + import conventions for a specific repo + framework.
|
|
77
|
+
* Computed ONCE per suite generation job; shared across all test cases.
|
|
78
|
+
*/
|
|
79
|
+
export interface RepoGenerationContext {
|
|
80
|
+
/** Directory for spec/test files (trailing slash). e.g. "tests/" or "src/tests/" */
|
|
81
|
+
specDir: string;
|
|
82
|
+
/** Directory for page object files (trailing slash). e.g. "src/advantage/pages/" */
|
|
83
|
+
pageObjectDir: string;
|
|
84
|
+
/** Directory for locator constants (trailing slash) or null if collocated. */
|
|
85
|
+
locatorsDir: string | null;
|
|
86
|
+
/** Directory for test data files (trailing slash) or null if collocated. */
|
|
87
|
+
testDataDir: string | null;
|
|
88
|
+
/**
|
|
89
|
+
* Import path FROM page object file TO base page class.
|
|
90
|
+
* TS/JS: relative file path e.g. "./base.page" or "../../framework/BasePage".
|
|
91
|
+
* Python: module path e.g. "pages.base_page" or "src.framework.base_page".
|
|
92
|
+
*/
|
|
93
|
+
basePageImport: string;
|
|
94
|
+
/**
|
|
95
|
+
* Relative path FROM specDir directory TO pageObjectDir directory.
|
|
96
|
+
* Used to build spec → PO import. e.g. "../src/advantage/pages".
|
|
97
|
+
* Python: module prefix e.g. "pages" or "advantage.pages".
|
|
98
|
+
*/
|
|
99
|
+
poImportDir: string;
|
|
100
|
+
/** Page object class name suffix. e.g. "Page", "Steps", "Helper". */
|
|
101
|
+
poClassSuffix: string;
|
|
102
|
+
/** Spec file extension suffix. e.g. ".spec.ts", ".cy.ts", "_test.py". */
|
|
103
|
+
specFileSuffix: string;
|
|
104
|
+
/**
|
|
105
|
+
* File stem naming convention detected from the repo.
|
|
106
|
+
* 'pascal' = ServiceMessagingPage.ts (PascalCase, no separator)
|
|
107
|
+
* 'kebab' = service-messaging.page.ts (kebab-case, ZeTa default)
|
|
108
|
+
* 'snake' = service_messaging_test.py (snake_case, Python default)
|
|
109
|
+
*/
|
|
110
|
+
stemCase: 'pascal' | 'kebab' | 'snake';
|
|
111
|
+
/** Directory for fixture files (trailing slash). e.g. "tests/fixtures/". */
|
|
112
|
+
fixtureDir: string;
|
|
113
|
+
/** Test timeout in ms to inject via test.setTimeout(). Undefined = use framework default. */
|
|
114
|
+
defaultTimeoutMs?: number;
|
|
115
|
+
/** Base URL extracted from playwright.config.ts / cypress.config.ts — used as default appUrl fallback. */
|
|
116
|
+
baseURL?: string;
|
|
117
|
+
/** Sample locator file content from the repo — injected into the prompt so the LLM follows the same naming + selector strategy (ZETA-253). */
|
|
118
|
+
sampleLocatorFileContent?: string;
|
|
119
|
+
}
|
|
120
|
+
export declare function generateZetaV2Bundle(opts: {
|
|
121
|
+
tenantId: string;
|
|
122
|
+
projectId: string;
|
|
123
|
+
testCaseId: string;
|
|
124
|
+
appSlug?: string;
|
|
125
|
+
repoSkillContext?: string;
|
|
126
|
+
/** Java base package (e.g. "com.crm.qa") derived from repo scan. Overrides io.zeta default. */
|
|
127
|
+
basePackage?: string;
|
|
128
|
+
/** Repo structure type: 'flat' | 'two-tier' | 'zeta-v2' | 'custom'. Non-zeta-v2 → 2-file output. */
|
|
129
|
+
testStructurePattern?: string;
|
|
130
|
+
/** Where page object classes live in the repo (e.g. "src/main/java/pages"). Non-zeta-v2 repos. */
|
|
131
|
+
pageObjectLocation?: string;
|
|
132
|
+
/** Where test classes live in the repo (e.g. "src/test/java/tests"). Non-zeta-v2 repos. */
|
|
133
|
+
testLocation?: string;
|
|
134
|
+
/** Repo base page class name or FQN (e.g. "BasePage" or "com.acme.core.BasePage"). */
|
|
135
|
+
basePageClass?: string;
|
|
136
|
+
/** Repo driver factory class name or FQN (e.g. "Browser" or "com.acme.core.DriverFactory"). */
|
|
137
|
+
driverClass?: string;
|
|
138
|
+
/** File naming pattern from repo scan (e.g. "{PascalCase}Helper.java") — used to derive PO class suffix. */
|
|
139
|
+
namingPattern?: string;
|
|
140
|
+
jobId?: string;
|
|
141
|
+
/** Pre-extracted Playwright locators from the live page — injected verbatim into the LLM prompt. */
|
|
142
|
+
extractedLocators?: Array<{
|
|
143
|
+
key: string;
|
|
144
|
+
expression: string;
|
|
145
|
+
description: string;
|
|
146
|
+
confidence: string;
|
|
147
|
+
}>;
|
|
148
|
+
}): Promise<{
|
|
149
|
+
files: Array<{
|
|
150
|
+
filename: string;
|
|
151
|
+
path: string;
|
|
152
|
+
code: string;
|
|
153
|
+
}>;
|
|
154
|
+
primaryCode: string;
|
|
155
|
+
}>;
|
|
156
|
+
/**
|
|
157
|
+
* Pre-execution dry-run: validates that test steps reference elements that exist
|
|
158
|
+
* in the crawled element inventory. Returns a list of flagged steps that may fail.
|
|
159
|
+
* Non-blocking — caller decides whether to proceed or surface warnings to the user.
|
|
160
|
+
*/
|
|
161
|
+
export declare function validateStepsAgainstInventory(opts: {
|
|
162
|
+
tenantId: string;
|
|
163
|
+
projectId: string;
|
|
164
|
+
steps: string[];
|
|
165
|
+
elementInventory?: Array<{
|
|
166
|
+
label: string;
|
|
167
|
+
role: string;
|
|
168
|
+
ariaLabel?: string;
|
|
169
|
+
cssSelector?: string;
|
|
170
|
+
selector?: string;
|
|
171
|
+
textContent?: string;
|
|
172
|
+
}>;
|
|
173
|
+
}): Promise<{
|
|
174
|
+
valid: boolean;
|
|
175
|
+
flaggedSteps: Array<{
|
|
176
|
+
step: string;
|
|
177
|
+
reason: string;
|
|
178
|
+
}>;
|
|
179
|
+
coverage: number;
|
|
180
|
+
unmatchedSteps: string[];
|
|
181
|
+
}>;
|
|
182
|
+
export declare function generateTestScript(opts: {
|
|
183
|
+
tenantId: string;
|
|
184
|
+
projectId: string;
|
|
185
|
+
testCaseId: string;
|
|
186
|
+
language?: string;
|
|
187
|
+
/** When true, derive and persist repoTargetPath on the test case for IDE push. */
|
|
188
|
+
useV2?: boolean;
|
|
189
|
+
jobId?: string;
|
|
190
|
+
/** Pre-extracted Playwright locators from the live page — injected verbatim into the LLM prompt. */
|
|
191
|
+
extractedLocators?: Array<{
|
|
192
|
+
key: string;
|
|
193
|
+
expression: string;
|
|
194
|
+
description: string;
|
|
195
|
+
confidence: string;
|
|
196
|
+
}>;
|
|
197
|
+
}): Promise<{
|
|
198
|
+
language: string;
|
|
199
|
+
code: string;
|
|
200
|
+
files: {
|
|
201
|
+
testCaseId: string;
|
|
202
|
+
filename: string;
|
|
203
|
+
path: string;
|
|
204
|
+
code: string;
|
|
205
|
+
}[];
|
|
206
|
+
saved: boolean;
|
|
207
|
+
lintViolations: never[];
|
|
208
|
+
lintWarnings?: undefined;
|
|
209
|
+
dryRunWarnings?: undefined;
|
|
210
|
+
alignmentScore?: undefined;
|
|
211
|
+
aligned?: undefined;
|
|
212
|
+
alignmentIssues?: undefined;
|
|
213
|
+
stepCoverage?: undefined;
|
|
214
|
+
} | {
|
|
215
|
+
language: string;
|
|
216
|
+
code: string;
|
|
217
|
+
files: {
|
|
218
|
+
filename: string;
|
|
219
|
+
code: string;
|
|
220
|
+
path: string;
|
|
221
|
+
testCaseId: string;
|
|
222
|
+
role: string;
|
|
223
|
+
}[];
|
|
224
|
+
saved: {
|
|
225
|
+
tenantId: string;
|
|
226
|
+
id: string;
|
|
227
|
+
projectId: string;
|
|
228
|
+
validationStatus: string;
|
|
229
|
+
testCaseId: string;
|
|
230
|
+
language: string;
|
|
231
|
+
code: string;
|
|
232
|
+
filePath: string | null;
|
|
233
|
+
codeKey: string | null;
|
|
234
|
+
validationErrors: string | null;
|
|
235
|
+
pushedToPR: boolean;
|
|
236
|
+
pushedPRId: string | null;
|
|
237
|
+
};
|
|
238
|
+
lintViolations: string[];
|
|
239
|
+
lintWarnings: string[];
|
|
240
|
+
dryRunWarnings: {
|
|
241
|
+
step: string;
|
|
242
|
+
reason: string;
|
|
243
|
+
}[];
|
|
244
|
+
alignmentScore: number;
|
|
245
|
+
aligned: boolean;
|
|
246
|
+
alignmentIssues: string[];
|
|
247
|
+
stepCoverage: StepCoverageResult;
|
|
248
|
+
} | {
|
|
249
|
+
language: string;
|
|
250
|
+
code: string;
|
|
251
|
+
files: {
|
|
252
|
+
filename: string;
|
|
253
|
+
code: string;
|
|
254
|
+
path: string;
|
|
255
|
+
testCaseId: string;
|
|
256
|
+
role: string;
|
|
257
|
+
}[];
|
|
258
|
+
saved: {
|
|
259
|
+
tenantId: string;
|
|
260
|
+
id: string;
|
|
261
|
+
projectId: string;
|
|
262
|
+
validationStatus: string;
|
|
263
|
+
testCaseId: string;
|
|
264
|
+
language: string;
|
|
265
|
+
code: string;
|
|
266
|
+
filePath: string | null;
|
|
267
|
+
codeKey: string | null;
|
|
268
|
+
validationErrors: string | null;
|
|
269
|
+
pushedToPR: boolean;
|
|
270
|
+
pushedPRId: string | null;
|
|
271
|
+
};
|
|
272
|
+
lintViolations: string[];
|
|
273
|
+
lintWarnings: string[];
|
|
274
|
+
dryRunWarnings: {
|
|
275
|
+
step: string;
|
|
276
|
+
reason: string;
|
|
277
|
+
}[];
|
|
278
|
+
alignmentScore?: undefined;
|
|
279
|
+
aligned?: undefined;
|
|
280
|
+
alignmentIssues?: undefined;
|
|
281
|
+
stepCoverage?: undefined;
|
|
282
|
+
}>;
|
|
283
|
+
export declare function generateSuiteScript(opts: {
|
|
284
|
+
tenantId: string;
|
|
285
|
+
projectId: string;
|
|
286
|
+
suiteId: string;
|
|
287
|
+
language?: string;
|
|
288
|
+
caseIds?: string[];
|
|
289
|
+
/** When true, derive and persist repoTargetPath on each test case for IDE push. */
|
|
290
|
+
useV2?: boolean;
|
|
291
|
+
/** StyleProfile from connected repo — when provided, LLM mirrors repo conventions */
|
|
292
|
+
styleProfile?: Record<string, unknown>;
|
|
293
|
+
/** PageObjectInventory from connected repo — injected into LLM for reuse hints */
|
|
294
|
+
pageObjectInventory?: Array<{
|
|
295
|
+
filePath: string;
|
|
296
|
+
className: string;
|
|
297
|
+
methods: Array<{
|
|
298
|
+
name: string;
|
|
299
|
+
params: string;
|
|
300
|
+
returnType: string;
|
|
301
|
+
}>;
|
|
302
|
+
importPath: string;
|
|
303
|
+
}>;
|
|
304
|
+
/** Called after each test case is generated with (done, total) counts */
|
|
305
|
+
onProgress?: (done: number, total: number) => void;
|
|
306
|
+
jobId?: string;
|
|
307
|
+
/**
|
|
308
|
+
* Controls how per-TC spec files are bundled after generation.
|
|
309
|
+
* - PER_TEST_CASE: each TC gets its own spec file — no grouping.
|
|
310
|
+
* - BY_SCREEN: TCs sharing the same screenId are merged into a single grouped spec file.
|
|
311
|
+
* - BY_SECTION: TCs sharing the same scenarioId (or first @-tag) are merged into a single grouped spec file.
|
|
312
|
+
* - AUTO (default): auto-detect per TC source — BY_SCREEN when ≥60% of TCs have screenId,
|
|
313
|
+
* BY_SECTION when ≥60% have artifactId/scenarioId/traceTo, PER_TEST_CASE otherwise.
|
|
314
|
+
* Non-spec files (locators, page objects, test data, actions, assertions) are never merged.
|
|
315
|
+
*/
|
|
316
|
+
specGroupingStrategy?: 'PER_TEST_CASE' | 'BY_SCREEN' | 'BY_SECTION' | 'AUTO';
|
|
317
|
+
}): Promise<{
|
|
318
|
+
language: string;
|
|
319
|
+
files: Array<{
|
|
320
|
+
filename: string;
|
|
321
|
+
code: string;
|
|
322
|
+
testCaseId?: string;
|
|
323
|
+
}>;
|
|
324
|
+
basePage: string | null;
|
|
325
|
+
errors: Array<{
|
|
326
|
+
testCaseId: string;
|
|
327
|
+
title: string;
|
|
328
|
+
error: string;
|
|
329
|
+
}>;
|
|
330
|
+
}>;
|
|
331
|
+
export declare function generatePackScript(opts: {
|
|
332
|
+
tenantId: string;
|
|
333
|
+
projectId: string;
|
|
334
|
+
packType: 'regression' | 'smoke' | 'sanity' | 'api' | 'security' | 'integration' | 'e2e' | 'accessibility';
|
|
335
|
+
language?: string;
|
|
336
|
+
}): Promise<{
|
|
337
|
+
language: string;
|
|
338
|
+
files: any[];
|
|
339
|
+
basePage: string | null;
|
|
340
|
+
}>;
|
|
341
|
+
export declare function patchScriptWithAI(opts: {
|
|
342
|
+
tenantId: string;
|
|
343
|
+
projectId: string;
|
|
344
|
+
testCaseId: string;
|
|
345
|
+
language: string;
|
|
346
|
+
fullCode: string;
|
|
347
|
+
selection: {
|
|
348
|
+
startLine: number;
|
|
349
|
+
endLine: number;
|
|
350
|
+
} | null;
|
|
351
|
+
instruction: string;
|
|
352
|
+
testCaseContext?: {
|
|
353
|
+
title?: string;
|
|
354
|
+
steps?: unknown[];
|
|
355
|
+
expectedResult?: string;
|
|
356
|
+
};
|
|
357
|
+
}): Promise<{
|
|
358
|
+
patchedCode: string;
|
|
359
|
+
explanation: string;
|
|
360
|
+
lintViolations: string[];
|
|
361
|
+
lintWarnings: string[];
|
|
362
|
+
}>;
|
|
363
|
+
export declare function verifyScriptAlignment(opts: {
|
|
364
|
+
tenantId: string;
|
|
365
|
+
projectId: string;
|
|
366
|
+
testCaseId: string;
|
|
367
|
+
language: string;
|
|
368
|
+
code: string;
|
|
369
|
+
locatorsCode?: string;
|
|
370
|
+
testCase: {
|
|
371
|
+
title: string;
|
|
372
|
+
steps: unknown[];
|
|
373
|
+
expectedResult?: string;
|
|
374
|
+
kind: string;
|
|
375
|
+
};
|
|
376
|
+
}): Promise<{
|
|
377
|
+
aligned: boolean;
|
|
378
|
+
score: number;
|
|
379
|
+
issues: string[];
|
|
380
|
+
summary: string;
|
|
381
|
+
stepCoverage: StepCoverageResult;
|
|
382
|
+
}>;
|
|
383
|
+
import type { StyleProfile } from './repo-scan-agent.js';
|
|
384
|
+
export declare function generateScriptAligned(opts: {
|
|
385
|
+
tenantId: string;
|
|
386
|
+
projectId: string;
|
|
387
|
+
testCaseId: string;
|
|
388
|
+
language?: string;
|
|
389
|
+
styleProfile: StyleProfile;
|
|
390
|
+
/** Page object inventory from repo scan — injected into LLM prompt for reuse */
|
|
391
|
+
pageObjectInventory?: Array<{
|
|
392
|
+
filePath: string;
|
|
393
|
+
className: string;
|
|
394
|
+
methods: Array<{
|
|
395
|
+
name: string;
|
|
396
|
+
params: string;
|
|
397
|
+
returnType: string;
|
|
398
|
+
}>;
|
|
399
|
+
importPath: string;
|
|
400
|
+
}>;
|
|
401
|
+
/** Override target path in repo; if set, saved to TestCase.repoTargetPath */
|
|
402
|
+
repoTargetPath?: string;
|
|
403
|
+
save?: boolean;
|
|
404
|
+
}): Promise<{
|
|
405
|
+
language: string;
|
|
406
|
+
code: string;
|
|
407
|
+
saved: boolean;
|
|
408
|
+
repoTargetPath?: string;
|
|
409
|
+
}>;
|
|
410
|
+
export interface ScriptValidationResult {
|
|
411
|
+
ok: boolean;
|
|
412
|
+
errors: string;
|
|
413
|
+
method: 'tsc' | 'py_compile' | 'syntax_check' | 'skipped';
|
|
414
|
+
}
|
|
415
|
+
export declare function validateGeneratedScript(code: string, _framework: string, language: string): Promise<ScriptValidationResult>;
|
|
416
|
+
/**
|
|
417
|
+
* LLM-generates a description of the ZIP archive contents for the chosen framework.
|
|
418
|
+
* Uses repo styleProfile and skill files so the output reflects actual project conventions.
|
|
419
|
+
*/
|
|
420
|
+
export declare function generateScriptZipDescription(opts: {
|
|
421
|
+
tenantId: string;
|
|
422
|
+
projectId: string;
|
|
423
|
+
language: string;
|
|
424
|
+
styleProfile?: Record<string, unknown>;
|
|
425
|
+
repoSkillContext?: string;
|
|
426
|
+
}): Promise<{
|
|
427
|
+
items: string[];
|
|
428
|
+
}>;
|
|
429
|
+
export declare function generateRepoProjectStructure(opts: {
|
|
430
|
+
tenantId: string;
|
|
431
|
+
projectId: string;
|
|
432
|
+
repoName: string;
|
|
433
|
+
testFilePaths: string[];
|
|
434
|
+
pageObjectPaths: string[];
|
|
435
|
+
allRepoPaths?: string[];
|
|
436
|
+
styleProfile?: Record<string, unknown>;
|
|
437
|
+
}): Promise<{
|
|
438
|
+
tree: string;
|
|
439
|
+
}>;
|
|
440
|
+
export declare function loadApprovedContextLocators(tenantId: string, projectId: string, screenId?: string | null): Promise<Array<{
|
|
441
|
+
expression: string;
|
|
442
|
+
source: 'figma-design' | 'screenshot-extracted';
|
|
443
|
+
confidence: number;
|
|
444
|
+
elementType?: string;
|
|
445
|
+
description?: string;
|
|
446
|
+
}>>;
|
|
447
|
+
export {};
|