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,388 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module step-handlers
|
|
3
|
+
* @description
|
|
4
|
+
* StepHandler pattern (A-04) implementation for PromptTest.
|
|
5
|
+
*
|
|
6
|
+
* This module implements the Command/Strategy architectural pattern where each action
|
|
7
|
+
* type (e.g., TAP, SWIPE, VERIFY) is encapsulated in its own independent handler class.
|
|
8
|
+
* By isolating step execution logic into discrete classes, the PromptRunner becomes a
|
|
9
|
+
* thin dispatcher relying on an O(1) map lookup (see STEP_HANDLER_REGISTRY).
|
|
10
|
+
*
|
|
11
|
+
* Adding a new step type requires only implementing a new StepHandler class and
|
|
12
|
+
* registering it, ensuring the core execution engine remains untouched and adhering
|
|
13
|
+
* to the Open/Closed Principle.
|
|
14
|
+
*/
|
|
15
|
+
import { AndroidDriver } from './adb.js';
|
|
16
|
+
import { MemoryEngine } from './memory.js';
|
|
17
|
+
import { UiNode } from './crawler.js';
|
|
18
|
+
import { PromptStep } from './prompt-runner.js';
|
|
19
|
+
/**
|
|
20
|
+
* ExecutionContext provides shared resources and utility methods to StepHandlers.
|
|
21
|
+
* It encapsulates the driver instance, state cache, and common UI interaction logic.
|
|
22
|
+
*/
|
|
23
|
+
export interface ExecutionContext {
|
|
24
|
+
/** The ADB-based Android UI driver used to interact with the device. */
|
|
25
|
+
driver: AndroidDriver;
|
|
26
|
+
/** Memory engine used to record and learn resilient locators over time. */
|
|
27
|
+
memory: MemoryEngine;
|
|
28
|
+
/** Optional device serial number for targeting specific devices via ADB. */
|
|
29
|
+
serial?: string;
|
|
30
|
+
/** Device screen dimensions used for coordinate calculations. */
|
|
31
|
+
screenDimensions: {
|
|
32
|
+
width: number;
|
|
33
|
+
height: number;
|
|
34
|
+
};
|
|
35
|
+
/** Height of the navigation bar, used to prevent interacting with system overlays. */
|
|
36
|
+
navBarHeight: number;
|
|
37
|
+
/** Cached snapshot of the last known UI hierarchy to accelerate operations. */
|
|
38
|
+
lastHierarchy: {
|
|
39
|
+
xml: string;
|
|
40
|
+
flat: UiNode[];
|
|
41
|
+
timestamp: number;
|
|
42
|
+
hash?: string;
|
|
43
|
+
} | null;
|
|
44
|
+
/** Caches the provided hierarchy snapshot for subsequent steps. */
|
|
45
|
+
setLastHierarchy(h: {
|
|
46
|
+
xml: string;
|
|
47
|
+
flat: UiNode[];
|
|
48
|
+
timestamp: number;
|
|
49
|
+
hash?: string;
|
|
50
|
+
} | null): void;
|
|
51
|
+
/** Fetches a fresh UI hierarchy directly from the device. */
|
|
52
|
+
getCleanHierarchy(serial?: string): Promise<{
|
|
53
|
+
xml: string;
|
|
54
|
+
flat: UiNode[];
|
|
55
|
+
}>;
|
|
56
|
+
/** Polls for a specific target node until it appears or times out. */
|
|
57
|
+
waitForTarget(target: string, serial?: string, timeoutMs?: number, step?: PromptStep): Promise<{
|
|
58
|
+
flat: UiNode[];
|
|
59
|
+
matched: UiNode[];
|
|
60
|
+
}>;
|
|
61
|
+
/** Evaluates nodes against a natural language query or semantic pattern. */
|
|
62
|
+
matchNodes(nodes: UiNode[], query: string, step?: PromptStep): UiNode[];
|
|
63
|
+
/** Checks if a node is visible, scrolling the viewport if necessary. */
|
|
64
|
+
ensureInViewport(node: UiNode, serial?: string): Promise<boolean>;
|
|
65
|
+
/** Generates rich, contextual errors when a step fails. */
|
|
66
|
+
buildDiagnosticError(target: string, flat: UiNode[], context: string): Error;
|
|
67
|
+
/** Specialized locator for finding form inputs, prioritizing matching hints or labels. */
|
|
68
|
+
findTargetInputField(nodes: UiNode[], target: string, value?: string): UiNode | null;
|
|
69
|
+
/** Future steps in the current script, used for fast-forward lookahead optimizations. */
|
|
70
|
+
upcomingSteps?: PromptStep[];
|
|
71
|
+
/** Live mutable variables map for storing and interpolating $var values across steps. */
|
|
72
|
+
variables: Map<string, string>;
|
|
73
|
+
/** Stack tracking nested loop executions to prevent infinite recursion. */
|
|
74
|
+
loopStack: Array<{
|
|
75
|
+
current: number;
|
|
76
|
+
total: number;
|
|
77
|
+
variable?: string;
|
|
78
|
+
}>;
|
|
79
|
+
/** Callback to execute a sequence of child steps (e.g. inside IF or LOOP). */
|
|
80
|
+
executeChildSteps?(steps: PromptStep[], ctx: ExecutionContext): Promise<void>;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Represents the outcome of a StepHandler's execution.
|
|
84
|
+
*/
|
|
85
|
+
export interface StepResult {
|
|
86
|
+
/** Indicates if the step was bypassed because its desired state was already met. */
|
|
87
|
+
fastForwarded?: boolean;
|
|
88
|
+
/** Explanation for why the step was fast-forwarded or altered. */
|
|
89
|
+
reason?: string;
|
|
90
|
+
/** Number of upcoming steps to skip if fast-forwarded over multiple actions. */
|
|
91
|
+
skipCount?: number;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The base interface for all action handlers.
|
|
95
|
+
* Enforces a strict contract for dispatching PromptStep instructions.
|
|
96
|
+
*/
|
|
97
|
+
export interface StepHandler {
|
|
98
|
+
/** The specific PromptStep type this handler is responsible for (e.g., 'TAP'). */
|
|
99
|
+
readonly type: PromptStep['type'];
|
|
100
|
+
/**
|
|
101
|
+
* Executes the step using the provided context.
|
|
102
|
+
*
|
|
103
|
+
* @param step - The parsed step instruction to execute.
|
|
104
|
+
* @param ctx - The execution context providing driver and utility access.
|
|
105
|
+
* @returns A promise resolving to a StepResult, or void if standard execution completes.
|
|
106
|
+
* @throws Will throw if the step cannot be completed (e.g., element not found).
|
|
107
|
+
*/
|
|
108
|
+
execute(step: PromptStep, ctx: ExecutionContext): Promise<StepResult | void>;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Handles TAP actions by finding the target element and simulating a single touch event.
|
|
112
|
+
* Incorporates fast-forwarding and auto-scrolling optimizations.
|
|
113
|
+
*/
|
|
114
|
+
export declare class TapHandler implements StepHandler {
|
|
115
|
+
readonly type: "TAP";
|
|
116
|
+
/**
|
|
117
|
+
* Executes the TAP step.
|
|
118
|
+
* @param step - The step instruction.
|
|
119
|
+
* @param ctx - The execution context.
|
|
120
|
+
*/
|
|
121
|
+
execute(step: PromptStep, ctx: ExecutionContext): Promise<StepResult | void>;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Handles LONG_PRESS actions by pressing and holding on a target element.
|
|
125
|
+
*/
|
|
126
|
+
export declare class LongPressHandler implements StepHandler {
|
|
127
|
+
readonly type: "LONG_PRESS";
|
|
128
|
+
/**
|
|
129
|
+
* Executes the LONG_PRESS step.
|
|
130
|
+
* @param step - The step instruction.
|
|
131
|
+
* @param ctx - The execution context.
|
|
132
|
+
*/
|
|
133
|
+
execute(step: PromptStep, ctx: ExecutionContext): Promise<void>;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Handles TYPE actions to input text into form fields.
|
|
137
|
+
* Manages focus, clearing existing text, and keyboard interactions.
|
|
138
|
+
*/
|
|
139
|
+
export declare class TypeHandler implements StepHandler {
|
|
140
|
+
readonly type: "TYPE";
|
|
141
|
+
/**
|
|
142
|
+
* Executes the TYPE step.
|
|
143
|
+
* @param step - The step instruction.
|
|
144
|
+
* @param ctx - The execution context.
|
|
145
|
+
*/
|
|
146
|
+
execute(step: PromptStep, ctx: ExecutionContext): Promise<StepResult | void>;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Handles CLEAR actions to empty an input field.
|
|
150
|
+
* Locates the target input, taps to focus, and clears its contents.
|
|
151
|
+
*/
|
|
152
|
+
export declare class ClearHandler implements StepHandler {
|
|
153
|
+
readonly type: "CLEAR";
|
|
154
|
+
/**
|
|
155
|
+
* Executes the CLEAR step.
|
|
156
|
+
* @param step - The step instruction.
|
|
157
|
+
* @param ctx - The execution context.
|
|
158
|
+
*/
|
|
159
|
+
execute(step: PromptStep, ctx: ExecutionContext): Promise<void>;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Handles VERIFY actions to assert the presence or state of elements on the screen.
|
|
163
|
+
*/
|
|
164
|
+
export declare class VerifyHandler implements StepHandler {
|
|
165
|
+
readonly type: "VERIFY";
|
|
166
|
+
/**
|
|
167
|
+
* Executes the VERIFY step.
|
|
168
|
+
* @param step - The step instruction.
|
|
169
|
+
* @param ctx - The execution context.
|
|
170
|
+
*/
|
|
171
|
+
execute(step: PromptStep, ctx: ExecutionContext): Promise<StepResult | void>;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Handles BACK actions by simulating a hardware back button press.
|
|
175
|
+
*/
|
|
176
|
+
export declare class BackHandler implements StepHandler {
|
|
177
|
+
readonly type: "BACK";
|
|
178
|
+
/**
|
|
179
|
+
* Executes the BACK step.
|
|
180
|
+
* @param step - The step instruction.
|
|
181
|
+
* @param ctx - The execution context.
|
|
182
|
+
*/
|
|
183
|
+
execute(_step: PromptStep, ctx: ExecutionContext): Promise<void>;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Handles SCROLL actions to navigate through lists or pages.
|
|
187
|
+
*/
|
|
188
|
+
export declare class ScrollHandler implements StepHandler {
|
|
189
|
+
readonly type: "SCROLL";
|
|
190
|
+
/**
|
|
191
|
+
* Executes the SCROLL step.
|
|
192
|
+
* @param step - The step instruction.
|
|
193
|
+
* @param ctx - The execution context.
|
|
194
|
+
*/
|
|
195
|
+
execute(step: PromptStep, ctx: ExecutionContext): Promise<void>;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Handles SWIPE actions to perform directional swipe gestures on the screen or specific elements.
|
|
199
|
+
*/
|
|
200
|
+
export declare class SwipeHandler implements StepHandler {
|
|
201
|
+
readonly type: "SWIPE";
|
|
202
|
+
/**
|
|
203
|
+
* Executes the SWIPE step.
|
|
204
|
+
* @param step - The step instruction.
|
|
205
|
+
* @param ctx - The execution context.
|
|
206
|
+
*/
|
|
207
|
+
execute(step: PromptStep, ctx: ExecutionContext): Promise<void>;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Handles TOGGLE actions for checkboxes and switches, ensuring the element reaches the desired state.
|
|
211
|
+
*/
|
|
212
|
+
export declare class ToggleHandler implements StepHandler {
|
|
213
|
+
readonly type: "TOGGLE";
|
|
214
|
+
/**
|
|
215
|
+
* Executes the TOGGLE step.
|
|
216
|
+
* @param step - The step instruction.
|
|
217
|
+
* @param ctx - The execution context.
|
|
218
|
+
*/
|
|
219
|
+
execute(step: PromptStep, ctx: ExecutionContext): Promise<void>;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Handles SELECT actions to choose an option from a dropdown or picker modal.
|
|
223
|
+
*/
|
|
224
|
+
export declare class SelectHandler implements StepHandler {
|
|
225
|
+
readonly type: "SELECT";
|
|
226
|
+
/**
|
|
227
|
+
* Executes the SELECT step.
|
|
228
|
+
* @param step - The step instruction.
|
|
229
|
+
* @param ctx - The execution context.
|
|
230
|
+
*/
|
|
231
|
+
execute(step: PromptStep, ctx: ExecutionContext): Promise<void>;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Handles LAUNCH_APP actions by starting the application via its package name.
|
|
235
|
+
*/
|
|
236
|
+
export declare class LaunchAppHandler implements StepHandler {
|
|
237
|
+
readonly type: "LAUNCH_APP";
|
|
238
|
+
/**
|
|
239
|
+
* Executes the LAUNCH_APP step.
|
|
240
|
+
* @param step - The step instruction.
|
|
241
|
+
* @param ctx - The execution context.
|
|
242
|
+
*/
|
|
243
|
+
execute(step: PromptStep, ctx: ExecutionContext): Promise<void>;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Handles RESTART_APP actions by forcefully stopping and then relaunching the app.
|
|
247
|
+
*/
|
|
248
|
+
export declare class RestartAppHandler implements StepHandler {
|
|
249
|
+
readonly type: "RESTART_APP";
|
|
250
|
+
/**
|
|
251
|
+
* Executes the RESTART_APP step.
|
|
252
|
+
* @param step - The step instruction.
|
|
253
|
+
* @param ctx - The execution context.
|
|
254
|
+
*/
|
|
255
|
+
execute(step: PromptStep, ctx: ExecutionContext): Promise<void>;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Handles TERMINATE_APP actions by forcefully stopping the application.
|
|
259
|
+
*/
|
|
260
|
+
export declare class TerminateAppHandler implements StepHandler {
|
|
261
|
+
readonly type: "TERMINATE_APP";
|
|
262
|
+
/**
|
|
263
|
+
* Executes the TERMINATE_APP step.
|
|
264
|
+
* @param step - The step instruction.
|
|
265
|
+
* @param ctx - The execution context.
|
|
266
|
+
*/
|
|
267
|
+
execute(step: PromptStep, ctx: ExecutionContext): Promise<void>;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Handles CLEAR_DATA actions by wiping the application's local data and cache.
|
|
271
|
+
*/
|
|
272
|
+
export declare class ClearDataHandler implements StepHandler {
|
|
273
|
+
readonly type: "CLEAR_DATA";
|
|
274
|
+
/**
|
|
275
|
+
* Executes the CLEAR_DATA step.
|
|
276
|
+
* @param step - The step instruction.
|
|
277
|
+
* @param ctx - The execution context.
|
|
278
|
+
*/
|
|
279
|
+
execute(step: PromptStep, ctx: ExecutionContext): Promise<void>;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Handles GRANT_PERMISSION actions to grant specific runtime permissions to the app.
|
|
283
|
+
*/
|
|
284
|
+
export declare class GrantPermissionHandler implements StepHandler {
|
|
285
|
+
readonly type: "GRANT_PERMISSION";
|
|
286
|
+
/**
|
|
287
|
+
* Executes the GRANT_PERMISSION step.
|
|
288
|
+
* @param step - The step instruction.
|
|
289
|
+
* @param ctx - The execution context.
|
|
290
|
+
*/
|
|
291
|
+
execute(step: PromptStep, ctx: ExecutionContext): Promise<void>;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Handles DEEP_LINK actions by opening a URI scheme or Intent.
|
|
295
|
+
*/
|
|
296
|
+
export declare class DeepLinkHandler implements StepHandler {
|
|
297
|
+
readonly type: "DEEP_LINK";
|
|
298
|
+
/**
|
|
299
|
+
* Executes the DEEP_LINK step.
|
|
300
|
+
* @param step - The step instruction.
|
|
301
|
+
* @param ctx - The execution context.
|
|
302
|
+
*/
|
|
303
|
+
execute(step: PromptStep, ctx: ExecutionContext): Promise<void>;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Handles WAIT actions by pausing execution for a specified duration.
|
|
307
|
+
*/
|
|
308
|
+
export declare class WaitHandler implements StepHandler {
|
|
309
|
+
readonly type: "WAIT";
|
|
310
|
+
/**
|
|
311
|
+
* Executes the WAIT step.
|
|
312
|
+
* @param step - The step instruction.
|
|
313
|
+
* @param _ctx - The execution context.
|
|
314
|
+
*/
|
|
315
|
+
execute(step: PromptStep, _ctx: ExecutionContext): Promise<void>;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Handles conditional branching based on UI element presence.
|
|
319
|
+
* Executes thenSteps if visible, or elseSteps if present and element not found.
|
|
320
|
+
*/
|
|
321
|
+
export declare class ConditionalHandler implements StepHandler {
|
|
322
|
+
readonly type: "IF_VISIBLE";
|
|
323
|
+
execute(step: PromptStep, ctx: ExecutionContext): Promise<void>;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Handles iterative execution of child steps with loop bound protections.
|
|
327
|
+
*/
|
|
328
|
+
export declare class LoopHandler implements StepHandler {
|
|
329
|
+
readonly type: "LOOP";
|
|
330
|
+
execute(step: PromptStep, ctx: ExecutionContext): Promise<void>;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Polls for an element to appear or become enabled without failing immediately.
|
|
334
|
+
*/
|
|
335
|
+
export declare class WaitUntilHandler implements StepHandler {
|
|
336
|
+
readonly type: "WAIT_UNTIL";
|
|
337
|
+
execute(step: PromptStep, ctx: ExecutionContext): Promise<void>;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Sets dynamic variables in the execution context for interpolation into subsequent steps.
|
|
341
|
+
*/
|
|
342
|
+
export declare class SetVariableHandler implements StepHandler {
|
|
343
|
+
readonly type: "SET_VARIABLE";
|
|
344
|
+
execute(step: PromptStep, ctx: ExecutionContext): Promise<void>;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Executes hardware and connectivity controls (Wi-Fi, Airplane mode, Orientation, Notifications).
|
|
348
|
+
*/
|
|
349
|
+
export declare class DeviceStateHandler implements StepHandler {
|
|
350
|
+
readonly type: "DEVICE_STATE";
|
|
351
|
+
execute(step: PromptStep, ctx: ExecutionContext): Promise<void>;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Executes a sandboxed JavaScript snippet for runtime calculations or variable manipulation.
|
|
355
|
+
*/
|
|
356
|
+
export declare class RunJsHandler implements StepHandler {
|
|
357
|
+
readonly type: "RUN_JS";
|
|
358
|
+
execute(step: PromptStep, ctx: ExecutionContext): Promise<void>;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Handles automatic capture and input of One-Time Passwords (OTP) and 2FA codes.
|
|
362
|
+
* Reads codes from mock environment variables or live ADB logcat streams.
|
|
363
|
+
*/
|
|
364
|
+
export declare class OtpHandler implements StepHandler {
|
|
365
|
+
readonly type: "ENTER_OTP";
|
|
366
|
+
execute(step: PromptStep, ctx: ExecutionContext): Promise<StepResult | void>;
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Handles HTTP requests and API assertions within a test flow.
|
|
370
|
+
* Capable of extracting JSON response fields into runtime $variables.
|
|
371
|
+
*/
|
|
372
|
+
export declare class ApiHandler implements StepHandler {
|
|
373
|
+
readonly type: "API_REQUEST";
|
|
374
|
+
execute(step: PromptStep, ctx: ExecutionContext): Promise<void>;
|
|
375
|
+
private resolveJsonPath;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Handles assertions on transactional emails delivered to users during testing.
|
|
379
|
+
*/
|
|
380
|
+
export declare class EmailHandler implements StepHandler {
|
|
381
|
+
readonly type: "EMAIL_ASSERT";
|
|
382
|
+
execute(step: PromptStep, _ctx: ExecutionContext): Promise<void>;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* STEP_HANDLER_REGISTRY maps step types to their concrete handler implementations.
|
|
386
|
+
* Provides an O(1) lookup for dispatching steps in the PromptRunner.
|
|
387
|
+
*/
|
|
388
|
+
export declare const STEP_HANDLER_REGISTRY: Map<import("./runner-utils.js").PromptStepType, StepHandler>;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# PromptTest Architecture & System Design
|
|
2
|
+
|
|
3
|
+
PromptTest is a zero-code, AI-assisted Android test automation and visual QA framework. It drives native Android devices over ADB without requiring app instrumentation, agent binaries, or server daemons.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. High-Level Architecture Overview
|
|
8
|
+
|
|
9
|
+
PromptTest operates on a modular layered architecture where test scripts written in natural language or AST-driven directives are compiled, bound to live or synthetic data, executed against connected devices via an isolated locking layer, and reported with visual diffs and interactive HTML reports.
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
┌───────────────────────────────────────────────────────────┐
|
|
13
|
+
│ CLI & Runner Interface │
|
|
14
|
+
│ (bin/prompttest.ts, index.ts) │
|
|
15
|
+
└─────────────────────────────┬─────────────────────────────┘
|
|
16
|
+
│
|
|
17
|
+
┌─────────────────────────────▼─────────────────────────────┐
|
|
18
|
+
│ Compilation & Parsing │
|
|
19
|
+
│ lib/runner-utils.ts (AST, Parser, Includes) │
|
|
20
|
+
│ lib/data-loader.ts (Dynamic generators, CSV/JSON) │
|
|
21
|
+
└─────────────────────────────┬─────────────────────────────┘
|
|
22
|
+
│
|
|
23
|
+
┌─────────────────────────────▼─────────────────────────────┐
|
|
24
|
+
│ PromptRunner Orchestrator │
|
|
25
|
+
│ (lib/prompt-runner.ts) │
|
|
26
|
+
└──────┬──────────────────────┬──────────────────────┬──────┘
|
|
27
|
+
│ │ │
|
|
28
|
+
┌──────▼──────────────┐┌──────▼──────────────┐┌──────▼──────────────┐
|
|
29
|
+
│ Modular Handlers ││ Self-Healing & AI ││ Device & Locking │
|
|
30
|
+
│ lib/step-handlers.ts││ lib/memory.ts ││ lib/lock.ts │
|
|
31
|
+
│ (Wait, Tap, Type, ││ lib/patterns.ts ││ lib/adb.ts │
|
|
32
|
+
│ Cond, Loop, API, ││ lib/ai/ ││ lib/ios-driver.ts │
|
|
33
|
+
│ OTP, Email, Check) ││ (LLM & Vision) ││ │
|
|
34
|
+
└─────────────────────┘└─────────────────────┘└─────────────────────┘
|
|
35
|
+
│ │ │
|
|
36
|
+
┌──────▼──────────────────────▼──────────────────────▼──────┐
|
|
37
|
+
│ Visual Testing & Diagnostics │
|
|
38
|
+
│ lib/baseline.ts (SSIM / Perceptual Diff) │
|
|
39
|
+
│ lib/explorer.ts (Autonomous Crawler) │
|
|
40
|
+
└─────────────────────────────┬─────────────────────────────┘
|
|
41
|
+
│
|
|
42
|
+
┌─────────────────────────────▼─────────────────────────────┐
|
|
43
|
+
│ Reporting & Observability │
|
|
44
|
+
│ lib/reporter.ts (HTML, JSON, JUnit XML, Markdown) │
|
|
45
|
+
│ lib/live-server.ts (SSE / WebSocket Live Dash) │
|
|
46
|
+
└───────────────────────────────────────────────────────────┘
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 2. Core Modules & Responsibilities
|
|
52
|
+
|
|
53
|
+
### 2.1 PromptRunner Orchestrator (`lib/prompt-runner.ts`)
|
|
54
|
+
|
|
55
|
+
The `PromptRunner` class coordinates the full lifecycle of test execution:
|
|
56
|
+
|
|
57
|
+
- **Device Provisioning & Locking**: Acquires exclusive locks (`lib/lock.ts`) from device pools or the default ADB device.
|
|
58
|
+
- **Spec Resolution**: Loads script files, resolves data-driven iterations (`#!data`, `--iterations`, `--only-row`), expands modular includes (`#include <spec>`), and tokenizes AST step blocks.
|
|
59
|
+
- **Step Execution Loop**: Delegates individual step execution to registered step handlers (`lib/step-handlers.ts`) while handling error collection, retry policies, screenshot capture, and timeout budgets.
|
|
60
|
+
- **Reporting Hook Dispatch**: Triggers lifecycle callbacks (`onStep`, `onComplete`, `onError`) across reporters and live monitors.
|
|
61
|
+
|
|
62
|
+
### 2.2 Runner Utilities & Parser (`lib/runner-utils.ts`)
|
|
63
|
+
|
|
64
|
+
Extracted from the monolithic runner to ensure clean separation of concerns and maintainability:
|
|
65
|
+
|
|
66
|
+
- `parsePrompt(prompt)`: Tokenizes raw natural language statements into typed `PromptStep` AST definitions with action, target, value, timeout, and regex parameters.
|
|
67
|
+
- `assembleAstBlocks(lines)`: Assembles structured nested blocks (conditionals `IF...ELSE...ENDIF`, loops `LOOP...ENDLOOP`, wait-untils `WAIT_UNTIL...ENDWAIT`) into hierarchical AST trees.
|
|
68
|
+
- `expandSpecIncludes(specPath, visited)`: Recursively resolves and flattens `#include <subspec.txt>` directives with circular dependency detection.
|
|
69
|
+
- `buildDiagnosticError(...)`: Enriches execution failures with element dumps, screenshot paths, and suggested locator fixes.
|
|
70
|
+
- `findTargetInputField(tree, label)` & `matchNodes(tree, query)`: Spatial and attribute-based UI hierarchy matching algorithms.
|
|
71
|
+
|
|
72
|
+
### 2.3 Modular Step Handlers (`lib/step-handlers.ts`)
|
|
73
|
+
|
|
74
|
+
Instead of an unwieldy switch-case statement, execution is delegated to decoupled, single-responsibility handlers:
|
|
75
|
+
|
|
76
|
+
- **Primitive Action Handlers**: `WaitHandler`, `TapHandler`, `TypeHandler`, `VerifyHandler`, `SwipeHandler`, `KeyEventHandler`.
|
|
77
|
+
- **Flow Control Handlers**: `ConditionalHandler` (boolean element visibility checks), `LoopHandler` (fixed or dynamic iteration loops), `WaitUntilHandler` (polling with timeout), `SetVariableHandler`, `RunJsHandler` (sandboxed JavaScript expressions via `node:vm`).
|
|
78
|
+
- **Integration Handlers**:
|
|
79
|
+
- `OtpHandler`: Extracts verification codes from local mock stores, environment variables, or live SMS/email inboxes.
|
|
80
|
+
- `ApiHandler`: Dispatches synchronous REST/HTTP assertions (`status`, `jsonPath`, `headers`) directly within the test pipeline.
|
|
81
|
+
- `EmailHandler`: Asserts transactional email delivery and body content against test stores.
|
|
82
|
+
- **State & Checkpoint Handlers**: `DeviceActionHandler` (network, airplane mode, orientation, notifications), `CheckpointHandler` (named state saves and rollback).
|
|
83
|
+
|
|
84
|
+
### 2.4 Data-Driven Engine (`lib/data-loader.ts` & `lib/form-filler.ts`)
|
|
85
|
+
|
|
86
|
+
- **Iterative Testing**: Loads parameter matrices from CSV, JSON, or inline `#!data` tables.
|
|
87
|
+
- **Dynamic Generators**: In-line variable expansion for synthetic data generation:
|
|
88
|
+
- `$random.firstName`, `$random.lastName`, `$random.email`, `$random.phone`
|
|
89
|
+
- `$random.string(len)`, `$random.number(min, max)`
|
|
90
|
+
- `$uuid` (v4 UUID)
|
|
91
|
+
- `$seq.id` (monotonically incrementing sequence)
|
|
92
|
+
- `$date.now`, `$date.iso`, `$date.format(...)`
|
|
93
|
+
- `$calc(expression)`: Runtime arithmetic evaluation.
|
|
94
|
+
|
|
95
|
+
### 2.5 Hardware & Device Layer (`lib/adb.ts`, `lib/lock.ts`, `lib/ios-driver.ts`)
|
|
96
|
+
|
|
97
|
+
- `lib/adb.ts`: Wraps Android Debug Bridge commands (`shell input`, `uiautomator dump`, `screencap`, `install`, `forward`, Wi-Fi, airplane mode, orientation).
|
|
98
|
+
- `lib/lock.ts`: File-locking (`flock`/lockfile) mechanism enabling parallel worker execution across multi-device test farms (`--device-pool dev1,dev2`) without device collision.
|
|
99
|
+
- `lib/ios-driver.ts`: Implements `DriverInterface` for Apple iOS physical devices and Simulators via `idb` and `xcrun simctl`.
|
|
100
|
+
|
|
101
|
+
### 2.6 Visual Baselines & Computer Vision (`lib/baseline.ts`, `lib/explorer.ts`)
|
|
102
|
+
|
|
103
|
+
- Pixel-by-pixel perceptual diffing and Structural Similarity Index Measure (SSIM) algorithms.
|
|
104
|
+
- Configurable failure thresholds (e.g. `diffThreshold: 0.02` for 2% variance).
|
|
105
|
+
- Automatic bounding box masking for dynamic regions (e.g. status bar clocks, live feeds) to eliminate false positives in visual regression testing.
|
|
106
|
+
|
|
107
|
+
### 2.7 Self-Healing & Memory (`lib/memory.ts`, `lib/ai/`)
|
|
108
|
+
|
|
109
|
+
- Persistent memory storage (`.prompttest/memory.json`) mapping natural language queries to confirmed UI element identifiers (`resource-id`, `content-desc`, text).
|
|
110
|
+
- Autonomous self-healing: When an element locator shifts or fails, PromptTest queries the memory cache and fuzzy synonym dictionary (`lib/dictionary.ts`), falling back to optional LLM/Vision providers (`lib/ai/llm-provider.ts`) to repair the locator automatically.
|
|
111
|
+
|
|
112
|
+
### 2.8 Observability & Reporting (`lib/reporter.ts`, `lib/live-server.ts`)
|
|
113
|
+
|
|
114
|
+
- Multi-format report generation: Interactive standalone HTML dashboards with embedded base64 screenshots, JSON execution summaries, JUnit XML (for CI/CD pipelines like GitHub Actions and GitLab CI), and Markdown summaries.
|
|
115
|
+
- Real-time event streaming (`lib/live-server.ts`) for browser dashboards and CI progress logs.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## 3. Execution Data Flow
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
[Spec File (.txt)]
|
|
123
|
+
│
|
|
124
|
+
▼
|
|
125
|
+
[expandSpecIncludes] ─── Flat Raw Prompt
|
|
126
|
+
│
|
|
127
|
+
▼
|
|
128
|
+
[DataLoader / Generators] ─── Bound Row Variables ($var)
|
|
129
|
+
│
|
|
130
|
+
▼
|
|
131
|
+
[assembleAstBlocks] ─── Hierarchical AST (PromptStep[])
|
|
132
|
+
│
|
|
133
|
+
▼
|
|
134
|
+
[PromptRunner.runStep] ─── Iterates AST nodes
|
|
135
|
+
│
|
|
136
|
+
├─► [Acquire Device Lock]
|
|
137
|
+
├─► [Capture Screen & Dump Hierarchy]
|
|
138
|
+
├─► [Resolve Element via Memory / Crawler / AI]
|
|
139
|
+
├─► [Dispatch to Handler (lib/step-handlers.ts)]
|
|
140
|
+
├─► [Evaluate Baseline Diff if visual step]
|
|
141
|
+
└─► [Emit Events & Record Step Result]
|
|
142
|
+
│
|
|
143
|
+
▼
|
|
144
|
+
[Reporter.generateReport] ─── Output HTML / JSON / XML
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## 4. Design Principles & Non-Functional Guarantees
|
|
150
|
+
|
|
151
|
+
1. **Zero Client Instrumentation**: Target mobile applications require no modified build flavors, no test SDKs, and no debugging permissions beyond standard ADB authorization.
|
|
152
|
+
2. **Deterministic Flow Control**: Programmatic constructs (`IF`, `LOOP`, `WAIT_UNTIL`) execute with predictable time bounds and clear exit conditions.
|
|
153
|
+
3. **Fail-Fast vs. Resilient Execution**: Controlled via CLI flags (`--fail-fast` vs. `--continue-on-failure`), allowing rapid iteration in development or broad test suite discovery in nightly CI runs.
|
|
154
|
+
4. **Strict Modular Decoupling**: File sizes are capped (<1100 lines for core orchestrator), types are strictly enforced without `any` escapes, and modules communicate via well-typed TypeScript interfaces.
|