@questpie/probe 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/agent-browser-Cxuu-Zz0.js +203 -0
- package/dist/assert-BLP5_JwC.js +212 -0
- package/dist/browser-DoCXU5Bs.js +736 -0
- package/dist/check-Cny-3lkZ.js +41 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +30 -0
- package/dist/codegen-BH3cUNuf.js +61 -0
- package/dist/compose-D5a8qHkg.js +233 -0
- package/dist/config-BUEMgFYN.js +89 -0
- package/dist/duration-D1ya1zLn.js +3 -0
- package/dist/duration-DUrbfMLK.js +30 -0
- package/dist/health-B36ufFzJ.js +62 -0
- package/dist/http-BZouO1Cj.js +187 -0
- package/dist/index.d.ts +119 -0
- package/dist/index.js +4 -0
- package/dist/init-BjTfn_-A.js +92 -0
- package/dist/logs-BCgur07G.js +191 -0
- package/dist/output-CHUjdVDf.js +38 -0
- package/dist/process-manager-CzexpFO4.js +229 -0
- package/dist/process-manager-zzltWvZ0.js +4 -0
- package/dist/ps-DuHF7vmE.js +39 -0
- package/dist/record-C4SmoPsT.js +140 -0
- package/dist/recordings-Cb31alos.js +158 -0
- package/dist/replay-Dg9PHNrg.js +171 -0
- package/dist/reporter-CqWc26OP.js +25 -0
- package/dist/restart-By3Edj5X.js +44 -0
- package/dist/snapshot-diff-CqXEVTAZ.js +51 -0
- package/dist/start-BClY6oJq.js +79 -0
- package/dist/state-DRTSIt_r.js +62 -0
- package/dist/stop-QAP6gbDe.js +47 -0
- package/package.json +72 -0
- package/skills/qprobe/SKILL.md +103 -0
- package/skills/qprobe/references/browser.md +201 -0
- package/skills/qprobe/references/compose.md +128 -0
- package/skills/qprobe/references/http.md +151 -0
- package/skills/qprobe/references/process.md +114 -0
- package/skills/qprobe/references/recording.md +194 -0
- package/skills/qprobe-browser/SKILL.md +87 -0
- package/skills/qprobe-compose/SKILL.md +81 -0
- package/skills/qprobe-http/SKILL.md +67 -0
- package/skills/qprobe-process/SKILL.md +58 -0
- package/skills/qprobe-recording/SKILL.md +63 -0
- package/skills/qprobe-ux/SKILL.md +250 -0
|
@@ -0,0 +1,736 @@
|
|
|
1
|
+
import { parseDuration } from "./duration-DUrbfMLK.js";
|
|
2
|
+
import { loadProbeConfig, resolveBaseUrl } from "./config-BUEMgFYN.js";
|
|
3
|
+
import { AgentBrowserDriver } from "./agent-browser-Cxuu-Zz0.js";
|
|
4
|
+
import { error, info, json, log, success } from "./output-CHUjdVDf.js";
|
|
5
|
+
import { defineCommand } from "citty";
|
|
6
|
+
|
|
7
|
+
//#region src/commands/browser.ts
|
|
8
|
+
async function getDriver(args) {
|
|
9
|
+
const config = await loadProbeConfig();
|
|
10
|
+
const driverName = args.driver ?? config.browser?.driver ?? "agent-browser";
|
|
11
|
+
if (driverName !== "agent-browser") {
|
|
12
|
+
error(`Driver "${driverName}" is not yet supported. Use agent-browser.`);
|
|
13
|
+
process.exit(5);
|
|
14
|
+
}
|
|
15
|
+
return new AgentBrowserDriver({
|
|
16
|
+
session: args.session ?? config.browser?.session ?? "qprobe",
|
|
17
|
+
headed: args.headed ?? !(config.browser?.headless ?? true),
|
|
18
|
+
baseUrl: resolveBaseUrl(config)
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
const open = defineCommand({
|
|
22
|
+
meta: {
|
|
23
|
+
name: "open",
|
|
24
|
+
description: "Navigate to URL"
|
|
25
|
+
},
|
|
26
|
+
args: {
|
|
27
|
+
url: {
|
|
28
|
+
type: "positional",
|
|
29
|
+
description: "URL to open",
|
|
30
|
+
required: true
|
|
31
|
+
},
|
|
32
|
+
driver: {
|
|
33
|
+
type: "string",
|
|
34
|
+
description: "Browser driver"
|
|
35
|
+
},
|
|
36
|
+
headed: {
|
|
37
|
+
type: "boolean",
|
|
38
|
+
description: "Show browser window"
|
|
39
|
+
},
|
|
40
|
+
session: {
|
|
41
|
+
type: "string",
|
|
42
|
+
description: "Session name"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
async run({ args }) {
|
|
46
|
+
const driver = await getDriver(args);
|
|
47
|
+
await driver.open(args.url);
|
|
48
|
+
success(`Opened ${args.url}`);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
const back = defineCommand({
|
|
52
|
+
meta: {
|
|
53
|
+
name: "back",
|
|
54
|
+
description: "Go back"
|
|
55
|
+
},
|
|
56
|
+
args: {
|
|
57
|
+
driver: { type: "string" },
|
|
58
|
+
headed: { type: "boolean" },
|
|
59
|
+
session: { type: "string" }
|
|
60
|
+
},
|
|
61
|
+
async run({ args }) {
|
|
62
|
+
const driver = await getDriver(args);
|
|
63
|
+
await driver.back();
|
|
64
|
+
success("Navigated back");
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
const forward = defineCommand({
|
|
68
|
+
meta: {
|
|
69
|
+
name: "forward",
|
|
70
|
+
description: "Go forward"
|
|
71
|
+
},
|
|
72
|
+
args: {
|
|
73
|
+
driver: { type: "string" },
|
|
74
|
+
headed: { type: "boolean" },
|
|
75
|
+
session: { type: "string" }
|
|
76
|
+
},
|
|
77
|
+
async run({ args }) {
|
|
78
|
+
const driver = await getDriver(args);
|
|
79
|
+
await driver.forward();
|
|
80
|
+
success("Navigated forward");
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
const reload = defineCommand({
|
|
84
|
+
meta: {
|
|
85
|
+
name: "reload",
|
|
86
|
+
description: "Reload page"
|
|
87
|
+
},
|
|
88
|
+
args: {
|
|
89
|
+
driver: { type: "string" },
|
|
90
|
+
headed: { type: "boolean" },
|
|
91
|
+
session: { type: "string" }
|
|
92
|
+
},
|
|
93
|
+
async run({ args }) {
|
|
94
|
+
const driver = await getDriver(args);
|
|
95
|
+
await driver.reload();
|
|
96
|
+
success("Reloaded");
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
const url = defineCommand({
|
|
100
|
+
meta: {
|
|
101
|
+
name: "url",
|
|
102
|
+
description: "Print current URL"
|
|
103
|
+
},
|
|
104
|
+
args: {
|
|
105
|
+
driver: { type: "string" },
|
|
106
|
+
headed: { type: "boolean" },
|
|
107
|
+
session: { type: "string" }
|
|
108
|
+
},
|
|
109
|
+
async run({ args }) {
|
|
110
|
+
const driver = await getDriver(args);
|
|
111
|
+
log(await driver.url());
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
const title = defineCommand({
|
|
115
|
+
meta: {
|
|
116
|
+
name: "title",
|
|
117
|
+
description: "Print page title"
|
|
118
|
+
},
|
|
119
|
+
args: {
|
|
120
|
+
driver: { type: "string" },
|
|
121
|
+
headed: { type: "boolean" },
|
|
122
|
+
session: { type: "string" }
|
|
123
|
+
},
|
|
124
|
+
async run({ args }) {
|
|
125
|
+
const driver = await getDriver(args);
|
|
126
|
+
log(await driver.title());
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
const close = defineCommand({
|
|
130
|
+
meta: {
|
|
131
|
+
name: "close",
|
|
132
|
+
description: "Close browser"
|
|
133
|
+
},
|
|
134
|
+
args: {
|
|
135
|
+
driver: { type: "string" },
|
|
136
|
+
headed: { type: "boolean" },
|
|
137
|
+
session: { type: "string" }
|
|
138
|
+
},
|
|
139
|
+
async run({ args }) {
|
|
140
|
+
const driver = await getDriver(args);
|
|
141
|
+
await driver.close();
|
|
142
|
+
success("Browser closed");
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
const snapshot = defineCommand({
|
|
146
|
+
meta: {
|
|
147
|
+
name: "snapshot",
|
|
148
|
+
description: "Get accessibility tree snapshot"
|
|
149
|
+
},
|
|
150
|
+
args: {
|
|
151
|
+
interactive: {
|
|
152
|
+
type: "boolean",
|
|
153
|
+
alias: "i",
|
|
154
|
+
description: "Interactive elements only"
|
|
155
|
+
},
|
|
156
|
+
compact: {
|
|
157
|
+
type: "boolean",
|
|
158
|
+
alias: "c",
|
|
159
|
+
description: "Remove empty structural elements"
|
|
160
|
+
},
|
|
161
|
+
depth: {
|
|
162
|
+
type: "string",
|
|
163
|
+
alias: "d",
|
|
164
|
+
description: "Limit tree depth"
|
|
165
|
+
},
|
|
166
|
+
selector: {
|
|
167
|
+
type: "string",
|
|
168
|
+
alias: "s",
|
|
169
|
+
description: "Scope to CSS selector"
|
|
170
|
+
},
|
|
171
|
+
diff: {
|
|
172
|
+
type: "boolean",
|
|
173
|
+
description: "Show changes since last snapshot"
|
|
174
|
+
},
|
|
175
|
+
driver: { type: "string" },
|
|
176
|
+
headed: { type: "boolean" },
|
|
177
|
+
session: { type: "string" }
|
|
178
|
+
},
|
|
179
|
+
async run({ args }) {
|
|
180
|
+
const driver = await getDriver(args);
|
|
181
|
+
const result = await driver.snapshot({
|
|
182
|
+
interactive: args.interactive,
|
|
183
|
+
compact: args.compact,
|
|
184
|
+
depth: args.depth ? Number(args.depth) : void 0,
|
|
185
|
+
selector: args.selector,
|
|
186
|
+
diff: args.diff
|
|
187
|
+
});
|
|
188
|
+
log(result);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
const click = defineCommand({
|
|
192
|
+
meta: {
|
|
193
|
+
name: "click",
|
|
194
|
+
description: "Click element"
|
|
195
|
+
},
|
|
196
|
+
args: {
|
|
197
|
+
ref: {
|
|
198
|
+
type: "positional",
|
|
199
|
+
description: "Ref (@e1) or CSS selector",
|
|
200
|
+
required: true
|
|
201
|
+
},
|
|
202
|
+
driver: { type: "string" },
|
|
203
|
+
headed: { type: "boolean" },
|
|
204
|
+
session: { type: "string" }
|
|
205
|
+
},
|
|
206
|
+
async run({ args }) {
|
|
207
|
+
const driver = await getDriver(args);
|
|
208
|
+
await driver.click(args.ref);
|
|
209
|
+
success(`Clicked ${args.ref}`);
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
const dblclick = defineCommand({
|
|
213
|
+
meta: {
|
|
214
|
+
name: "dblclick",
|
|
215
|
+
description: "Double-click element"
|
|
216
|
+
},
|
|
217
|
+
args: {
|
|
218
|
+
ref: {
|
|
219
|
+
type: "positional",
|
|
220
|
+
required: true
|
|
221
|
+
},
|
|
222
|
+
driver: { type: "string" },
|
|
223
|
+
headed: { type: "boolean" },
|
|
224
|
+
session: { type: "string" }
|
|
225
|
+
},
|
|
226
|
+
async run({ args }) {
|
|
227
|
+
const driver = await getDriver(args);
|
|
228
|
+
await driver.dblclick(args.ref);
|
|
229
|
+
success(`Double-clicked ${args.ref}`);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
const fill = defineCommand({
|
|
233
|
+
meta: {
|
|
234
|
+
name: "fill",
|
|
235
|
+
description: "Fill input field"
|
|
236
|
+
},
|
|
237
|
+
args: {
|
|
238
|
+
ref: {
|
|
239
|
+
type: "positional",
|
|
240
|
+
description: "Ref or selector",
|
|
241
|
+
required: true
|
|
242
|
+
},
|
|
243
|
+
value: {
|
|
244
|
+
type: "positional",
|
|
245
|
+
description: "Value to fill",
|
|
246
|
+
required: true
|
|
247
|
+
},
|
|
248
|
+
driver: { type: "string" },
|
|
249
|
+
headed: { type: "boolean" },
|
|
250
|
+
session: { type: "string" }
|
|
251
|
+
},
|
|
252
|
+
async run({ args }) {
|
|
253
|
+
const driver = await getDriver(args);
|
|
254
|
+
await driver.fill(args.ref, args.value);
|
|
255
|
+
success(`Filled ${args.ref}`);
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
const selectCmd = defineCommand({
|
|
259
|
+
meta: {
|
|
260
|
+
name: "select",
|
|
261
|
+
description: "Select dropdown value"
|
|
262
|
+
},
|
|
263
|
+
args: {
|
|
264
|
+
ref: {
|
|
265
|
+
type: "positional",
|
|
266
|
+
required: true
|
|
267
|
+
},
|
|
268
|
+
value: {
|
|
269
|
+
type: "positional",
|
|
270
|
+
required: true
|
|
271
|
+
},
|
|
272
|
+
driver: { type: "string" },
|
|
273
|
+
headed: { type: "boolean" },
|
|
274
|
+
session: { type: "string" }
|
|
275
|
+
},
|
|
276
|
+
async run({ args }) {
|
|
277
|
+
const driver = await getDriver(args);
|
|
278
|
+
await driver.select(args.ref, args.value);
|
|
279
|
+
success(`Selected "${args.value}" in ${args.ref}`);
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
const checkCmd = defineCommand({
|
|
283
|
+
meta: {
|
|
284
|
+
name: "check",
|
|
285
|
+
description: "Check checkbox"
|
|
286
|
+
},
|
|
287
|
+
args: {
|
|
288
|
+
ref: {
|
|
289
|
+
type: "positional",
|
|
290
|
+
required: true
|
|
291
|
+
},
|
|
292
|
+
driver: { type: "string" },
|
|
293
|
+
headed: { type: "boolean" },
|
|
294
|
+
session: { type: "string" }
|
|
295
|
+
},
|
|
296
|
+
async run({ args }) {
|
|
297
|
+
const driver = await getDriver(args);
|
|
298
|
+
await driver.check(args.ref);
|
|
299
|
+
success(`Checked ${args.ref}`);
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
const uncheckCmd = defineCommand({
|
|
303
|
+
meta: {
|
|
304
|
+
name: "uncheck",
|
|
305
|
+
description: "Uncheck checkbox"
|
|
306
|
+
},
|
|
307
|
+
args: {
|
|
308
|
+
ref: {
|
|
309
|
+
type: "positional",
|
|
310
|
+
required: true
|
|
311
|
+
},
|
|
312
|
+
driver: { type: "string" },
|
|
313
|
+
headed: { type: "boolean" },
|
|
314
|
+
session: { type: "string" }
|
|
315
|
+
},
|
|
316
|
+
async run({ args }) {
|
|
317
|
+
const driver = await getDriver(args);
|
|
318
|
+
await driver.uncheck(args.ref);
|
|
319
|
+
success(`Unchecked ${args.ref}`);
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
const press = defineCommand({
|
|
323
|
+
meta: {
|
|
324
|
+
name: "press",
|
|
325
|
+
description: "Press keyboard key"
|
|
326
|
+
},
|
|
327
|
+
args: {
|
|
328
|
+
key: {
|
|
329
|
+
type: "positional",
|
|
330
|
+
description: "Key to press (Enter, Tab, Escape...)",
|
|
331
|
+
required: true
|
|
332
|
+
},
|
|
333
|
+
driver: { type: "string" },
|
|
334
|
+
headed: { type: "boolean" },
|
|
335
|
+
session: { type: "string" }
|
|
336
|
+
},
|
|
337
|
+
async run({ args }) {
|
|
338
|
+
const driver = await getDriver(args);
|
|
339
|
+
await driver.press(args.key);
|
|
340
|
+
success(`Pressed ${args.key}`);
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
const typeCmd = defineCommand({
|
|
344
|
+
meta: {
|
|
345
|
+
name: "type",
|
|
346
|
+
description: "Type text at current focus"
|
|
347
|
+
},
|
|
348
|
+
args: {
|
|
349
|
+
text: {
|
|
350
|
+
type: "positional",
|
|
351
|
+
description: "Text to type",
|
|
352
|
+
required: true
|
|
353
|
+
},
|
|
354
|
+
driver: { type: "string" },
|
|
355
|
+
headed: { type: "boolean" },
|
|
356
|
+
session: { type: "string" }
|
|
357
|
+
},
|
|
358
|
+
async run({ args }) {
|
|
359
|
+
const driver = await getDriver(args);
|
|
360
|
+
await driver.type(args.text);
|
|
361
|
+
success("Typed text");
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
const hover = defineCommand({
|
|
365
|
+
meta: {
|
|
366
|
+
name: "hover",
|
|
367
|
+
description: "Hover over element"
|
|
368
|
+
},
|
|
369
|
+
args: {
|
|
370
|
+
ref: {
|
|
371
|
+
type: "positional",
|
|
372
|
+
required: true
|
|
373
|
+
},
|
|
374
|
+
driver: { type: "string" },
|
|
375
|
+
headed: { type: "boolean" },
|
|
376
|
+
session: { type: "string" }
|
|
377
|
+
},
|
|
378
|
+
async run({ args }) {
|
|
379
|
+
const driver = await getDriver(args);
|
|
380
|
+
await driver.hover(args.ref);
|
|
381
|
+
success(`Hovered ${args.ref}`);
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
const focus = defineCommand({
|
|
385
|
+
meta: {
|
|
386
|
+
name: "focus",
|
|
387
|
+
description: "Focus element"
|
|
388
|
+
},
|
|
389
|
+
args: {
|
|
390
|
+
ref: {
|
|
391
|
+
type: "positional",
|
|
392
|
+
required: true
|
|
393
|
+
},
|
|
394
|
+
driver: { type: "string" },
|
|
395
|
+
headed: { type: "boolean" },
|
|
396
|
+
session: { type: "string" }
|
|
397
|
+
},
|
|
398
|
+
async run({ args }) {
|
|
399
|
+
const driver = await getDriver(args);
|
|
400
|
+
await driver.focus(args.ref);
|
|
401
|
+
success(`Focused ${args.ref}`);
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
const scroll = defineCommand({
|
|
405
|
+
meta: {
|
|
406
|
+
name: "scroll",
|
|
407
|
+
description: "Scroll page"
|
|
408
|
+
},
|
|
409
|
+
args: {
|
|
410
|
+
direction: {
|
|
411
|
+
type: "positional",
|
|
412
|
+
description: "up/down/left/right",
|
|
413
|
+
required: true
|
|
414
|
+
},
|
|
415
|
+
px: {
|
|
416
|
+
type: "positional",
|
|
417
|
+
description: "Pixels to scroll",
|
|
418
|
+
required: false
|
|
419
|
+
},
|
|
420
|
+
driver: { type: "string" },
|
|
421
|
+
headed: { type: "boolean" },
|
|
422
|
+
session: { type: "string" }
|
|
423
|
+
},
|
|
424
|
+
async run({ args }) {
|
|
425
|
+
const driver = await getDriver(args);
|
|
426
|
+
await driver.scroll(args.direction, args.px ? Number(args.px) : void 0);
|
|
427
|
+
success(`Scrolled ${args.direction}`);
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
const upload = defineCommand({
|
|
431
|
+
meta: {
|
|
432
|
+
name: "upload",
|
|
433
|
+
description: "Upload file to input"
|
|
434
|
+
},
|
|
435
|
+
args: {
|
|
436
|
+
ref: {
|
|
437
|
+
type: "positional",
|
|
438
|
+
required: true
|
|
439
|
+
},
|
|
440
|
+
file: {
|
|
441
|
+
type: "positional",
|
|
442
|
+
description: "File path",
|
|
443
|
+
required: true
|
|
444
|
+
},
|
|
445
|
+
driver: { type: "string" },
|
|
446
|
+
headed: { type: "boolean" },
|
|
447
|
+
session: { type: "string" }
|
|
448
|
+
},
|
|
449
|
+
async run({ args }) {
|
|
450
|
+
const driver = await getDriver(args);
|
|
451
|
+
await driver.upload(args.ref, args.file);
|
|
452
|
+
success(`Uploaded to ${args.ref}`);
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
const screenshot = defineCommand({
|
|
456
|
+
meta: {
|
|
457
|
+
name: "screenshot",
|
|
458
|
+
description: "Take screenshot"
|
|
459
|
+
},
|
|
460
|
+
args: {
|
|
461
|
+
path: {
|
|
462
|
+
type: "positional",
|
|
463
|
+
description: "Output path",
|
|
464
|
+
required: false
|
|
465
|
+
},
|
|
466
|
+
annotate: {
|
|
467
|
+
type: "boolean",
|
|
468
|
+
description: "Add @e ref annotations"
|
|
469
|
+
},
|
|
470
|
+
full: {
|
|
471
|
+
type: "boolean",
|
|
472
|
+
description: "Full page screenshot"
|
|
473
|
+
},
|
|
474
|
+
selector: {
|
|
475
|
+
type: "string",
|
|
476
|
+
description: "Scope to CSS selector"
|
|
477
|
+
},
|
|
478
|
+
driver: { type: "string" },
|
|
479
|
+
headed: { type: "boolean" },
|
|
480
|
+
session: { type: "string" }
|
|
481
|
+
},
|
|
482
|
+
async run({ args }) {
|
|
483
|
+
const driver = await getDriver(args);
|
|
484
|
+
const path = await driver.screenshot({
|
|
485
|
+
path: args.path,
|
|
486
|
+
annotate: args.annotate,
|
|
487
|
+
full: args.full,
|
|
488
|
+
selector: args.selector
|
|
489
|
+
});
|
|
490
|
+
success(`Screenshot saved: ${path}`);
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
const consoleCmd = defineCommand({
|
|
494
|
+
meta: {
|
|
495
|
+
name: "console",
|
|
496
|
+
description: "Browser console messages"
|
|
497
|
+
},
|
|
498
|
+
args: {
|
|
499
|
+
level: {
|
|
500
|
+
type: "string",
|
|
501
|
+
description: "Filter by level (log, warn, error, info)"
|
|
502
|
+
},
|
|
503
|
+
clear: {
|
|
504
|
+
type: "boolean",
|
|
505
|
+
description: "Clear console buffer"
|
|
506
|
+
},
|
|
507
|
+
json: {
|
|
508
|
+
type: "boolean",
|
|
509
|
+
description: "JSON output"
|
|
510
|
+
},
|
|
511
|
+
driver: { type: "string" },
|
|
512
|
+
headed: { type: "boolean" },
|
|
513
|
+
session: { type: "string" }
|
|
514
|
+
},
|
|
515
|
+
async run({ args }) {
|
|
516
|
+
const driver = await getDriver(args);
|
|
517
|
+
const entries = await driver.console({
|
|
518
|
+
level: args.level,
|
|
519
|
+
clear: args.clear,
|
|
520
|
+
json: args.json
|
|
521
|
+
});
|
|
522
|
+
if (args.json) json(entries);
|
|
523
|
+
else if (entries.length === 0) info("No console messages");
|
|
524
|
+
else for (const e of entries) log(`[${e.level}] ${e.text}`);
|
|
525
|
+
}
|
|
526
|
+
});
|
|
527
|
+
const errors = defineCommand({
|
|
528
|
+
meta: {
|
|
529
|
+
name: "errors",
|
|
530
|
+
description: "Uncaught JS exceptions"
|
|
531
|
+
},
|
|
532
|
+
args: {
|
|
533
|
+
clear: {
|
|
534
|
+
type: "boolean",
|
|
535
|
+
description: "Clear error buffer"
|
|
536
|
+
},
|
|
537
|
+
driver: { type: "string" },
|
|
538
|
+
headed: { type: "boolean" },
|
|
539
|
+
session: { type: "string" }
|
|
540
|
+
},
|
|
541
|
+
async run({ args }) {
|
|
542
|
+
const driver = await getDriver(args);
|
|
543
|
+
if (args.clear) {
|
|
544
|
+
await driver.console({ clear: true });
|
|
545
|
+
success("Errors cleared");
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
const errs = await driver.errors();
|
|
549
|
+
if (errs.length === 0) success("No JS errors");
|
|
550
|
+
else for (const e of errs) {
|
|
551
|
+
error(e.message);
|
|
552
|
+
if (e.stack) log(e.stack);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
});
|
|
556
|
+
const network = defineCommand({
|
|
557
|
+
meta: {
|
|
558
|
+
name: "network",
|
|
559
|
+
description: "HTTP request log"
|
|
560
|
+
},
|
|
561
|
+
args: {
|
|
562
|
+
failed: {
|
|
563
|
+
type: "boolean",
|
|
564
|
+
description: "Only 4xx/5xx responses"
|
|
565
|
+
},
|
|
566
|
+
method: {
|
|
567
|
+
type: "string",
|
|
568
|
+
description: "Filter by HTTP method"
|
|
569
|
+
},
|
|
570
|
+
grep: {
|
|
571
|
+
type: "string",
|
|
572
|
+
description: "Filter URL pattern"
|
|
573
|
+
},
|
|
574
|
+
json: {
|
|
575
|
+
type: "boolean",
|
|
576
|
+
description: "JSON output"
|
|
577
|
+
},
|
|
578
|
+
driver: { type: "string" },
|
|
579
|
+
headed: { type: "boolean" },
|
|
580
|
+
session: { type: "string" }
|
|
581
|
+
},
|
|
582
|
+
async run({ args }) {
|
|
583
|
+
const driver = await getDriver(args);
|
|
584
|
+
const entries = await driver.network({
|
|
585
|
+
failed: args.failed,
|
|
586
|
+
method: args.method,
|
|
587
|
+
grep: args.grep,
|
|
588
|
+
json: args.json
|
|
589
|
+
});
|
|
590
|
+
if (args.json) json(entries);
|
|
591
|
+
else if (entries.length === 0) info("No network requests");
|
|
592
|
+
else for (const e of entries) log(`${e.method} ${e.status} ${e.url} (${e.duration}ms)`);
|
|
593
|
+
}
|
|
594
|
+
});
|
|
595
|
+
const evalCmd = defineCommand({
|
|
596
|
+
meta: {
|
|
597
|
+
name: "eval",
|
|
598
|
+
description: "Execute JavaScript in browser"
|
|
599
|
+
},
|
|
600
|
+
args: {
|
|
601
|
+
js: {
|
|
602
|
+
type: "positional",
|
|
603
|
+
description: "JavaScript expression",
|
|
604
|
+
required: true
|
|
605
|
+
},
|
|
606
|
+
driver: { type: "string" },
|
|
607
|
+
headed: { type: "boolean" },
|
|
608
|
+
session: { type: "string" }
|
|
609
|
+
},
|
|
610
|
+
async run({ args }) {
|
|
611
|
+
const driver = await getDriver(args);
|
|
612
|
+
const result = await driver.eval(args.js);
|
|
613
|
+
log(result);
|
|
614
|
+
}
|
|
615
|
+
});
|
|
616
|
+
const text = defineCommand({
|
|
617
|
+
meta: {
|
|
618
|
+
name: "text",
|
|
619
|
+
description: "Extract text content"
|
|
620
|
+
},
|
|
621
|
+
args: {
|
|
622
|
+
selector: {
|
|
623
|
+
type: "positional",
|
|
624
|
+
description: "CSS selector",
|
|
625
|
+
required: false
|
|
626
|
+
},
|
|
627
|
+
driver: { type: "string" },
|
|
628
|
+
headed: { type: "boolean" },
|
|
629
|
+
session: { type: "string" }
|
|
630
|
+
},
|
|
631
|
+
async run({ args }) {
|
|
632
|
+
const driver = await getDriver(args);
|
|
633
|
+
const result = await driver.text(args.selector);
|
|
634
|
+
log(result);
|
|
635
|
+
}
|
|
636
|
+
});
|
|
637
|
+
const wait = defineCommand({
|
|
638
|
+
meta: {
|
|
639
|
+
name: "wait",
|
|
640
|
+
description: "Wait for condition"
|
|
641
|
+
},
|
|
642
|
+
args: {
|
|
643
|
+
target: {
|
|
644
|
+
type: "positional",
|
|
645
|
+
description: "Ref or selector to wait for",
|
|
646
|
+
required: false
|
|
647
|
+
},
|
|
648
|
+
url: {
|
|
649
|
+
type: "string",
|
|
650
|
+
description: "Wait for URL pattern"
|
|
651
|
+
},
|
|
652
|
+
text: {
|
|
653
|
+
type: "string",
|
|
654
|
+
description: "Wait for text on page"
|
|
655
|
+
},
|
|
656
|
+
network: {
|
|
657
|
+
type: "string",
|
|
658
|
+
description: "Wait for network idle"
|
|
659
|
+
},
|
|
660
|
+
timeout: {
|
|
661
|
+
type: "string",
|
|
662
|
+
description: "Timeout (e.g. 10s, 30s)",
|
|
663
|
+
default: "30s"
|
|
664
|
+
},
|
|
665
|
+
driver: { type: "string" },
|
|
666
|
+
headed: { type: "boolean" },
|
|
667
|
+
session: { type: "string" }
|
|
668
|
+
},
|
|
669
|
+
async run({ args }) {
|
|
670
|
+
const driver = await getDriver(args);
|
|
671
|
+
const timeoutMs = parseDuration(args.timeout);
|
|
672
|
+
if (args.target) {
|
|
673
|
+
const isRefInput = args.target.startsWith("@e");
|
|
674
|
+
await driver.wait({
|
|
675
|
+
ref: isRefInput ? args.target : void 0,
|
|
676
|
+
selector: isRefInput ? void 0 : args.target,
|
|
677
|
+
timeout: timeoutMs
|
|
678
|
+
});
|
|
679
|
+
} else if (args.url) await driver.wait({
|
|
680
|
+
url: args.url,
|
|
681
|
+
timeout: timeoutMs
|
|
682
|
+
});
|
|
683
|
+
else if (args.text) await driver.wait({
|
|
684
|
+
text: args.text,
|
|
685
|
+
timeout: timeoutMs
|
|
686
|
+
});
|
|
687
|
+
else if (args.network === "idle") await driver.wait({
|
|
688
|
+
network: "idle",
|
|
689
|
+
timeout: timeoutMs
|
|
690
|
+
});
|
|
691
|
+
else {
|
|
692
|
+
error("Provide a target (ref/selector), --url, --text, or --network idle");
|
|
693
|
+
process.exit(1);
|
|
694
|
+
}
|
|
695
|
+
success("Wait condition met");
|
|
696
|
+
}
|
|
697
|
+
});
|
|
698
|
+
const command = defineCommand({
|
|
699
|
+
meta: {
|
|
700
|
+
name: "browser",
|
|
701
|
+
description: "Control browser for visual testing"
|
|
702
|
+
},
|
|
703
|
+
subCommands: {
|
|
704
|
+
open,
|
|
705
|
+
back,
|
|
706
|
+
forward,
|
|
707
|
+
reload,
|
|
708
|
+
url,
|
|
709
|
+
title,
|
|
710
|
+
close,
|
|
711
|
+
snapshot,
|
|
712
|
+
click,
|
|
713
|
+
dblclick,
|
|
714
|
+
fill,
|
|
715
|
+
select: selectCmd,
|
|
716
|
+
check: checkCmd,
|
|
717
|
+
uncheck: uncheckCmd,
|
|
718
|
+
press,
|
|
719
|
+
type: typeCmd,
|
|
720
|
+
hover,
|
|
721
|
+
focus,
|
|
722
|
+
scroll,
|
|
723
|
+
upload,
|
|
724
|
+
screenshot,
|
|
725
|
+
console: consoleCmd,
|
|
726
|
+
errors,
|
|
727
|
+
network,
|
|
728
|
+
eval: evalCmd,
|
|
729
|
+
text,
|
|
730
|
+
wait
|
|
731
|
+
}
|
|
732
|
+
});
|
|
733
|
+
var browser_default = command;
|
|
734
|
+
|
|
735
|
+
//#endregion
|
|
736
|
+
export { browser_default as default };
|