flowspec 0.1.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/dist/runner.js ADDED
@@ -0,0 +1,418 @@
1
+ import { execSync } from "node:child_process";
2
+ /**
3
+ * Default timeout for assertion retries (in milliseconds)
4
+ */
5
+ export const DEFAULT_TIMEOUT = 5000;
6
+ /**
7
+ * Interval between retry attempts (in milliseconds)
8
+ */
9
+ export const POLL_INTERVAL = 250;
10
+ /**
11
+ * Sleep for specified milliseconds
12
+ */
13
+ function sleep(ms) {
14
+ return new Promise((resolve) => setTimeout(resolve, ms));
15
+ }
16
+ const DEFAULT_BASE_URL = "http://localhost:3456";
17
+ /**
18
+ * Escape a string for safe use in shell commands.
19
+ * Uses single quotes and escapes any single quotes within the string.
20
+ * This prevents command injection via backticks, $(), etc.
21
+ */
22
+ function shellEscape(str) {
23
+ // Single-quote the entire string and escape any embedded single quotes
24
+ // 'foo' -> 'foo'
25
+ // "it's" -> 'it'"'"'s'
26
+ return `'${str.replace(/'/g, "'\"'\"'")}'`;
27
+ }
28
+ /**
29
+ * Generate a unique session name for isolation between test runs
30
+ */
31
+ function generateSessionName() {
32
+ return `flowspec-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
33
+ }
34
+ /**
35
+ * Execute an agent-browser command and return the output
36
+ */
37
+ function execBrowser(command, session) {
38
+ try {
39
+ const fullCommand = `agent-browser --session ${session} ${command}`;
40
+ const result = execSync(fullCommand, {
41
+ encoding: "utf-8",
42
+ timeout: 30000,
43
+ shell: process.env.SHELL || "/bin/sh",
44
+ });
45
+ return result;
46
+ }
47
+ catch (error) {
48
+ const execError = error;
49
+ throw new Error(execError.stderr ||
50
+ execError.stdout ||
51
+ execError.message ||
52
+ "Browser command failed");
53
+ }
54
+ }
55
+ /**
56
+ * Get the current page URL
57
+ */
58
+ function getCurrentUrl(session) {
59
+ return execBrowser('eval "window.location.href"', session).trim();
60
+ }
61
+ /**
62
+ * Get the current page text content
63
+ */
64
+ function getPageContent(session) {
65
+ return execBrowser("snapshot", session);
66
+ }
67
+ /**
68
+ * Get interactive elements with refs
69
+ */
70
+ function getInteractiveSnapshot(session) {
71
+ return execBrowser("snapshot -i", session);
72
+ }
73
+ /**
74
+ * Parse snapshot output to find element ref by text/label
75
+ * Returns the ref (e.g., "@e3") for the matching element
76
+ */
77
+ function findElementRef(snapshot, targetText) {
78
+ const lines = snapshot.split("\n");
79
+ for (const line of lines) {
80
+ // Match lines with refs like: [ref=e3] followed by element info
81
+ // Format examples:
82
+ // - textbox "Email" [ref=e1]
83
+ // - button "Sign In" [ref=e2]
84
+ // - link "Settings" [ref=e5]
85
+ const refMatch = line.match(/\[ref=(\w+)\]/);
86
+ if (!refMatch)
87
+ continue;
88
+ const ref = `@${refMatch[1]}`;
89
+ // Check if this line contains the target text
90
+ // Could be in quotes as label, or as visible text
91
+ if (line.includes(`"${targetText}"`)) {
92
+ return ref;
93
+ }
94
+ // Also check for partial matches (e.g., "Technical Support" in options)
95
+ const quotedTextMatch = line.match(/"([^"]+)"/g);
96
+ if (quotedTextMatch) {
97
+ for (const quoted of quotedTextMatch) {
98
+ const text = quoted.slice(1, -1); // Remove quotes
99
+ if (text === targetText) {
100
+ return ref;
101
+ }
102
+ }
103
+ }
104
+ }
105
+ return null;
106
+ }
107
+ /**
108
+ * Find element ref by label (for form fields)
109
+ * Searches for input/textarea/select with the given label
110
+ */
111
+ function findFieldRefByLabel(snapshot, labelText) {
112
+ const lines = snapshot.split("\n");
113
+ for (const line of lines) {
114
+ const refMatch = line.match(/\[ref=(\w+)\]/);
115
+ if (!refMatch)
116
+ continue;
117
+ // Check for textbox, combobox, or other input types with the label
118
+ const isFormField = line.includes("textbox") ||
119
+ line.includes("combobox") ||
120
+ line.includes("textarea") ||
121
+ line.includes("spinbutton");
122
+ if (isFormField && line.includes(`"${labelText}"`)) {
123
+ return `@${refMatch[1]}`;
124
+ }
125
+ }
126
+ return null;
127
+ }
128
+ /**
129
+ * Execute a visit step
130
+ */
131
+ function executeVisit(url, baseUrl, session) {
132
+ const fullUrl = url.startsWith("http")
133
+ ? url
134
+ : new URL(url, baseUrl).toString();
135
+ execBrowser(`open ${shellEscape(fullUrl)}`, session);
136
+ }
137
+ /**
138
+ * Execute a click step
139
+ */
140
+ function executeClick(targetText, session) {
141
+ const snapshot = getInteractiveSnapshot(session);
142
+ const ref = findElementRef(snapshot, targetText);
143
+ if (!ref) {
144
+ const currentUrl = getCurrentUrl(session);
145
+ throw new Error(`Could not find element with text "${targetText}" on ${currentUrl}`);
146
+ }
147
+ execBrowser(`click ${ref}`, session);
148
+ }
149
+ /**
150
+ * Execute a fill step
151
+ */
152
+ function executeFill(fields, session) {
153
+ const snapshot = getInteractiveSnapshot(session);
154
+ for (const [label, value] of Object.entries(fields)) {
155
+ const ref = findFieldRefByLabel(snapshot, label);
156
+ if (!ref) {
157
+ const currentUrl = getCurrentUrl(session);
158
+ throw new Error(`Could not find field with label "${label}" on ${currentUrl}`);
159
+ }
160
+ // Use fill to clear and set value
161
+ execBrowser(`fill ${ref} ${shellEscape(value)}`, session);
162
+ }
163
+ }
164
+ /**
165
+ * Execute a select step
166
+ */
167
+ function executeSelect(selections, session) {
168
+ const snapshot = getInteractiveSnapshot(session);
169
+ for (const [label, option] of Object.entries(selections)) {
170
+ const ref = findFieldRefByLabel(snapshot, label);
171
+ if (!ref) {
172
+ const currentUrl = getCurrentUrl(session);
173
+ throw new Error(`Could not find select field with label "${label}" on ${currentUrl}`);
174
+ }
175
+ execBrowser(`select ${ref} ${shellEscape(option)}`, session);
176
+ }
177
+ }
178
+ /**
179
+ * Check if text is visible on the page
180
+ * Returns undefined if found, or an error message if not found
181
+ */
182
+ function checkTextVisible(text, session) {
183
+ const content = getPageContent(session);
184
+ if (content.includes(text)) {
185
+ return undefined;
186
+ }
187
+ const currentUrl = getCurrentUrl(session);
188
+ return `Text "${text}" not found on ${currentUrl}`;
189
+ }
190
+ /**
191
+ * Execute a wait_for step with retry/polling
192
+ * Waits until the specified text appears on the page
193
+ */
194
+ async function executeWaitFor(text, session, timeout) {
195
+ // First check: if text is visible, return immediately
196
+ let lastError = checkTextVisible(text, session);
197
+ if (!lastError) {
198
+ return;
199
+ }
200
+ // If timeout is 0, fail immediately
201
+ if (timeout <= 0) {
202
+ throw new Error(lastError);
203
+ }
204
+ // Calculate deadline for retry loop
205
+ const deadline = Date.now() + timeout;
206
+ // Poll loop: sleep, then re-check until found or deadline
207
+ while (Date.now() < deadline) {
208
+ await sleep(POLL_INTERVAL);
209
+ lastError = checkTextVisible(text, session);
210
+ if (!lastError) {
211
+ return;
212
+ }
213
+ }
214
+ // Timeout reached: throw the last error
215
+ throw new Error(`Timeout waiting for text "${text}" to appear (waited ${timeout}ms)`);
216
+ }
217
+ /**
218
+ * Execute a single step
219
+ * Returns a Promise to handle async steps like wait_for
220
+ */
221
+ async function executeStep(step, baseUrl, session, timeout) {
222
+ if ("visit" in step) {
223
+ executeVisit(step.visit, baseUrl, session);
224
+ }
225
+ else if ("click" in step) {
226
+ executeClick(step.click, session);
227
+ }
228
+ else if ("fill" in step) {
229
+ executeFill(step.fill, session);
230
+ }
231
+ else if ("select" in step) {
232
+ executeSelect(step.select, session);
233
+ }
234
+ else if ("wait_for" in step) {
235
+ await executeWaitFor(step.wait_for, session, timeout);
236
+ }
237
+ }
238
+ /**
239
+ * Check a URL assertion
240
+ */
241
+ function assertUrl(expected, session) {
242
+ const actual = getCurrentUrl(session);
243
+ const passed = actual.endsWith(expected) || actual.includes(expected);
244
+ return { passed, actual };
245
+ }
246
+ /**
247
+ * Check a visible assertion
248
+ */
249
+ function assertVisible(text, session) {
250
+ const content = getPageContent(session);
251
+ const passed = content.includes(text);
252
+ return { passed, content };
253
+ }
254
+ /**
255
+ * Check a matches (regex) assertion
256
+ */
257
+ function assertMatches(pattern, session) {
258
+ const content = getPageContent(session);
259
+ const regex = new RegExp(pattern);
260
+ const passed = regex.test(content);
261
+ return { passed, content };
262
+ }
263
+ /**
264
+ * Check a not_visible assertion
265
+ */
266
+ function assertNotVisible(text, session) {
267
+ const content = getPageContent(session);
268
+ const passed = !content.includes(text);
269
+ return { passed, content };
270
+ }
271
+ /**
272
+ * Check a single assertion once (synchronous single-check)
273
+ * Returns error if assertion fails, undefined if it passes
274
+ */
275
+ function checkAssertion(assertion, session) {
276
+ if ("url" in assertion) {
277
+ const result = assertUrl(assertion.url, session);
278
+ if (!result.passed) {
279
+ return {
280
+ message: `URL assertion failed: expected "${assertion.url}" but got "${result.actual}"`,
281
+ assertion,
282
+ };
283
+ }
284
+ }
285
+ else if ("visible" in assertion) {
286
+ const result = assertVisible(assertion.visible, session);
287
+ if (!result.passed) {
288
+ return {
289
+ message: `Visible assertion failed: text "${assertion.visible}" not found on page`,
290
+ assertion,
291
+ };
292
+ }
293
+ }
294
+ else if ("matches" in assertion) {
295
+ try {
296
+ const result = assertMatches(assertion.matches, session);
297
+ if (!result.passed) {
298
+ return {
299
+ message: `Matches assertion failed: pattern "${assertion.matches}" did not match page content`,
300
+ assertion,
301
+ };
302
+ }
303
+ }
304
+ catch (error) {
305
+ const message = error instanceof Error ? error.message : String(error);
306
+ return {
307
+ message: `Matches assertion failed: invalid pattern "${assertion.matches}" - ${message}`,
308
+ assertion,
309
+ };
310
+ }
311
+ }
312
+ else if ("not_visible" in assertion) {
313
+ const result = assertNotVisible(assertion.not_visible, session);
314
+ if (!result.passed) {
315
+ return {
316
+ message: `Not visible assertion failed: text "${assertion.not_visible}" was found on page`,
317
+ assertion,
318
+ };
319
+ }
320
+ }
321
+ return undefined;
322
+ }
323
+ /**
324
+ * Execute a single assertion with retry/polling
325
+ * Wraps checkAssertion in a poll loop until pass or timeout
326
+ * Returns error if assertion fails after all retries, undefined if it passes
327
+ */
328
+ async function executeAssertion(assertion, session, timeout) {
329
+ // First check: if it passes, return immediately (zero overhead)
330
+ let lastError = checkAssertion(assertion, session);
331
+ if (!lastError) {
332
+ return undefined;
333
+ }
334
+ // If timeout is 0, no retry - return the error immediately
335
+ if (timeout <= 0) {
336
+ return lastError;
337
+ }
338
+ // Calculate deadline for retry loop
339
+ const deadline = Date.now() + timeout;
340
+ // Poll loop: sleep, then re-check until pass or deadline
341
+ while (Date.now() < deadline) {
342
+ await sleep(POLL_INTERVAL);
343
+ // Re-check assertion (re-fetches page state from browser)
344
+ lastError = checkAssertion(assertion, session);
345
+ if (!lastError) {
346
+ return undefined;
347
+ }
348
+ }
349
+ // Timeout reached: return the last error
350
+ return lastError;
351
+ }
352
+ /**
353
+ * Close a browser session
354
+ */
355
+ function closeBrowserSession(session) {
356
+ try {
357
+ execBrowser("close", session);
358
+ }
359
+ catch {
360
+ // Ignore errors when closing - session may already be closed
361
+ }
362
+ }
363
+ /**
364
+ * Execute a flow specification and return the result
365
+ * @param flow - The FlowSpec to execute
366
+ * @param options - Optional runner configuration
367
+ * @returns Promise resolving to the FlowResult
368
+ */
369
+ export async function runFlow(flow, options) {
370
+ const startTime = Date.now();
371
+ const baseUrl = options?.baseUrl ?? DEFAULT_BASE_URL;
372
+ const timeout = options?.timeout ?? DEFAULT_TIMEOUT;
373
+ const session = generateSessionName();
374
+ try {
375
+ // Execute all steps
376
+ for (let stepIndex = 0; stepIndex < flow.steps.length; stepIndex++) {
377
+ const step = flow.steps[stepIndex];
378
+ try {
379
+ await executeStep(step, baseUrl, session, timeout);
380
+ }
381
+ catch (error) {
382
+ const errorMessage = error instanceof Error ? error.message : String(error);
383
+ return {
384
+ success: false,
385
+ flowName: flow.name,
386
+ duration: Date.now() - startTime,
387
+ error: {
388
+ message: errorMessage,
389
+ step: stepIndex,
390
+ action: step,
391
+ },
392
+ };
393
+ }
394
+ }
395
+ // Execute all assertions with retry/polling
396
+ for (const assertion of flow.expect) {
397
+ const assertionError = await executeAssertion(assertion, session, timeout);
398
+ if (assertionError) {
399
+ return {
400
+ success: false,
401
+ flowName: flow.name,
402
+ duration: Date.now() - startTime,
403
+ error: assertionError,
404
+ };
405
+ }
406
+ }
407
+ return {
408
+ success: true,
409
+ flowName: flow.name,
410
+ duration: Date.now() - startTime,
411
+ };
412
+ }
413
+ finally {
414
+ // Always close the browser session when done
415
+ closeBrowserSession(session);
416
+ }
417
+ }
418
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"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"}