@showrun/core 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/LICENSE +21 -0
- package/dist/__tests__/dsl-validation.test.d.ts +2 -0
- package/dist/__tests__/dsl-validation.test.d.ts.map +1 -0
- package/dist/__tests__/dsl-validation.test.js +203 -0
- package/dist/__tests__/pack-versioning.test.d.ts +2 -0
- package/dist/__tests__/pack-versioning.test.d.ts.map +1 -0
- package/dist/__tests__/pack-versioning.test.js +165 -0
- package/dist/__tests__/validator.test.d.ts +2 -0
- package/dist/__tests__/validator.test.d.ts.map +1 -0
- package/dist/__tests__/validator.test.js +149 -0
- package/dist/authResilience.d.ts +146 -0
- package/dist/authResilience.d.ts.map +1 -0
- package/dist/authResilience.js +378 -0
- package/dist/browserLauncher.d.ts +74 -0
- package/dist/browserLauncher.d.ts.map +1 -0
- package/dist/browserLauncher.js +159 -0
- package/dist/browserPersistence.d.ts +49 -0
- package/dist/browserPersistence.d.ts.map +1 -0
- package/dist/browserPersistence.js +143 -0
- package/dist/context.d.ts +10 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +30 -0
- package/dist/dsl/builders.d.ts +340 -0
- package/dist/dsl/builders.d.ts.map +1 -0
- package/dist/dsl/builders.js +416 -0
- package/dist/dsl/conditions.d.ts +33 -0
- package/dist/dsl/conditions.d.ts.map +1 -0
- package/dist/dsl/conditions.js +169 -0
- package/dist/dsl/interpreter.d.ts +24 -0
- package/dist/dsl/interpreter.d.ts.map +1 -0
- package/dist/dsl/interpreter.js +491 -0
- package/dist/dsl/stepHandlers.d.ts +32 -0
- package/dist/dsl/stepHandlers.d.ts.map +1 -0
- package/dist/dsl/stepHandlers.js +787 -0
- package/dist/dsl/target.d.ts +28 -0
- package/dist/dsl/target.d.ts.map +1 -0
- package/dist/dsl/target.js +110 -0
- package/dist/dsl/templating.d.ts +21 -0
- package/dist/dsl/templating.d.ts.map +1 -0
- package/dist/dsl/templating.js +73 -0
- package/dist/dsl/types.d.ts +695 -0
- package/dist/dsl/types.d.ts.map +1 -0
- package/dist/dsl/types.js +7 -0
- package/dist/dsl/validation.d.ts +15 -0
- package/dist/dsl/validation.d.ts.map +1 -0
- package/dist/dsl/validation.js +974 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/jsonPackValidator.d.ts +11 -0
- package/dist/jsonPackValidator.d.ts.map +1 -0
- package/dist/jsonPackValidator.js +61 -0
- package/dist/loader.d.ts +35 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +107 -0
- package/dist/networkCapture.d.ts +107 -0
- package/dist/networkCapture.d.ts.map +1 -0
- package/dist/networkCapture.js +390 -0
- package/dist/packUtils.d.ts +36 -0
- package/dist/packUtils.d.ts.map +1 -0
- package/dist/packUtils.js +97 -0
- package/dist/packVersioning.d.ts +25 -0
- package/dist/packVersioning.d.ts.map +1 -0
- package/dist/packVersioning.js +137 -0
- package/dist/runner.d.ts +62 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +170 -0
- package/dist/types.d.ts +336 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/validator.d.ts +20 -0
- package/dist/validator.d.ts.map +1 -0
- package/dist/validator.js +68 -0
- package/package.json +49 -0
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builder functions for creating DSL steps.
|
|
3
|
+
* These return plain objects that are JSON-serializable.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Helper builders for creating Target objects
|
|
7
|
+
*/
|
|
8
|
+
export function targetCss(selector) {
|
|
9
|
+
return { kind: 'css', selector };
|
|
10
|
+
}
|
|
11
|
+
export function targetText(text, exact) {
|
|
12
|
+
return { kind: 'text', text, exact };
|
|
13
|
+
}
|
|
14
|
+
export function targetRole(role, name, exact) {
|
|
15
|
+
return { kind: 'role', role, name, exact };
|
|
16
|
+
}
|
|
17
|
+
export function targetLabel(text, exact) {
|
|
18
|
+
return { kind: 'label', text, exact };
|
|
19
|
+
}
|
|
20
|
+
export function targetPlaceholder(text, exact) {
|
|
21
|
+
return { kind: 'placeholder', text, exact };
|
|
22
|
+
}
|
|
23
|
+
export function targetAltText(text, exact) {
|
|
24
|
+
return { kind: 'altText', text, exact };
|
|
25
|
+
}
|
|
26
|
+
export function targetTestId(id) {
|
|
27
|
+
return { kind: 'testId', id };
|
|
28
|
+
}
|
|
29
|
+
export function targetAnyOf(...targets) {
|
|
30
|
+
return { anyOf: targets };
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Helper builders for creating SkipCondition objects
|
|
34
|
+
*/
|
|
35
|
+
export const conditions = {
|
|
36
|
+
/**
|
|
37
|
+
* Skip if URL includes the given string
|
|
38
|
+
*/
|
|
39
|
+
urlIncludes(value) {
|
|
40
|
+
return { url_includes: value };
|
|
41
|
+
},
|
|
42
|
+
/**
|
|
43
|
+
* Skip if URL matches the given regex pattern
|
|
44
|
+
*/
|
|
45
|
+
urlMatches(pattern) {
|
|
46
|
+
return { url_matches: pattern };
|
|
47
|
+
},
|
|
48
|
+
/**
|
|
49
|
+
* Skip if element is visible
|
|
50
|
+
*/
|
|
51
|
+
elementVisible(target) {
|
|
52
|
+
return { element_visible: target };
|
|
53
|
+
},
|
|
54
|
+
/**
|
|
55
|
+
* Skip if element exists in DOM
|
|
56
|
+
*/
|
|
57
|
+
elementExists(target) {
|
|
58
|
+
return { element_exists: target };
|
|
59
|
+
},
|
|
60
|
+
/**
|
|
61
|
+
* Skip if variable equals the given value
|
|
62
|
+
*/
|
|
63
|
+
varEquals(name, value) {
|
|
64
|
+
return { var_equals: { name, value } };
|
|
65
|
+
},
|
|
66
|
+
/**
|
|
67
|
+
* Skip if variable is truthy
|
|
68
|
+
*/
|
|
69
|
+
varTruthy(name) {
|
|
70
|
+
return { var_truthy: name };
|
|
71
|
+
},
|
|
72
|
+
/**
|
|
73
|
+
* Skip if variable is falsy
|
|
74
|
+
*/
|
|
75
|
+
varFalsy(name) {
|
|
76
|
+
return { var_falsy: name };
|
|
77
|
+
},
|
|
78
|
+
/**
|
|
79
|
+
* Skip if ALL conditions are true (AND)
|
|
80
|
+
*/
|
|
81
|
+
all(...conditions) {
|
|
82
|
+
return { all: conditions };
|
|
83
|
+
},
|
|
84
|
+
/**
|
|
85
|
+
* Skip if ANY condition is true (OR)
|
|
86
|
+
*/
|
|
87
|
+
any(...conditions) {
|
|
88
|
+
return { any: conditions };
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Creates a navigate step
|
|
93
|
+
*/
|
|
94
|
+
export function navigate(id, params) {
|
|
95
|
+
return {
|
|
96
|
+
id,
|
|
97
|
+
type: 'navigate',
|
|
98
|
+
label: params.label,
|
|
99
|
+
timeoutMs: params.timeoutMs,
|
|
100
|
+
optional: params.optional,
|
|
101
|
+
onError: params.onError,
|
|
102
|
+
params: {
|
|
103
|
+
url: params.url,
|
|
104
|
+
waitUntil: params.waitUntil ?? 'networkidle',
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Creates an extract_title step
|
|
110
|
+
*/
|
|
111
|
+
export function extractTitle(id, params) {
|
|
112
|
+
return {
|
|
113
|
+
id,
|
|
114
|
+
type: 'extract_title',
|
|
115
|
+
label: params.label,
|
|
116
|
+
timeoutMs: params.timeoutMs,
|
|
117
|
+
optional: params.optional,
|
|
118
|
+
onError: params.onError,
|
|
119
|
+
params: {
|
|
120
|
+
out: params.out,
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Creates an extract_text step
|
|
126
|
+
*/
|
|
127
|
+
export function extractText(id, params) {
|
|
128
|
+
return {
|
|
129
|
+
id,
|
|
130
|
+
type: 'extract_text',
|
|
131
|
+
label: params.label,
|
|
132
|
+
timeoutMs: params.timeoutMs,
|
|
133
|
+
optional: params.optional,
|
|
134
|
+
onError: params.onError,
|
|
135
|
+
params: {
|
|
136
|
+
selector: params.selector,
|
|
137
|
+
target: params.target,
|
|
138
|
+
out: params.out,
|
|
139
|
+
first: params.first ?? true,
|
|
140
|
+
trim: params.trim ?? true,
|
|
141
|
+
default: params.default,
|
|
142
|
+
hint: params.hint,
|
|
143
|
+
scope: params.scope,
|
|
144
|
+
near: params.near,
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Creates a sleep step
|
|
150
|
+
* @deprecated Prefer wait_for for deterministic waiting
|
|
151
|
+
*/
|
|
152
|
+
export function sleep(id, params) {
|
|
153
|
+
return {
|
|
154
|
+
id,
|
|
155
|
+
type: 'sleep',
|
|
156
|
+
label: params.label,
|
|
157
|
+
timeoutMs: params.timeoutMs,
|
|
158
|
+
optional: params.optional,
|
|
159
|
+
onError: params.onError,
|
|
160
|
+
params: {
|
|
161
|
+
durationMs: params.durationMs,
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Creates a wait_for step
|
|
167
|
+
*/
|
|
168
|
+
export function waitFor(id, params) {
|
|
169
|
+
return {
|
|
170
|
+
id,
|
|
171
|
+
type: 'wait_for',
|
|
172
|
+
label: params.label,
|
|
173
|
+
timeoutMs: params.timeoutMs ?? params.timeoutMs,
|
|
174
|
+
optional: params.optional,
|
|
175
|
+
onError: params.onError,
|
|
176
|
+
params: {
|
|
177
|
+
selector: params.selector,
|
|
178
|
+
target: params.target,
|
|
179
|
+
visible: params.visible ?? true,
|
|
180
|
+
url: params.url,
|
|
181
|
+
loadState: params.loadState,
|
|
182
|
+
timeoutMs: params.timeoutMs ?? 30000,
|
|
183
|
+
hint: params.hint,
|
|
184
|
+
scope: params.scope,
|
|
185
|
+
near: params.near,
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Creates a click step
|
|
191
|
+
*/
|
|
192
|
+
export function click(id, params) {
|
|
193
|
+
return {
|
|
194
|
+
id,
|
|
195
|
+
type: 'click',
|
|
196
|
+
label: params.label,
|
|
197
|
+
timeoutMs: params.timeoutMs,
|
|
198
|
+
optional: params.optional,
|
|
199
|
+
onError: params.onError,
|
|
200
|
+
params: {
|
|
201
|
+
selector: params.selector,
|
|
202
|
+
target: params.target,
|
|
203
|
+
first: params.first ?? true,
|
|
204
|
+
waitForVisible: params.waitForVisible ?? true,
|
|
205
|
+
hint: params.hint,
|
|
206
|
+
scope: params.scope,
|
|
207
|
+
near: params.near,
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Creates a fill step
|
|
213
|
+
*/
|
|
214
|
+
export function fill(id, params) {
|
|
215
|
+
return {
|
|
216
|
+
id,
|
|
217
|
+
type: 'fill',
|
|
218
|
+
label: params.label,
|
|
219
|
+
timeoutMs: params.timeoutMs,
|
|
220
|
+
optional: params.optional,
|
|
221
|
+
onError: params.onError,
|
|
222
|
+
params: {
|
|
223
|
+
selector: params.selector,
|
|
224
|
+
target: params.target,
|
|
225
|
+
value: params.value,
|
|
226
|
+
first: params.first ?? true,
|
|
227
|
+
clear: params.clear ?? true,
|
|
228
|
+
hint: params.hint,
|
|
229
|
+
scope: params.scope,
|
|
230
|
+
near: params.near,
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Creates an extract_attribute step
|
|
236
|
+
*/
|
|
237
|
+
export function extractAttribute(id, params) {
|
|
238
|
+
return {
|
|
239
|
+
id,
|
|
240
|
+
type: 'extract_attribute',
|
|
241
|
+
label: params.label,
|
|
242
|
+
timeoutMs: params.timeoutMs,
|
|
243
|
+
optional: params.optional,
|
|
244
|
+
onError: params.onError,
|
|
245
|
+
params: {
|
|
246
|
+
selector: params.selector,
|
|
247
|
+
target: params.target,
|
|
248
|
+
attribute: params.attribute,
|
|
249
|
+
out: params.out,
|
|
250
|
+
first: params.first ?? true,
|
|
251
|
+
default: params.default,
|
|
252
|
+
hint: params.hint,
|
|
253
|
+
scope: params.scope,
|
|
254
|
+
near: params.near,
|
|
255
|
+
},
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Creates an assert step
|
|
260
|
+
*/
|
|
261
|
+
export function assert(id, params) {
|
|
262
|
+
return {
|
|
263
|
+
id,
|
|
264
|
+
type: 'assert',
|
|
265
|
+
label: params.label,
|
|
266
|
+
timeoutMs: params.timeoutMs,
|
|
267
|
+
optional: params.optional,
|
|
268
|
+
onError: params.onError,
|
|
269
|
+
params: {
|
|
270
|
+
selector: params.selector,
|
|
271
|
+
target: params.target,
|
|
272
|
+
visible: params.visible,
|
|
273
|
+
textIncludes: params.textIncludes,
|
|
274
|
+
urlIncludes: params.urlIncludes,
|
|
275
|
+
message: params.message,
|
|
276
|
+
hint: params.hint,
|
|
277
|
+
scope: params.scope,
|
|
278
|
+
near: params.near,
|
|
279
|
+
},
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Creates a set_var step
|
|
284
|
+
*/
|
|
285
|
+
export function setVar(id, params) {
|
|
286
|
+
return {
|
|
287
|
+
id,
|
|
288
|
+
type: 'set_var',
|
|
289
|
+
label: params.label,
|
|
290
|
+
timeoutMs: params.timeoutMs,
|
|
291
|
+
optional: params.optional,
|
|
292
|
+
onError: params.onError,
|
|
293
|
+
params: {
|
|
294
|
+
name: params.name,
|
|
295
|
+
value: params.value,
|
|
296
|
+
},
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Creates a select_option step
|
|
301
|
+
*/
|
|
302
|
+
export function selectOption(id, params) {
|
|
303
|
+
return {
|
|
304
|
+
id,
|
|
305
|
+
type: 'select_option',
|
|
306
|
+
label: params.label,
|
|
307
|
+
timeoutMs: params.timeoutMs,
|
|
308
|
+
optional: params.optional,
|
|
309
|
+
onError: params.onError,
|
|
310
|
+
params: {
|
|
311
|
+
selector: params.selector,
|
|
312
|
+
target: params.target,
|
|
313
|
+
value: params.value,
|
|
314
|
+
first: params.first ?? true,
|
|
315
|
+
hint: params.hint,
|
|
316
|
+
scope: params.scope,
|
|
317
|
+
near: params.near,
|
|
318
|
+
},
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Creates a press_key step
|
|
323
|
+
*/
|
|
324
|
+
export function pressKey(id, params) {
|
|
325
|
+
return {
|
|
326
|
+
id,
|
|
327
|
+
type: 'press_key',
|
|
328
|
+
label: params.label,
|
|
329
|
+
timeoutMs: params.timeoutMs,
|
|
330
|
+
optional: params.optional,
|
|
331
|
+
onError: params.onError,
|
|
332
|
+
params: {
|
|
333
|
+
key: params.key,
|
|
334
|
+
selector: params.selector,
|
|
335
|
+
target: params.target,
|
|
336
|
+
times: params.times ?? 1,
|
|
337
|
+
delayMs: params.delayMs ?? 0,
|
|
338
|
+
hint: params.hint,
|
|
339
|
+
scope: params.scope,
|
|
340
|
+
near: params.near,
|
|
341
|
+
},
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Creates an upload_file step
|
|
346
|
+
*/
|
|
347
|
+
export function uploadFile(id, params) {
|
|
348
|
+
return {
|
|
349
|
+
id,
|
|
350
|
+
type: 'upload_file',
|
|
351
|
+
label: params.label,
|
|
352
|
+
timeoutMs: params.timeoutMs,
|
|
353
|
+
optional: params.optional,
|
|
354
|
+
onError: params.onError,
|
|
355
|
+
params: {
|
|
356
|
+
selector: params.selector,
|
|
357
|
+
target: params.target,
|
|
358
|
+
files: params.files,
|
|
359
|
+
first: params.first ?? true,
|
|
360
|
+
hint: params.hint,
|
|
361
|
+
scope: params.scope,
|
|
362
|
+
near: params.near,
|
|
363
|
+
},
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Creates a frame step
|
|
368
|
+
*/
|
|
369
|
+
export function frame(id, params) {
|
|
370
|
+
return {
|
|
371
|
+
id,
|
|
372
|
+
type: 'frame',
|
|
373
|
+
label: params.label,
|
|
374
|
+
timeoutMs: params.timeoutMs,
|
|
375
|
+
optional: params.optional,
|
|
376
|
+
onError: params.onError,
|
|
377
|
+
params: {
|
|
378
|
+
frame: params.frame,
|
|
379
|
+
action: params.action,
|
|
380
|
+
},
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Creates a new_tab step
|
|
385
|
+
*/
|
|
386
|
+
export function newTab(id, params) {
|
|
387
|
+
return {
|
|
388
|
+
id,
|
|
389
|
+
type: 'new_tab',
|
|
390
|
+
label: params.label,
|
|
391
|
+
timeoutMs: params.timeoutMs,
|
|
392
|
+
optional: params.optional,
|
|
393
|
+
onError: params.onError,
|
|
394
|
+
params: {
|
|
395
|
+
url: params.url,
|
|
396
|
+
saveTabIndexAs: params.saveTabIndexAs,
|
|
397
|
+
},
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Creates a switch_tab step
|
|
402
|
+
*/
|
|
403
|
+
export function switchTab(id, params) {
|
|
404
|
+
return {
|
|
405
|
+
id,
|
|
406
|
+
type: 'switch_tab',
|
|
407
|
+
label: params.label,
|
|
408
|
+
timeoutMs: params.timeoutMs,
|
|
409
|
+
optional: params.optional,
|
|
410
|
+
onError: params.onError,
|
|
411
|
+
params: {
|
|
412
|
+
tab: params.tab,
|
|
413
|
+
closeCurrentTab: params.closeCurrentTab ?? false,
|
|
414
|
+
},
|
|
415
|
+
};
|
|
416
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Condition evaluator for skip_if conditions
|
|
3
|
+
*
|
|
4
|
+
* Evaluates skip conditions to determine if a step should be skipped.
|
|
5
|
+
*/
|
|
6
|
+
import type { Page } from 'playwright';
|
|
7
|
+
import type { SkipCondition } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Context for condition evaluation
|
|
10
|
+
*/
|
|
11
|
+
export interface ConditionContext {
|
|
12
|
+
/**
|
|
13
|
+
* Playwright page
|
|
14
|
+
*/
|
|
15
|
+
page: Page;
|
|
16
|
+
/**
|
|
17
|
+
* Current variable values
|
|
18
|
+
*/
|
|
19
|
+
vars: Record<string, unknown>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Evaluates a skip condition
|
|
23
|
+
*
|
|
24
|
+
* @param ctx - Condition context with page and vars
|
|
25
|
+
* @param condition - The condition to evaluate
|
|
26
|
+
* @returns true if the condition is met (step should be skipped), false otherwise
|
|
27
|
+
*/
|
|
28
|
+
export declare function evaluateCondition(ctx: ConditionContext, condition: SkipCondition): Promise<boolean>;
|
|
29
|
+
/**
|
|
30
|
+
* Converts a condition to a human-readable string for logging
|
|
31
|
+
*/
|
|
32
|
+
export declare function conditionToString(condition: SkipCondition): string;
|
|
33
|
+
//# sourceMappingURL=conditions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conditions.d.ts","sourceRoot":"","sources":["../../src/dsl/conditions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,EAAE,aAAa,EAAyB,MAAM,YAAY,CAAC;AAQvE;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,IAAI,EAAE,IAAI,CAAC;IACX;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,gBAAgB,EACrB,SAAS,EAAE,aAAa,GACvB,OAAO,CAAC,OAAO,CAAC,CAgElB;AA2DD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,aAAa,GAAG,MAAM,CA6BlE"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Condition evaluator for skip_if conditions
|
|
3
|
+
*
|
|
4
|
+
* Evaluates skip conditions to determine if a step should be skipped.
|
|
5
|
+
*/
|
|
6
|
+
import { resolveTarget } from './target.js';
|
|
7
|
+
/**
|
|
8
|
+
* Timeout for element checks (1 second - fast fail)
|
|
9
|
+
*/
|
|
10
|
+
const ELEMENT_CHECK_TIMEOUT_MS = 1000;
|
|
11
|
+
/**
|
|
12
|
+
* Evaluates a skip condition
|
|
13
|
+
*
|
|
14
|
+
* @param ctx - Condition context with page and vars
|
|
15
|
+
* @param condition - The condition to evaluate
|
|
16
|
+
* @returns true if the condition is met (step should be skipped), false otherwise
|
|
17
|
+
*/
|
|
18
|
+
export async function evaluateCondition(ctx, condition) {
|
|
19
|
+
// URL conditions
|
|
20
|
+
if ('url_includes' in condition) {
|
|
21
|
+
const currentUrl = ctx.page.url();
|
|
22
|
+
return currentUrl.includes(condition.url_includes);
|
|
23
|
+
}
|
|
24
|
+
if ('url_matches' in condition) {
|
|
25
|
+
const currentUrl = ctx.page.url();
|
|
26
|
+
try {
|
|
27
|
+
const regex = new RegExp(condition.url_matches);
|
|
28
|
+
return regex.test(currentUrl);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
console.warn(`[conditions] Invalid regex in url_matches: ${condition.url_matches}`);
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Element conditions
|
|
36
|
+
if ('element_visible' in condition) {
|
|
37
|
+
return await isElementVisible(ctx.page, condition.element_visible);
|
|
38
|
+
}
|
|
39
|
+
if ('element_exists' in condition) {
|
|
40
|
+
return await elementExists(ctx.page, condition.element_exists);
|
|
41
|
+
}
|
|
42
|
+
// Variable conditions
|
|
43
|
+
if ('var_equals' in condition) {
|
|
44
|
+
const { name, value } = condition.var_equals;
|
|
45
|
+
const actualValue = ctx.vars[name];
|
|
46
|
+
return actualValue === value;
|
|
47
|
+
}
|
|
48
|
+
if ('var_truthy' in condition) {
|
|
49
|
+
const value = ctx.vars[condition.var_truthy];
|
|
50
|
+
return Boolean(value);
|
|
51
|
+
}
|
|
52
|
+
if ('var_falsy' in condition) {
|
|
53
|
+
const value = ctx.vars[condition.var_falsy];
|
|
54
|
+
return !value;
|
|
55
|
+
}
|
|
56
|
+
// Compound conditions
|
|
57
|
+
if ('all' in condition) {
|
|
58
|
+
for (const subCondition of condition.all) {
|
|
59
|
+
const result = await evaluateCondition(ctx, subCondition);
|
|
60
|
+
if (!result)
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
if ('any' in condition) {
|
|
66
|
+
for (const subCondition of condition.any) {
|
|
67
|
+
const result = await evaluateCondition(ctx, subCondition);
|
|
68
|
+
if (result)
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
// Unknown condition type
|
|
74
|
+
console.warn('[conditions] Unknown condition type:', condition);
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Resolves a TargetOrAnyOf to a Playwright Locator
|
|
79
|
+
* Handles both single targets and anyOf arrays
|
|
80
|
+
*/
|
|
81
|
+
function resolveTargetOrAnyOf(page, target) {
|
|
82
|
+
if ('anyOf' in target) {
|
|
83
|
+
// For anyOf, try the first one (we just need to check existence/visibility)
|
|
84
|
+
// The condition is met if ANY of the targets match
|
|
85
|
+
return target.anyOf.map((t) => resolveTarget(page, t));
|
|
86
|
+
}
|
|
87
|
+
return [resolveTarget(page, target)];
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Checks if an element is visible on the page
|
|
91
|
+
*/
|
|
92
|
+
async function isElementVisible(page, target) {
|
|
93
|
+
try {
|
|
94
|
+
const locators = resolveTargetOrAnyOf(page, target);
|
|
95
|
+
// Check if any locator is visible
|
|
96
|
+
for (const locator of locators) {
|
|
97
|
+
try {
|
|
98
|
+
const isVisible = await locator.first().isVisible({ timeout: ELEMENT_CHECK_TIMEOUT_MS });
|
|
99
|
+
if (isVisible)
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// Continue to next locator
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// Element not found or timeout - not visible
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Checks if an element exists in the DOM (visible or not)
|
|
115
|
+
*/
|
|
116
|
+
async function elementExists(page, target) {
|
|
117
|
+
try {
|
|
118
|
+
const locators = resolveTargetOrAnyOf(page, target);
|
|
119
|
+
// Check if any locator has matches
|
|
120
|
+
for (const locator of locators) {
|
|
121
|
+
try {
|
|
122
|
+
const count = await locator.count();
|
|
123
|
+
if (count > 0)
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// Continue to next locator
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
// Error resolving target - doesn't exist
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Converts a condition to a human-readable string for logging
|
|
139
|
+
*/
|
|
140
|
+
export function conditionToString(condition) {
|
|
141
|
+
if ('url_includes' in condition) {
|
|
142
|
+
return `url_includes("${condition.url_includes}")`;
|
|
143
|
+
}
|
|
144
|
+
if ('url_matches' in condition) {
|
|
145
|
+
return `url_matches("${condition.url_matches}")`;
|
|
146
|
+
}
|
|
147
|
+
if ('element_visible' in condition) {
|
|
148
|
+
return `element_visible(${JSON.stringify(condition.element_visible)})`;
|
|
149
|
+
}
|
|
150
|
+
if ('element_exists' in condition) {
|
|
151
|
+
return `element_exists(${JSON.stringify(condition.element_exists)})`;
|
|
152
|
+
}
|
|
153
|
+
if ('var_equals' in condition) {
|
|
154
|
+
return `var_equals(${condition.var_equals.name}, ${JSON.stringify(condition.var_equals.value)})`;
|
|
155
|
+
}
|
|
156
|
+
if ('var_truthy' in condition) {
|
|
157
|
+
return `var_truthy("${condition.var_truthy}")`;
|
|
158
|
+
}
|
|
159
|
+
if ('var_falsy' in condition) {
|
|
160
|
+
return `var_falsy("${condition.var_falsy}")`;
|
|
161
|
+
}
|
|
162
|
+
if ('all' in condition) {
|
|
163
|
+
return `all(${condition.all.map(conditionToString).join(', ')})`;
|
|
164
|
+
}
|
|
165
|
+
if ('any' in condition) {
|
|
166
|
+
return `any(${condition.any.map(conditionToString).join(', ')})`;
|
|
167
|
+
}
|
|
168
|
+
return JSON.stringify(condition);
|
|
169
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { RunContext, AuthConfig } from '../types.js';
|
|
2
|
+
import type { DslStep, RunFlowOptions, RunFlowResult } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Extended options for running a flow with auth resilience
|
|
5
|
+
*/
|
|
6
|
+
export interface RunFlowOptionsWithAuth extends RunFlowOptions {
|
|
7
|
+
inputs?: Record<string, unknown>;
|
|
8
|
+
auth?: AuthConfig;
|
|
9
|
+
sessionId?: string;
|
|
10
|
+
profileId?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Directory for profile cache storage (typically the pack directory)
|
|
13
|
+
*/
|
|
14
|
+
cacheDir?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Secrets for template resolution ({{secret.NAME}})
|
|
17
|
+
*/
|
|
18
|
+
secrets?: Record<string, string>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Runs a flow of DSL steps sequentially with auth resilience support
|
|
22
|
+
*/
|
|
23
|
+
export declare function runFlow(ctx: RunContext, steps: DslStep[], options?: RunFlowOptionsWithAuth): Promise<RunFlowResult>;
|
|
24
|
+
//# sourceMappingURL=interpreter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interpreter.d.ts","sourceRoot":"","sources":["../../src/dsl/interpreter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAa,UAAU,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AA8DzE;;GAEG;AACH,MAAM,WAAW,sBAAuB,SAAQ,cAAc;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAyBD;;GAEG;AACH,wBAAsB,OAAO,CAC3B,GAAG,EAAE,UAAU,EACf,KAAK,EAAE,OAAO,EAAE,EAChB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,aAAa,CAAC,CAybxB"}
|