prompttest 1.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/CONTRIBUTING.md +80 -0
- package/LICENSE +36 -0
- package/LICENSES.md +81 -0
- package/README.md +402 -0
- package/SECURITY.md +56 -0
- package/dist/bin/prompttest.d.ts +2 -0
- package/dist/bin/prompttest.js +1020 -0
- package/dist/constants/commands.d.ts +125 -0
- package/dist/index.d.ts +140 -0
- package/dist/index.js +862 -0
- package/dist/lib/adb.d.ts +394 -0
- package/dist/lib/ai/heuristic-resolver.d.ts +19 -0
- package/dist/lib/ai/index.d.ts +16 -0
- package/dist/lib/ai/llm-provider.d.ts +40 -0
- package/dist/lib/ai/types.d.ts +64 -0
- package/dist/lib/baseline.d.ts +111 -0
- package/dist/lib/benchmark.d.ts +100 -0
- package/dist/lib/checkpoint.d.ts +61 -0
- package/dist/lib/config-loader.d.ts +87 -0
- package/dist/lib/config.d.ts +136 -0
- package/dist/lib/crawler.d.ts +335 -0
- package/dist/lib/data-loader.d.ts +53 -0
- package/dist/lib/dfs-engine.d.ts +106 -0
- package/dist/lib/dictionary.d.ts +41 -0
- package/dist/lib/doctor.d.ts +45 -0
- package/dist/lib/driver-interface.d.ts +50 -0
- package/dist/lib/enterprise.d.ts +71 -0
- package/dist/lib/errors.d.ts +68 -0
- package/dist/lib/explorer.d.ts +121 -0
- package/dist/lib/form-filler.d.ts +101 -0
- package/dist/lib/ios-driver.d.ts +38 -0
- package/dist/lib/live-server.d.ts +47 -0
- package/dist/lib/lock.d.ts +30 -0
- package/dist/lib/logger.d.ts +68 -0
- package/dist/lib/memory.d.ts +259 -0
- package/dist/lib/patterns.d.ts +202 -0
- package/dist/lib/prompt-runner.d.ts +100 -0
- package/dist/lib/recorder.d.ts +115 -0
- package/dist/lib/repl.d.ts +29 -0
- package/dist/lib/reporter.d.ts +253 -0
- package/dist/lib/runner-utils.d.ts +290 -0
- package/dist/lib/step-handlers.d.ts +388 -0
- package/docs/ARCHITECTURE.md +154 -0
- package/docs/USER_MANUAL.md +765 -0
- package/package.json +90 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a stored association between a test action and a specific on-screen element.
|
|
3
|
+
*/
|
|
4
|
+
export interface LearnedMapping {
|
|
5
|
+
/** The normalized natural language intent string that led to this mapping */
|
|
6
|
+
canonicalIntent: string;
|
|
7
|
+
/** The action type being performed */
|
|
8
|
+
action: 'TAP' | 'TYPE' | 'VERIFY';
|
|
9
|
+
/** The literal text, content descriptor, or resource ID of the matched element */
|
|
10
|
+
matchedIdentifier: string;
|
|
11
|
+
/** How the matched identifier is exposed on the Android element */
|
|
12
|
+
matchType: 'text' | 'contentDesc' | 'resourceId';
|
|
13
|
+
/** Probability score [0.0 - 1.0] of this mapping being correct */
|
|
14
|
+
confidence: number;
|
|
15
|
+
/** Number of consecutive times this mapping succeeded */
|
|
16
|
+
successCount: number;
|
|
17
|
+
/** Number of consecutive times this mapping failed */
|
|
18
|
+
failCount: number;
|
|
19
|
+
/** Total lifetime successful interactions with this mapping */
|
|
20
|
+
totalSuccesses: number;
|
|
21
|
+
/** Sliding window of recent interaction outcomes ('PASS' | 'FAIL') */
|
|
22
|
+
recentOutcomes: ('PASS' | 'FAIL')[];
|
|
23
|
+
/** ISO 8601 timestamp of the last time this mapping was updated or used */
|
|
24
|
+
lastUpdated: string;
|
|
25
|
+
/** ISO 8601 timestamp when this element was last observed on screen */
|
|
26
|
+
lastSeenTs: string;
|
|
27
|
+
/** Originating locator this element was healed from during autonomous self-healing */
|
|
28
|
+
healedFrom?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Represents a stored screen state fingerprint with elements, crawl status, and safe actions (LN-01, AX-07).
|
|
32
|
+
*/
|
|
33
|
+
export interface ScreenMemoryEntry {
|
|
34
|
+
lastSeenTs: string;
|
|
35
|
+
elements: string[];
|
|
36
|
+
crawled?: boolean;
|
|
37
|
+
crawledAt?: string;
|
|
38
|
+
safeActions?: string[];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Represents a cached natural language intent expansion into actionable PromptTest steps (LN-03).
|
|
42
|
+
*/
|
|
43
|
+
export interface IntentExpansionEntry {
|
|
44
|
+
intent: string;
|
|
45
|
+
steps: string[];
|
|
46
|
+
learnedAt: string;
|
|
47
|
+
usageCount: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Persisted JSON schema for storing memory data per Android package.
|
|
51
|
+
*/
|
|
52
|
+
export interface AppMemoryData {
|
|
53
|
+
/** The Android application package name (or "global") */
|
|
54
|
+
packageName: string;
|
|
55
|
+
/** Schema version for migration handling */
|
|
56
|
+
version: number;
|
|
57
|
+
/** ISO 8601 timestamp of the last update to this package's memory */
|
|
58
|
+
lastUpdated: string;
|
|
59
|
+
/** Dictionary of composite keys to learned mappings */
|
|
60
|
+
mappings: Record<string, LearnedMapping>;
|
|
61
|
+
/** Optional screen-hash index mapping screen fingerprints to element keys and crawl status (LN-01, AX-07) */
|
|
62
|
+
screens?: Record<string, ScreenMemoryEntry>;
|
|
63
|
+
/** Optional macro intent expansion cache (LN-03) */
|
|
64
|
+
intents?: Record<string, IntentExpansionEntry>;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The MemoryEngine handles loading, resolving, recording, and persisting
|
|
68
|
+
* learned test actions to improve performance and reliability.
|
|
69
|
+
*/
|
|
70
|
+
export declare class MemoryEngine {
|
|
71
|
+
private memoryDir;
|
|
72
|
+
private currentPackage;
|
|
73
|
+
private mappings;
|
|
74
|
+
private screens;
|
|
75
|
+
private intents;
|
|
76
|
+
private dirty;
|
|
77
|
+
private locale;
|
|
78
|
+
/**
|
|
79
|
+
* Sets the active locale for taxonomy lookup.
|
|
80
|
+
*/
|
|
81
|
+
setLocale(locale: string): void;
|
|
82
|
+
/**
|
|
83
|
+
* Gets the active locale.
|
|
84
|
+
*/
|
|
85
|
+
getLocale(): string;
|
|
86
|
+
/**
|
|
87
|
+
* Initializes the memory engine.
|
|
88
|
+
* @param customMemoryDir Optional directory path to store memory files. Defaults to a standard memory directory.
|
|
89
|
+
*/
|
|
90
|
+
constructor(customMemoryDir?: string);
|
|
91
|
+
private cleanPackageName;
|
|
92
|
+
private static readonly SCHEMA_VERSION;
|
|
93
|
+
/**
|
|
94
|
+
* Initializes memory for a specific Android package, loading its existing mappings from disk.
|
|
95
|
+
* @param packageName The Android package name to load.
|
|
96
|
+
* @returns A promise that resolves when initialization is complete.
|
|
97
|
+
*/
|
|
98
|
+
init(packageName: string): Promise<void>;
|
|
99
|
+
/**
|
|
100
|
+
* Resolves a deterministic canonical query for synonymous terms (LN-02).
|
|
101
|
+
*/
|
|
102
|
+
getCanonicalQuery(query: string): string;
|
|
103
|
+
private buildKey;
|
|
104
|
+
/**
|
|
105
|
+
* Resolves a learned mapping for a specific action and query intent.
|
|
106
|
+
* Supports synonym-canonical resolution so equivalent phrasings resolve to the same mapping (LN-02).
|
|
107
|
+
* @param action The action type (e.g., 'TAP', 'TYPE').
|
|
108
|
+
* @param query The natural language query intent.
|
|
109
|
+
* @returns The learned mapping if found, otherwise undefined.
|
|
110
|
+
*/
|
|
111
|
+
resolve(action: string, query: string): LearnedMapping | undefined;
|
|
112
|
+
/**
|
|
113
|
+
* Returns an ordered list of search candidates:
|
|
114
|
+
* 0. Screen-specific learned element identifier (if screenHash provided & verified) (LN-01)
|
|
115
|
+
* 1. The learned element identifier (if verified memory exists) (LN-02)
|
|
116
|
+
* 2. The literal query itself
|
|
117
|
+
* 3. Seed dictionary synonyms
|
|
118
|
+
*
|
|
119
|
+
* @param action The action being performed.
|
|
120
|
+
* @param query The natural language query to match.
|
|
121
|
+
* @param locale Optional locale override. Defaults to engine active locale.
|
|
122
|
+
* @param screenHash Optional screen hash fingerprint for whole-screen lookup.
|
|
123
|
+
* @returns Array of candidate strings to search for on screen.
|
|
124
|
+
*/
|
|
125
|
+
getAllCandidates(action: string, query: string, locale?: string, screenHash?: string): string[];
|
|
126
|
+
/**
|
|
127
|
+
* Records a successful element interaction into persistent memory.
|
|
128
|
+
*
|
|
129
|
+
* @param action The action performed.
|
|
130
|
+
* @param query The initial query intent.
|
|
131
|
+
* @param matchedIdentifier The actual identifier matched on screen.
|
|
132
|
+
* @param matchType The type of match (text, contentDesc, resourceId).
|
|
133
|
+
* @param confidence Initial confidence score for the new mapping.
|
|
134
|
+
*/
|
|
135
|
+
recordSuccess(action: string, query: string, matchedIdentifier: string, matchType: 'text' | 'contentDesc' | 'resourceId', confidence?: number, healedFrom?: string, screenHash?: string): void;
|
|
136
|
+
/**
|
|
137
|
+
* Associates a learned element mapping key with a screen hash fingerprint (LN-01).
|
|
138
|
+
* @param screenHash The unique hash fingerprint of the UI screen.
|
|
139
|
+
* @param elementKey The memory key of the learned mapping.
|
|
140
|
+
*/
|
|
141
|
+
associateScreenElement(screenHash: string, elementKey: string): void;
|
|
142
|
+
/**
|
|
143
|
+
* Retrieves all learned elements associated with a specific screen hash (LN-01).
|
|
144
|
+
* Enables whole-screen fast-forwarding on recognized screens.
|
|
145
|
+
* @param screenHash The unique hash fingerprint of the screen.
|
|
146
|
+
* @returns Array of LearnedMapping objects known to exist on this screen.
|
|
147
|
+
*/
|
|
148
|
+
getScreenElements(screenHash: string): LearnedMapping[];
|
|
149
|
+
/**
|
|
150
|
+
* Retrieves raw screen index data for reporting and inspection.
|
|
151
|
+
*/
|
|
152
|
+
getScreenIndex(): Record<string, ScreenMemoryEntry>;
|
|
153
|
+
/**
|
|
154
|
+
* Marks a screen hash fingerprint as crawled and records verified safe actions (AX-07).
|
|
155
|
+
* @param screenHash The unique hash fingerprint of the screen.
|
|
156
|
+
* @param safeActions Optional array of action labels verified safe on this screen.
|
|
157
|
+
*/
|
|
158
|
+
markScreenCrawled(screenHash: string, safeActions?: string[]): void;
|
|
159
|
+
/**
|
|
160
|
+
* Queries whether a screen fingerprint was previously crawled offline (AX-07).
|
|
161
|
+
* @param screenHash The unique hash fingerprint of the screen.
|
|
162
|
+
* @returns true if the screen was previously explored and marked crawled.
|
|
163
|
+
*/
|
|
164
|
+
isScreenCrawled(screenHash: string): boolean;
|
|
165
|
+
/**
|
|
166
|
+
* Retrieves screen memory entry for a specific screen hash.
|
|
167
|
+
*/
|
|
168
|
+
getScreenMemory(screenHash: string): ScreenMemoryEntry | undefined;
|
|
169
|
+
/**
|
|
170
|
+
* Retrieves the number of unique screens marked as crawled (AX-07).
|
|
171
|
+
*/
|
|
172
|
+
getCrawledScreensCount(): number;
|
|
173
|
+
/**
|
|
174
|
+
* Caches a resolved natural language macro intent expansion into actionable PromptTest steps (LN-03).
|
|
175
|
+
* @param intent The natural language intent text (e.g. "log in with default credentials").
|
|
176
|
+
* @param steps Array of actionable PromptTest step strings.
|
|
177
|
+
*/
|
|
178
|
+
recordIntentExpansion(intent: string, steps: string[]): void;
|
|
179
|
+
/**
|
|
180
|
+
* Retrieves a cached natural language intent expansion if available (LN-03).
|
|
181
|
+
* Increments usage count upon cache hit.
|
|
182
|
+
* @param intent The natural language intent text.
|
|
183
|
+
* @returns Array of step strings or undefined if not cached.
|
|
184
|
+
*/
|
|
185
|
+
getIntentExpansion(intent: string): string[] | undefined;
|
|
186
|
+
/**
|
|
187
|
+
* Checks whether a macro intent expansion exists in persistent memory (LN-03).
|
|
188
|
+
*/
|
|
189
|
+
hasIntentExpansion(intent: string): boolean;
|
|
190
|
+
/**
|
|
191
|
+
* Retrieves total count of cached macro intent expansions (LN-03).
|
|
192
|
+
*/
|
|
193
|
+
getIntentExpansionsCount(): number;
|
|
194
|
+
/**
|
|
195
|
+
* Records an interaction failure for a learned mapping.
|
|
196
|
+
* Employs sliding-window decay over the last 5 interactions.
|
|
197
|
+
* A mapping is pruned only if 3 or more recent interactions failed or confidence drops below 0.20.
|
|
198
|
+
*
|
|
199
|
+
* @param action The action that failed.
|
|
200
|
+
* @param query The natural language query intent that failed.
|
|
201
|
+
*/
|
|
202
|
+
recordFailure(action: string, query: string): void;
|
|
203
|
+
/**
|
|
204
|
+
* Applies stale-mapping decay for elements not observed recently (LN-05).
|
|
205
|
+
* Reduces confidence of mappings whose lastSeenTs is older than thresholdDays.
|
|
206
|
+
* Does NOT delete them outright, preserving knowledge with demoted confidence.
|
|
207
|
+
*
|
|
208
|
+
* @param thresholdDays Number of days of inactivity before decaying (defaults to CONFIG.memory.staleThresholdDays).
|
|
209
|
+
* @returns Number of mappings decayed.
|
|
210
|
+
*/
|
|
211
|
+
decayStaleMappings(thresholdDays?: number): number;
|
|
212
|
+
/**
|
|
213
|
+
* Asynchronously commits learned knowledge to disk.
|
|
214
|
+
* @returns A promise that resolves when the save operation completes.
|
|
215
|
+
*/
|
|
216
|
+
save(): Promise<void>;
|
|
217
|
+
/**
|
|
218
|
+
* Exports learned mappings to a designated JSON file for sharing across CI or developers.
|
|
219
|
+
* @param destFilePath Optional destination file path. Defaults to memory/<package>-export.json
|
|
220
|
+
* @returns The resolved destination file path.
|
|
221
|
+
*/
|
|
222
|
+
exportMemory(destFilePath?: string): Promise<string>;
|
|
223
|
+
/**
|
|
224
|
+
* Imports learned mappings from a JSON export file into the current knowledge base.
|
|
225
|
+
* Merges imported mappings with existing knowledge, retaining higher-confidence entries.
|
|
226
|
+
* @param sourceFilePath Path to the JSON file to import.
|
|
227
|
+
* @returns Number of mappings successfully imported or merged.
|
|
228
|
+
*/
|
|
229
|
+
importMemory(sourceFilePath: string): Promise<number>;
|
|
230
|
+
/**
|
|
231
|
+
* Retrieves all learned mappings for the current package.
|
|
232
|
+
* @returns An array of all learned mappings.
|
|
233
|
+
*/
|
|
234
|
+
getMappingsList(): LearnedMapping[];
|
|
235
|
+
/**
|
|
236
|
+
* Gets memory statistics for the current package.
|
|
237
|
+
* @returns An object containing total mappings, package name, lifetime successes, and average confidence.
|
|
238
|
+
*/
|
|
239
|
+
getStats(): {
|
|
240
|
+
totalMappings: number;
|
|
241
|
+
totalScreens: number;
|
|
242
|
+
crawledScreens: number;
|
|
243
|
+
totalIntents: number;
|
|
244
|
+
package: string;
|
|
245
|
+
totalSuccesses: number;
|
|
246
|
+
averageConfidence: number;
|
|
247
|
+
};
|
|
248
|
+
/**
|
|
249
|
+
* Clears the memory mappings for a specific package, deleting the associated file.
|
|
250
|
+
* @param packageName Optional package name to clear. Defaults to current package.
|
|
251
|
+
* @returns A promise resolving to true if a file was deleted, false otherwise.
|
|
252
|
+
*/
|
|
253
|
+
clear(packageName?: string): Promise<boolean>;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Global singleton instance of the MemoryEngine.
|
|
257
|
+
* Used throughout the framework to access the persistent knowledge base.
|
|
258
|
+
*/
|
|
259
|
+
export declare const memoryEngine: MemoryEngine;
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized Regex & Matching Patterns for PromptTest
|
|
3
|
+
*
|
|
4
|
+
* Provides unified, reusable regular expressions and string extraction helpers
|
|
5
|
+
* for prompt instruction parsing, XML hierarchy parsing, and UI element matching.
|
|
6
|
+
* This file serves as the central pattern repository for all text normalization,
|
|
7
|
+
* variable interpolation, and string similarity operations across the framework.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Removes leading step numbers, bullets e.g. "1. ", "10. ", "- ", "* "
|
|
11
|
+
* @type {RegExp}
|
|
12
|
+
*/
|
|
13
|
+
export declare const STEP_PREFIX_REGEX: RegExp;
|
|
14
|
+
/**
|
|
15
|
+
* Robust extraction of text wrapped in either double quotes ("..."), single quotes ('...'),
|
|
16
|
+
* or bare tokens.
|
|
17
|
+
* Correctly handles apostrophes inside double quotes (e.g. "Today's Schedule")
|
|
18
|
+
* and double quotes inside single quotes (e.g. 'Press "OK"').
|
|
19
|
+
*
|
|
20
|
+
* @param {string} text - The input text from which to extract the quoted token.
|
|
21
|
+
* @returns {string} The extracted text without the wrapping quotes, or trimmed text if unquoted.
|
|
22
|
+
*/
|
|
23
|
+
export declare function extractQuotedText(text: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* Helper to get value from a captured token match (checking group indices)
|
|
26
|
+
*
|
|
27
|
+
* @param {(string | undefined)[]} groups - Array of captured regex groups to check.
|
|
28
|
+
* @returns {string} The first non-empty, defined capture group string.
|
|
29
|
+
*/
|
|
30
|
+
export declare function resolveTokenMatch(groups: (string | undefined)[]): string;
|
|
31
|
+
/**
|
|
32
|
+
* Dynamic variable interpolation helper
|
|
33
|
+
*
|
|
34
|
+
* @param {string} text - The raw text containing variable placeholders to interpolate.
|
|
35
|
+
* @param {Record<string, string>} [customVars] - Optional map of custom variables to inject.
|
|
36
|
+
* @returns {string} The text with all variables resolved and interpolated.
|
|
37
|
+
*/
|
|
38
|
+
export declare function interpolateVariables(text: string, customVars?: Record<string, string>): string;
|
|
39
|
+
/**
|
|
40
|
+
* Collection of regular expressions used to parse natural language prompt instructions
|
|
41
|
+
* into actionable test steps.
|
|
42
|
+
* @type {Record<string, RegExp>}
|
|
43
|
+
*/
|
|
44
|
+
export declare const PROMPT_ACTION_PATTERNS: {
|
|
45
|
+
/** TAP / CLICK: e.g. Tap 'Sign In', Click "Today's Schedule", Tap on 'rajesh.verma', Press button 'Submit' */
|
|
46
|
+
TAP: RegExp;
|
|
47
|
+
/** ORDINAL TAP: e.g. Tap 1st 'View', Click 2nd "Export", Tap last 'Delete' */
|
|
48
|
+
ORDINAL_TAP: RegExp;
|
|
49
|
+
/** RELATIVE PROXIMITY TAP: e.g. Tap 'Delete' next to 'Rohan Gupta', Click 'Edit' near 'Batch 1' */
|
|
50
|
+
PROXIMITY_TAP: RegExp;
|
|
51
|
+
/** CLEAR INPUT: e.g. Clear 'Email', Empty field 'Enter your password', Clear text in 'Search' */
|
|
52
|
+
CLEAR: RegExp;
|
|
53
|
+
/** LONG PRESS: e.g. Long press 'Mid-Term Examination Schedule', Press and hold 'Message' */
|
|
54
|
+
LONG_PRESS: RegExp;
|
|
55
|
+
/** TYPE / ENTER: e.g. Type 'ramesh@coachconnect.app' into 'Email' */
|
|
56
|
+
TYPE: RegExp;
|
|
57
|
+
/** VERIFY / ASSERT: e.g. Verify 'Apex Coaching Academy' is visible, Verify error message "Email is required" is not visible */
|
|
58
|
+
VERIFY: RegExp;
|
|
59
|
+
/** BACK: e.g. Press back, Go back, Navigate back, Back */
|
|
60
|
+
BACK: RegExp;
|
|
61
|
+
/** SCROLL TO: e.g. Scroll to 'Apex Coaching Academy', Scroll down to 'Submit', Swipe up to 'Top' */
|
|
62
|
+
SCROLL_TO: RegExp;
|
|
63
|
+
/** SCROLL / SWIPE: e.g. Scroll down, Swipe up, Swipe left on 'Card' */
|
|
64
|
+
SCROLL: RegExp;
|
|
65
|
+
/** DIRECTIONAL SWIPE: e.g. Swipe left, Swipe right, Swipe left on 'Carousel' */
|
|
66
|
+
DIRECTIONAL_SWIPE: RegExp;
|
|
67
|
+
/** TOGGLE / CHECK / UNCHECK: e.g. Toggle 'Remember Me', Check 'I agree', Turn on 'Notifications' */
|
|
68
|
+
TOGGLE: RegExp;
|
|
69
|
+
/** SELECT DROPDOWN / PICKER: e.g. Select 'Grade 10' from 'Class Dropdown' */
|
|
70
|
+
SELECT_DROPDOWN: RegExp;
|
|
71
|
+
/** APP LIFECYCLE: Launch / Open */
|
|
72
|
+
LAUNCH_APP: RegExp;
|
|
73
|
+
/** APP LIFECYCLE: Restart / Relaunch */
|
|
74
|
+
RESTART_APP: RegExp;
|
|
75
|
+
/** APP LIFECYCLE: Terminate / Close / Force Stop */
|
|
76
|
+
TERMINATE_APP: RegExp;
|
|
77
|
+
/** APP LIFECYCLE: Clear App Data */
|
|
78
|
+
CLEAR_DATA: RegExp;
|
|
79
|
+
/** APP LIFECYCLE: Grant Permission */
|
|
80
|
+
GRANT_PERMISSION: RegExp;
|
|
81
|
+
/** DEEP LINK: e.g. Open deep link 'myapp://batches/10' */
|
|
82
|
+
DEEP_LINK: RegExp;
|
|
83
|
+
/** WAIT: e.g. Wait 3s, Wait 5 seconds, Wait 2 */
|
|
84
|
+
WAIT: RegExp;
|
|
85
|
+
/** WAIT UNTIL: e.g. Wait until 'Welcome' is visible, Wait for "Submit" is enabled up to 10s */
|
|
86
|
+
WAIT_UNTIL: RegExp;
|
|
87
|
+
/** CONDITIONAL IF: e.g. If 'Allow' is visible, If 'Skip' is present */
|
|
88
|
+
IF_VISIBLE: RegExp;
|
|
89
|
+
/** CONDITIONAL ELSE */
|
|
90
|
+
ELSE: RegExp;
|
|
91
|
+
/** BLOCK TERMINATOR: End, End if, End loop, fi, done */
|
|
92
|
+
END: RegExp;
|
|
93
|
+
/** LOOP: e.g. Loop 5 times, Repeat 3 */
|
|
94
|
+
LOOP: RegExp;
|
|
95
|
+
/** FOR EACH: e.g. For each item in 'Settings List', For each 'Order Card' */
|
|
96
|
+
FOR_EACH: RegExp;
|
|
97
|
+
/** VARIABLE ASSIGNMENT: e.g. Set $username = 'admin', Set $email = $RANDOM_EMAIL */
|
|
98
|
+
SET_VARIABLE: RegExp;
|
|
99
|
+
/** DEVICE STATE: Wi-Fi on/off */
|
|
100
|
+
DEVICE_WIFI: RegExp;
|
|
101
|
+
/** DEVICE STATE: Airplane mode on/off */
|
|
102
|
+
DEVICE_AIRPLANE: RegExp;
|
|
103
|
+
/** DEVICE STATE: Orientation portrait/landscape */
|
|
104
|
+
DEVICE_ORIENTATION: RegExp;
|
|
105
|
+
/** DEVICE STATE: Notification shade */
|
|
106
|
+
DEVICE_NOTIFICATIONS: RegExp;
|
|
107
|
+
/** SPEC MODULARITY: Include / Run subflow */
|
|
108
|
+
INCLUDE_SPEC: RegExp;
|
|
109
|
+
/** JS HOOK: e.g. Run JS: vars.counter = 5 */
|
|
110
|
+
RUN_JS: RegExp;
|
|
111
|
+
/** OTP / 2FA CAPTURE: e.g. Enter verification code just sent, Enter OTP into 'Code Field' */
|
|
112
|
+
ENTER_OTP: RegExp;
|
|
113
|
+
/** API REQUEST: e.g. API GET 'https://api.example.com/status' assert status 200 */
|
|
114
|
+
API_REQUEST: RegExp;
|
|
115
|
+
/** EMAIL ASSERT: e.g. Assert email to 'user@test.com' with subject 'Welcome' contains 'Verify' */
|
|
116
|
+
EMAIL_ASSERT: RegExp;
|
|
117
|
+
/** OPTIONAL SUFFIX CHECK: (optional) or (if present) */
|
|
118
|
+
OPTIONAL_SUFFIX: RegExp;
|
|
119
|
+
/** Fallback TAP with any quotes */
|
|
120
|
+
FALLBACK_QUOTED_TAP: RegExp;
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* Collection of regular expressions used for parsing Android UI Automator XML hierarchies.
|
|
124
|
+
* @type {Record<string, RegExp>}
|
|
125
|
+
*/
|
|
126
|
+
export declare const XML_HIERARCHY_PATTERNS: {
|
|
127
|
+
/** Outer <hierarchy> ... </hierarchy> wrapper */
|
|
128
|
+
HIERARCHY_ROOT: RegExp;
|
|
129
|
+
/** Individual XML node tag opening / self-closing / closing */
|
|
130
|
+
NODE_TAG: RegExp;
|
|
131
|
+
/** XML attribute key-value pairs (key="value") */
|
|
132
|
+
ATTR_KEY_VALUE: RegExp;
|
|
133
|
+
/** Android element bounds string: [x1,y1][x2,y2] */
|
|
134
|
+
BOUNDS_RECT: RegExp;
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* Unescapes standard XML and numeric character entities (e.g. 🚨 -> 🚨)
|
|
138
|
+
* present in Android UI Automator hierarchy dumps.
|
|
139
|
+
*
|
|
140
|
+
* @param {string} text - The XML text to unescape.
|
|
141
|
+
* @returns {string} The unescaped string with standard characters.
|
|
142
|
+
*/
|
|
143
|
+
export declare function unescapeXml(text: string): string;
|
|
144
|
+
/**
|
|
145
|
+
* Normalizes text for resilient matching:
|
|
146
|
+
* - Unescapes XML entities (& -> &)
|
|
147
|
+
* - Trims whitespace
|
|
148
|
+
* - Converts to lower case
|
|
149
|
+
* - Normalizes curly single/double quotes to straight quotes
|
|
150
|
+
*
|
|
151
|
+
* @param {string} str - The string to normalize.
|
|
152
|
+
* @returns {string} The normalized, stripped string.
|
|
153
|
+
*/
|
|
154
|
+
export declare function normalizeText(str: string): string;
|
|
155
|
+
/**
|
|
156
|
+
* Flexible text containment check that is resilient to case, icon prefixes,
|
|
157
|
+
* XML entity escaping (& vs &), and punctuation differences.
|
|
158
|
+
*
|
|
159
|
+
* @param {string} needle - The expected text or subset to look for.
|
|
160
|
+
* @param {string} haystack - The full text to search within.
|
|
161
|
+
* @returns {boolean} True if the haystack contains the needle.
|
|
162
|
+
*/
|
|
163
|
+
export declare function matchesText(needle: string, haystack: string): boolean;
|
|
164
|
+
/**
|
|
165
|
+
* Common keywords used to identify form submission buttons or actions.
|
|
166
|
+
* @type {string[]}
|
|
167
|
+
*/
|
|
168
|
+
export declare const SUBMIT_KEYWORDS: string[];
|
|
169
|
+
/**
|
|
170
|
+
* Semantic keywords indicating primary user actions or interactive elements.
|
|
171
|
+
* @type {string[]}
|
|
172
|
+
*/
|
|
173
|
+
export declare const ACTION_KEYWORDS: string[];
|
|
174
|
+
/**
|
|
175
|
+
* Computes the Levenshtein distance between two strings.
|
|
176
|
+
*
|
|
177
|
+
* @param {string} s1 - The first string to compare.
|
|
178
|
+
* @param {string} s2 - The second string to compare.
|
|
179
|
+
* @returns {number} The edit distance between the two strings.
|
|
180
|
+
*/
|
|
181
|
+
export declare function levenshteinDistance(s1: string, s2: string): number;
|
|
182
|
+
/**
|
|
183
|
+
* Computes a normalized similarity score between 0.0 (completely different) and 1.0 (identical).
|
|
184
|
+
*
|
|
185
|
+
* @param {string} s1 - The first string to compare.
|
|
186
|
+
* @param {string} s2 - The second string to compare.
|
|
187
|
+
* @returns {number} A score representing the similarity of the strings.
|
|
188
|
+
*/
|
|
189
|
+
export declare function stringSimilarity(s1: string, s2: string): number;
|
|
190
|
+
/**
|
|
191
|
+
* Searches a list of candidates and returns the top closest matches above a given similarity threshold.
|
|
192
|
+
*
|
|
193
|
+
* @param {string} query - The target string to search for.
|
|
194
|
+
* @param {string[]} candidates - The array of candidate strings to search against.
|
|
195
|
+
* @param {number} [limit=3] - The maximum number of matches to return.
|
|
196
|
+
* @param {number} [threshold=0.35] - The minimum similarity score required to be considered a match.
|
|
197
|
+
* @returns {{ text: string; score: number }[]} An array of objects containing matching text and their scores.
|
|
198
|
+
*/
|
|
199
|
+
export declare function findClosestMatches(query: string, candidates: string[], limit?: number, threshold?: number): {
|
|
200
|
+
text: string;
|
|
201
|
+
score: number;
|
|
202
|
+
}[];
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { AndroidDriver } from './adb.js';
|
|
2
|
+
import { QaReportData, Reporter } from './reporter.js';
|
|
3
|
+
import { MemoryEngine } from './memory.js';
|
|
4
|
+
import { CheckpointManager } from './checkpoint.js';
|
|
5
|
+
import { BaselineManager } from './baseline.js';
|
|
6
|
+
import { SemanticResolver } from './ai/index.js';
|
|
7
|
+
import { type PromptStep, type PromptStepType, type RunOptions } from './runner-utils.js';
|
|
8
|
+
export type { PromptStep, PromptStepType, RunOptions };
|
|
9
|
+
/**
|
|
10
|
+
* Core engine responsible for parsing test specs and coordinating execution
|
|
11
|
+
* on an Android device using the provided driver and services.
|
|
12
|
+
*/
|
|
13
|
+
export declare class PromptRunner {
|
|
14
|
+
private driver;
|
|
15
|
+
private memory;
|
|
16
|
+
private reporter;
|
|
17
|
+
private checkpoints;
|
|
18
|
+
private baselines;
|
|
19
|
+
private lastHierarchy;
|
|
20
|
+
private screenDimensions;
|
|
21
|
+
private navBarHeight;
|
|
22
|
+
/**
|
|
23
|
+
* Initializes a new instance of the PromptRunner.
|
|
24
|
+
* Uses dependency injection for core services, defaulting to singletons if omitted.
|
|
25
|
+
*
|
|
26
|
+
* @param driver - The Android ADB driver for device communication.
|
|
27
|
+
* @param memory - The memory engine for storing and retrieving learned locators.
|
|
28
|
+
* @param reporter - The reporting engine for test results.
|
|
29
|
+
* @param checkpoints - Manager for test step checkpoints and resuming.
|
|
30
|
+
* @param baselines - Manager for visual baseline testing.
|
|
31
|
+
*/
|
|
32
|
+
constructor(driver?: AndroidDriver, memory?: MemoryEngine, reporter?: Reporter, checkpoints?: CheckpointManager, baselines?: BaselineManager, semanticResolver?: SemanticResolver);
|
|
33
|
+
private semanticResolver;
|
|
34
|
+
private healEnabled;
|
|
35
|
+
private activeLocale;
|
|
36
|
+
private runtimeVariables;
|
|
37
|
+
private loopStack;
|
|
38
|
+
/**
|
|
39
|
+
* Recursively expands `INCLUDE '<path>'` directives within a spec file.
|
|
40
|
+
* Resolves paths relative to current spec directory and guards against circular recursion.
|
|
41
|
+
*
|
|
42
|
+
* @param specFilePath - Path to the root spec file.
|
|
43
|
+
* @param visitedFiles - Set of visited absolute file paths in the recursion stack.
|
|
44
|
+
* @returns The fully expanded spec string.
|
|
45
|
+
* @throws SpecRecursionError if circular spec inclusion is detected.
|
|
46
|
+
*/
|
|
47
|
+
expandSpecIncludes(specFilePath: string, visitedFiles?: Set<string>): string;
|
|
48
|
+
/**
|
|
49
|
+
* Expands high-level macro steps in a test spec into concrete primitive actions.
|
|
50
|
+
*
|
|
51
|
+
* @param specText - Original spec text containing potential high-level intents.
|
|
52
|
+
* @param resolver - Optional custom semantic resolver.
|
|
53
|
+
* @returns The expanded specification string and count of expanded steps.
|
|
54
|
+
*/
|
|
55
|
+
expandSpec(specText: string, resolver?: SemanticResolver): Promise<{
|
|
56
|
+
expanded: string;
|
|
57
|
+
stepsAdded: number;
|
|
58
|
+
}>;
|
|
59
|
+
/**
|
|
60
|
+
* Parses a multi-line, plain-English test specification into a structured array of actionable steps.
|
|
61
|
+
* Understands variable interpolation, optional steps, flow control blocks (IF, LOOP), and all action types.
|
|
62
|
+
*
|
|
63
|
+
* @param promptText - The raw plain-English spec to parse.
|
|
64
|
+
* @param customVars - Optional key-value pairs for string interpolation.
|
|
65
|
+
* @returns An array of parsed PromptStep objects structured into an execution AST.
|
|
66
|
+
*/
|
|
67
|
+
parsePrompt(promptText: string, customVars?: Record<string, string>): PromptStep[];
|
|
68
|
+
/**
|
|
69
|
+
* Executes a plain-English test spec against the connected Android device.
|
|
70
|
+
* Handles device locking, memory loading, sequential execution, checkpointing,
|
|
71
|
+
* error recovery, and final report generation.
|
|
72
|
+
*
|
|
73
|
+
* @param specFilePath - The absolute or relative path to the plain-English spec file.
|
|
74
|
+
* @param pkgOrOptions - The target app package name (legacy) or a RunOptions configuration object.
|
|
75
|
+
* @param legacySerial - The target device serial number (legacy support).
|
|
76
|
+
* @returns A promise that resolves to the final QA report data upon completion or failure.
|
|
77
|
+
* @throws Error if the spec file does not exist.
|
|
78
|
+
*/
|
|
79
|
+
runSpec(specFilePath: string, pkgOrOptions?: string | RunOptions, legacySerial?: string): Promise<QaReportData>;
|
|
80
|
+
private getCleanHierarchy;
|
|
81
|
+
/**
|
|
82
|
+
* Expectation-driven dynamic polling: waits for an element matching target to appear on screen.
|
|
83
|
+
* Proceeds as soon as the element exists without waiting for blind static sleeps.
|
|
84
|
+
*/
|
|
85
|
+
private ensureInViewport;
|
|
86
|
+
private waitForTarget;
|
|
87
|
+
private buildDiagnosticError;
|
|
88
|
+
executeStep(step: PromptStep, serial?: string, upcomingSteps?: PromptStep[]): Promise<{
|
|
89
|
+
fastForwarded?: boolean;
|
|
90
|
+
reason?: string;
|
|
91
|
+
skipCount?: number;
|
|
92
|
+
} | void>;
|
|
93
|
+
private findTargetInputField;
|
|
94
|
+
private matchNodes;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* A singleton instance of the PromptRunner.
|
|
98
|
+
* Pre-configured with default dependencies for convenient global usage across the framework.
|
|
99
|
+
*/
|
|
100
|
+
export declare const promptRunner: PromptRunner;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { AndroidDriver } from './adb.js';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration options for the recording session.
|
|
4
|
+
*/
|
|
5
|
+
export interface RecordOptions {
|
|
6
|
+
/**
|
|
7
|
+
* If true, the recorder will append new captured steps to the existing test spec file
|
|
8
|
+
* rather than overwriting or creating a new file.
|
|
9
|
+
*/
|
|
10
|
+
append?: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Represents a discrete user interaction event captured during the session.
|
|
14
|
+
*/
|
|
15
|
+
export interface RecordedEvent {
|
|
16
|
+
/** The generated plain-English instruction for this event. */
|
|
17
|
+
stepText: string;
|
|
18
|
+
/** The exact epoch timestamp (in milliseconds) when this event occurred. */
|
|
19
|
+
timestamp: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The core engine that listens to device input and transforms raw interaction telemetry
|
|
23
|
+
* into semantic PromptTest step instructions.
|
|
24
|
+
*/
|
|
25
|
+
export declare class AutonomousRecorder {
|
|
26
|
+
private driver;
|
|
27
|
+
private deviceLock;
|
|
28
|
+
private isRecording;
|
|
29
|
+
private recordedSteps;
|
|
30
|
+
private existingSteps;
|
|
31
|
+
private existingFileHeader;
|
|
32
|
+
private lastHierarchyFlat;
|
|
33
|
+
private lastScreenTitle;
|
|
34
|
+
private visitedScreens;
|
|
35
|
+
private targetPackage;
|
|
36
|
+
private isAppendMode;
|
|
37
|
+
private resolvedOutputPath;
|
|
38
|
+
private activeInput;
|
|
39
|
+
private geteventProcess;
|
|
40
|
+
private isRefreshingHierarchy;
|
|
41
|
+
private targetSerial;
|
|
42
|
+
private touchMaxX;
|
|
43
|
+
private touchMaxY;
|
|
44
|
+
private displayWidth;
|
|
45
|
+
private displayHeight;
|
|
46
|
+
private lastTapTimestamp;
|
|
47
|
+
private lastRecordedTapTarget;
|
|
48
|
+
private inFlightTapQueue;
|
|
49
|
+
private lastScrollTimestamp;
|
|
50
|
+
private lastScrollDirection;
|
|
51
|
+
private inputDebounceTimer;
|
|
52
|
+
private logcatEventProcess;
|
|
53
|
+
private logcatCrashProcess;
|
|
54
|
+
private hierarchyStale;
|
|
55
|
+
private hierarchyCacheTime;
|
|
56
|
+
private currentScreenName;
|
|
57
|
+
private sessionScreenSections;
|
|
58
|
+
private sessionStartTime;
|
|
59
|
+
private screenshotDir;
|
|
60
|
+
private screenshotCounter;
|
|
61
|
+
private crashDetected;
|
|
62
|
+
private lastScreenTransitionTime;
|
|
63
|
+
/**
|
|
64
|
+
* Initializes a new AutonomousRecorder.
|
|
65
|
+
* @param driver An optional AndroidDriver instance to use. If omitted, the default singleton is used.
|
|
66
|
+
*/
|
|
67
|
+
constructor(driver?: AndroidDriver);
|
|
68
|
+
private extractBrandSlug;
|
|
69
|
+
/**
|
|
70
|
+
* Starts an interactive real-time recording session on the target Android device.
|
|
71
|
+
* Automatically detects the active app, starts capturing gestures and key events,
|
|
72
|
+
* monitors screen transitions, and writes out a plain-text spec.
|
|
73
|
+
*
|
|
74
|
+
* @param outputSpecPath Optional file path to save the generated test spec to.
|
|
75
|
+
* @param serial Optional serial number of the target device to record from.
|
|
76
|
+
* @param options Additional recording configuration options.
|
|
77
|
+
* @returns A promise that resolves when the recording session concludes.
|
|
78
|
+
*/
|
|
79
|
+
startRecording(outputSpecPath?: string, serial?: string, options?: RecordOptions): Promise<void>;
|
|
80
|
+
private startEventStream;
|
|
81
|
+
private cleanLabel;
|
|
82
|
+
private handleScroll;
|
|
83
|
+
private handleSwipe;
|
|
84
|
+
private handleLongPressAt;
|
|
85
|
+
private handleTapAt;
|
|
86
|
+
private handleKeyPress;
|
|
87
|
+
private scheduleInputDebounce;
|
|
88
|
+
private flushActiveInput;
|
|
89
|
+
private syncActiveInputText;
|
|
90
|
+
private recordInputText;
|
|
91
|
+
private startLogcatScreenWatcher;
|
|
92
|
+
private startLogcatCrashWatcher;
|
|
93
|
+
private captureSessionScreenshot;
|
|
94
|
+
private triggerAsyncHierarchyRefresh;
|
|
95
|
+
private doHierarchyRefresh;
|
|
96
|
+
private detectAndLogTransientAlerts;
|
|
97
|
+
private refreshHierarchySync;
|
|
98
|
+
private isIconGlyph;
|
|
99
|
+
private cleanDialogOrCompoundLabel;
|
|
100
|
+
private isCardMetadataSubtitle;
|
|
101
|
+
private findPrimaryCardTitle;
|
|
102
|
+
private resolveActionLabel;
|
|
103
|
+
private getCurrentStepNumber;
|
|
104
|
+
private detectAndLogScreenHeader;
|
|
105
|
+
private resolveFieldLabel;
|
|
106
|
+
private isPlaceholderText;
|
|
107
|
+
private saveSpec;
|
|
108
|
+
private saveReport;
|
|
109
|
+
private printExitSummary;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Pre-instantiated global singleton instance of the AutonomousRecorder.
|
|
113
|
+
* Use this for starting recording sessions without managing class instances manually.
|
|
114
|
+
*/
|
|
115
|
+
export declare const autonomousRecorder: AutonomousRecorder;
|