@humanjs/playwright 0.3.0 → 0.5.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/README.md +200 -7
- package/dist/index.cjs +1022 -183
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +406 -31
- package/dist/index.d.ts +406 -31
- package/dist/index.js +1004 -186
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,80 @@
|
|
|
1
|
-
import { ReadKind, PersonalityConfig, HumanPlugin,
|
|
2
|
-
export { ActionResult, ActionType, BezierPathOptions, ComputeReadingDwellOptions, DwellProfile, HumanAction, HumanPlugin, HumanizePathOptions, Keystroke, KnownActionType, MouseProfile, Personality, PersonalityConfig, PersonalityExtension, PlanTypingOptions, PluginContext, Point, PresetName, ReadKind, ReadingProfile, Rng, ScrollProfile, ScrollSegment, TypingProfile, applyMicroJitter, applyVelocityProfile, bezierPath, blend, careful, computeReadingDwellMs, countWords, createRng, distracted, fast, humanizePath, planScroll, planTypeKeystrokes, precise, resolvePersonality } from '@humanjs/core';
|
|
1
|
+
import { Point, ReadKind, PersonalityConfig, HumanPlugin, Personality } from '@humanjs/core';
|
|
2
|
+
export { ActionResult, ActionType, BezierPathOptions, ComputeReadingDwellOptions, DwellProfile, HumanAction, HumanPlugin, HumanizePathOptions, Keystroke, KnownActionType, MouseProfile, Personality, PersonalityConfig, PersonalityExtension, PlanTypingOptions, PluginContext, Point, PresetName, ReadKind, ReadingProfile, Rng, ScrollProfile, ScrollSegment, TypingProfile, applyMicroJitter, applyVelocityProfile, bezierPath, blend, careful, computeReadingDwellMs, countWords, createRng, distracted, fast, humanizePath, planScroll, planTypeKeystrokes, precise, resolvePersonality, sleep } from '@humanjs/core';
|
|
3
3
|
import { Locator, BrowserContext, Page } from 'playwright';
|
|
4
|
+
export { Browser, BrowserContext, BrowserContextOptions, ElementHandle, LaunchOptions, Locator, Page, chromium, firefox, webkit } from 'playwright';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Modifier tokens accepted in a `human.press()` chord. `Mod` and `CmdOrCtrl` /
|
|
8
|
+
* `CommandOrControl` are the magic auto-mapping tokens (Meta on Mac,
|
|
9
|
+
* Control elsewhere). The rest are literal — they always resolve to the
|
|
10
|
+
* keycode they name, on every platform.
|
|
11
|
+
*
|
|
12
|
+
* Canonical-case names are listed here for IntelliSense; the runtime
|
|
13
|
+
* parser is case-insensitive, so `'cmd+s'` and `'CMD+S'` work too — they
|
|
14
|
+
* just won't autocomplete.
|
|
15
|
+
*/
|
|
16
|
+
type KeyModifier = 'Mod' | 'CmdOrCtrl' | 'CommandOrControl' | 'Cmd' | 'Command' | 'Meta' | 'Win' | 'Super' | 'Ctrl' | 'Control' | 'Alt' | 'Option' | 'Opt' | 'Shift';
|
|
17
|
+
/**
|
|
18
|
+
* The canonical key names that autocomplete in a `KeyOrChord`. Mirrors
|
|
19
|
+
* Playwright's accepted key vocabulary, plus a few common synonyms.
|
|
20
|
+
* CamelCase names (`ArrowDown`, `PageUp`) are listed in their canonical
|
|
21
|
+
* form — `normalizeKey` preserves case from the input, so what you type is
|
|
22
|
+
* what gets dispatched.
|
|
23
|
+
*
|
|
24
|
+
* Not exhaustive: every other Playwright key (less-common Numpad keys,
|
|
25
|
+
* `BracketLeft`, locale-specific keys, etc.) is outside the typed union
|
|
26
|
+
* and needs a cast at the call site (`'BracketLeft' as KeyOrChord`). The
|
|
27
|
+
* runtime parser handles them — the type just doesn't enumerate them,
|
|
28
|
+
* because adding a `(string & {})` escape hatch would collapse TypeScript's
|
|
29
|
+
* template-literal IntelliSense for the chord autocompletes.
|
|
30
|
+
*/
|
|
31
|
+
type KeyName = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | 'F1' | 'F2' | 'F3' | 'F4' | 'F5' | 'F6' | 'F7' | 'F8' | 'F9' | 'F10' | 'F11' | 'F12' | 'ArrowUp' | 'ArrowDown' | 'ArrowLeft' | 'ArrowRight' | 'PageUp' | 'PageDown' | 'Home' | 'End' | 'Enter' | 'Tab' | 'Escape' | 'Space' | 'Backspace' | 'Delete' | 'Insert' | 'CapsLock' | 'NumLock' | 'ScrollLock' | 'PrintScreen' | 'Pause';
|
|
32
|
+
/**
|
|
33
|
+
* Strings accepted by `human.press(key)`:
|
|
34
|
+
*
|
|
35
|
+
* - A bare known key: `'Enter'`, `'F4'`, `'ArrowDown'`, `'S'`, …
|
|
36
|
+
* - One known modifier + a known key: `'Mod+S'`, `'Shift+ArrowDown'`, …
|
|
37
|
+
* - Two known modifiers + a known key: `'Mod+Shift+P'`, `'Ctrl+Alt+Tab'`, …
|
|
38
|
+
*
|
|
39
|
+
* Every member of the union is a fully-enumerated literal, which is what
|
|
40
|
+
* makes IDE autocomplete work — type `'Shift+'` and you get every
|
|
41
|
+
* `Shift+<key>` combination as a completion. Adding a `(string & {})`
|
|
42
|
+
* escape hatch anywhere would collapse that down to a single wide
|
|
43
|
+
* template member, killing the completion list.
|
|
44
|
+
*
|
|
45
|
+
* Modifier typos (`'Mosd+S'`) and uncommon-key typos (`'Mod+BraketLeft'`)
|
|
46
|
+
* are both TS errors at the call site — the closed sets on both sides
|
|
47
|
+
* give you compile-time protection that Playwright's plain `string` key
|
|
48
|
+
* type can't.
|
|
49
|
+
*
|
|
50
|
+
* **Escape hatch for uncommon keys.** Less-common Playwright keys
|
|
51
|
+
* (`'BracketLeft'`, `'NumpadAdd'`, locale-specific keys, …) and 3+
|
|
52
|
+
* modifier chords (`'Ctrl+Shift+Alt+K'`) aren't in the union and need a
|
|
53
|
+
* cast at the call site:
|
|
54
|
+
*
|
|
55
|
+
* ```ts
|
|
56
|
+
* await human.press('Mod+BracketLeft' as KeyOrChord);
|
|
57
|
+
* await human.press('Ctrl+Shift+Alt+K' as KeyOrChord);
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* The runtime parser handles these fine — the cast just acknowledges
|
|
61
|
+
* "I'm using a key outside the autocomplete vocabulary." If you find
|
|
62
|
+
* yourself casting often for a specific key, propose adding it to
|
|
63
|
+
* `KeyName` in a PR.
|
|
64
|
+
*
|
|
65
|
+
* Lowercase modifiers (`'mod+s'`) also don't typecheck even though the
|
|
66
|
+
* runtime accepts them — TS-strict steers users toward the canonical
|
|
67
|
+
* casing, which keeps key strings consistent across a codebase.
|
|
68
|
+
*/
|
|
69
|
+
type KeyOrChord = KeyName | `${KeyModifier}+${KeyName}` | `${KeyModifier}+${KeyModifier}+${KeyName}`;
|
|
70
|
+
/** Result of a `press` action. */
|
|
71
|
+
interface PressResult {
|
|
72
|
+
/** The exact chord that was dispatched (after Mod-resolution). */
|
|
73
|
+
readonly dispatched: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Anything that can resolve to a click/move point. */
|
|
77
|
+
type MouseTarget = Locator | string | Point;
|
|
4
78
|
|
|
5
79
|
/**
|
|
6
80
|
* What to read:
|
|
@@ -39,9 +113,10 @@ interface ReadOptions {
|
|
|
39
113
|
/**
|
|
40
114
|
* For selector/Locator targets: trace a humanized cursor path through the
|
|
41
115
|
* target's bounding box while the dwell elapses, like an eye tracking
|
|
42
|
-
* lines of text.
|
|
43
|
-
*
|
|
44
|
-
*
|
|
116
|
+
* lines of text. **Defaults to `true`** — "reading" implies looking, and
|
|
117
|
+
* looking implies motion. Pass `false` to skip motion when you only
|
|
118
|
+
* care about the temporal pattern (typical AI-agent use case where
|
|
119
|
+
* the cursor position is irrelevant).
|
|
45
120
|
*
|
|
46
121
|
* The scan path is generated by `planReadingScan` from `@humanjs/core`
|
|
47
122
|
* (same deterministic-by-seed contract as the rest of the library) and
|
|
@@ -63,6 +138,183 @@ interface ReadResult {
|
|
|
63
138
|
readonly kind: ReadKind;
|
|
64
139
|
}
|
|
65
140
|
|
|
141
|
+
/**
|
|
142
|
+
* A captured frame in the timer-based capture session. `tMs` is the
|
|
143
|
+
* wall-clock offset (ms) from the capture start.
|
|
144
|
+
*/
|
|
145
|
+
interface CapturedFrame {
|
|
146
|
+
readonly path: string;
|
|
147
|
+
readonly tMs: number;
|
|
148
|
+
}
|
|
149
|
+
/** Outcome of a finalized capture session. */
|
|
150
|
+
interface CaptureResult {
|
|
151
|
+
readonly dir: string;
|
|
152
|
+
readonly frames: readonly CapturedFrame[];
|
|
153
|
+
readonly startedAtMs: number;
|
|
154
|
+
readonly stoppedAtMs: number;
|
|
155
|
+
readonly format: 'jpeg' | 'png';
|
|
156
|
+
readonly fps: number;
|
|
157
|
+
/**
|
|
158
|
+
* Removes the temp directory + all frames. Called by `Recording.dispose()`
|
|
159
|
+
* and by the sweep-on-exit handler — not by the exporters, which are
|
|
160
|
+
* repeatable and read the frames without consuming them. Also called
|
|
161
|
+
* directly by the error path in `human.record()` when the callback throws.
|
|
162
|
+
*/
|
|
163
|
+
cleanup(): Promise<void>;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Encoding quality preset. Picks the per-frame capture quality + the
|
|
168
|
+
* ffmpeg encode settings used to assemble them into a video.
|
|
169
|
+
*
|
|
170
|
+
* - `'fast'` — JPEG q=85, CRF 23, preset fast (iteration)
|
|
171
|
+
* - `'standard'` — JPEG q=90, CRF 20, preset fast (balanced)
|
|
172
|
+
* - `'high'` (default) — JPEG q=95, CRF 18, preset slow, tune animation (marketing-grade)
|
|
173
|
+
* - `'lossless'` — PNG capture, CRF 12, preset veryslow (archival; huge temp files)
|
|
174
|
+
*/
|
|
175
|
+
type RecordingQuality = 'fast' | 'high' | 'lossless' | 'standard';
|
|
176
|
+
/** ffmpeg `-preset` values, ordered from fastest to slowest. */
|
|
177
|
+
type FfmpegPreset = 'fast' | 'faster' | 'medium' | 'slow' | 'slower' | 'superfast' | 'ultrafast' | 'veryfast' | 'veryslow';
|
|
178
|
+
/** ffmpeg `-tune` values for libx264. */
|
|
179
|
+
type FfmpegTune = 'animation' | 'fastdecode' | 'film' | 'grain' | 'stillimage' | 'zerolatency';
|
|
180
|
+
/** Options for {@link Recording.toVideo}. */
|
|
181
|
+
interface ToVideoOptions {
|
|
182
|
+
/** Encoding quality preset. Defaults to `'high'`. */
|
|
183
|
+
readonly quality?: RecordingQuality;
|
|
184
|
+
/** Override CRF (0–51, lower = better). Defaults to the quality preset's CRF. */
|
|
185
|
+
readonly crf?: number;
|
|
186
|
+
/** Override ffmpeg `-preset`. Defaults to the quality preset's preset. */
|
|
187
|
+
readonly preset?: FfmpegPreset;
|
|
188
|
+
/** Override ffmpeg `-tune`. Defaults to the quality preset's tune (if any). */
|
|
189
|
+
readonly tune?: FfmpegTune;
|
|
190
|
+
}
|
|
191
|
+
/** Options for {@link Recording.toGif}. */
|
|
192
|
+
interface ToGifOptions {
|
|
193
|
+
/**
|
|
194
|
+
* Frames per second of the output GIF. Defaults to `15` — high enough for
|
|
195
|
+
* smooth motion in most renderers, low enough to keep file size sane.
|
|
196
|
+
* Renderers cap GIF playback around 50fps anyway.
|
|
197
|
+
*/
|
|
198
|
+
readonly fps?: number;
|
|
199
|
+
/**
|
|
200
|
+
* Scale the GIF to this width (pixels). Height is computed to preserve
|
|
201
|
+
* aspect ratio. Omit to keep the source viewport size — but most embedded
|
|
202
|
+
* GIFs (README, PR, Slack) look fine at 640–960px and weigh a fraction.
|
|
203
|
+
*/
|
|
204
|
+
readonly width?: number;
|
|
205
|
+
}
|
|
206
|
+
/** One action captured during a recording, as emitted in {@link Timeline.events}. */
|
|
207
|
+
interface TimelineEvent {
|
|
208
|
+
readonly type: string;
|
|
209
|
+
readonly params: Readonly<Record<string, unknown>>;
|
|
210
|
+
/** Offset (ms) from the recording start when the action began. */
|
|
211
|
+
readonly tMs: number;
|
|
212
|
+
readonly durationMs: number;
|
|
213
|
+
/** Error message, present only if the action threw. */
|
|
214
|
+
readonly error?: string;
|
|
215
|
+
}
|
|
216
|
+
/** Structured action timeline of a recording. */
|
|
217
|
+
interface Timeline {
|
|
218
|
+
readonly version: 1;
|
|
219
|
+
readonly personality: string;
|
|
220
|
+
readonly seed: string | null;
|
|
221
|
+
readonly speed: string;
|
|
222
|
+
readonly durationMs: number;
|
|
223
|
+
readonly events: readonly TimelineEvent[];
|
|
224
|
+
}
|
|
225
|
+
/** Metadata passed from `human.record()` into the Recording constructor. */
|
|
226
|
+
interface RecordingTimelineSource {
|
|
227
|
+
readonly personality: string;
|
|
228
|
+
readonly seed: string | null;
|
|
229
|
+
readonly speed: string;
|
|
230
|
+
readonly events: readonly TimelineEvent[];
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* A recorded window of a humanized session. Returned by `human.record(cb)`.
|
|
234
|
+
*
|
|
235
|
+
* A Recording can hold a frame capture (`hasVideo === true`) OR be
|
|
236
|
+
* timeline-only (`hasVideo === false`). `toVideo()` / `toGif()` require a
|
|
237
|
+
* capture; `toTimeline()` and `.timeline` work either way.
|
|
238
|
+
*
|
|
239
|
+
* The video exporters are repeatable and interleavable — they read the
|
|
240
|
+
* captured frames without consuming them. Calling `dispose()` is OPTIONAL:
|
|
241
|
+
* the captured-frames temp dir is also swept by a `process.on('exit')`
|
|
242
|
+
* handler installed on first use, so casual scripts can skip it entirely.
|
|
243
|
+
* Call `dispose()` (or use `await using`) when you want to release the
|
|
244
|
+
* frames proactively — long-running services, batch jobs, etc.
|
|
245
|
+
*/
|
|
246
|
+
declare class Recording {
|
|
247
|
+
#private;
|
|
248
|
+
constructor(capture: CaptureResult | null, windowStartMs: number, windowEndMs: number, timelineSource: RecordingTimelineSource);
|
|
249
|
+
/** Wall-clock duration of the recorded window. */
|
|
250
|
+
get durationMs(): number;
|
|
251
|
+
/** True if frames were captured during this recording. */
|
|
252
|
+
get hasVideo(): boolean;
|
|
253
|
+
/**
|
|
254
|
+
* The structured action timeline of this recording — same data that
|
|
255
|
+
* `toTimeline()` writes to disk.
|
|
256
|
+
*/
|
|
257
|
+
get timeline(): Timeline;
|
|
258
|
+
/**
|
|
259
|
+
* Assembles the captured frames into a video at `outputPath`. The output
|
|
260
|
+
* format is inferred from the extension — `.mp4` (H.264, re-encoded
|
|
261
|
+
* with the configured quality) or `.webm` (VP9).
|
|
262
|
+
*
|
|
263
|
+
* Repeatable and interleavable with `toGif()` — the frame source is read,
|
|
264
|
+
* not consumed. Frames live until you call `dispose()` (or `await using`
|
|
265
|
+
* goes out of scope, or the process exits and the OS reaps `tmpdir`).
|
|
266
|
+
*
|
|
267
|
+
* @returns the resolved output path.
|
|
268
|
+
*/
|
|
269
|
+
toVideo(outputPath: string, options?: ToVideoOptions): Promise<string>;
|
|
270
|
+
/**
|
|
271
|
+
* Assembles the captured frames into an animated GIF at `outputPath`.
|
|
272
|
+
* Optimized for embedding in READMEs, PRs, Slack, and docs — uses a
|
|
273
|
+
* per-recording palette (`palettegen` + `paletteuse`) with Bayer dithering
|
|
274
|
+
* so gradients stay smooth without exploding the file size.
|
|
275
|
+
*
|
|
276
|
+
* Repeatable and interleavable with `toVideo()` — call them in any order,
|
|
277
|
+
* any number of times. Frames live until you call `dispose()`.
|
|
278
|
+
*
|
|
279
|
+
* @returns the resolved output path.
|
|
280
|
+
*/
|
|
281
|
+
toGif(outputPath: string, options?: ToGifOptions): Promise<string>;
|
|
282
|
+
/**
|
|
283
|
+
* Writes the structured action timeline to `outputPath` as JSON.
|
|
284
|
+
* Independent of `toVideo()` / `toGif()` — call before, after, in between,
|
|
285
|
+
* or instead. Safe to call multiple times. Unaffected by `dispose()`
|
|
286
|
+
* (the timeline lives in memory, not in the captured-frames temp dir).
|
|
287
|
+
*
|
|
288
|
+
* @returns the resolved output path.
|
|
289
|
+
*/
|
|
290
|
+
toTimeline(outputPath: string): Promise<string>;
|
|
291
|
+
/**
|
|
292
|
+
* Releases the captured-frames temp directory. After this call, `toVideo()`
|
|
293
|
+
* and `toGif()` throw — but `toTimeline()` and the in-memory `timeline`
|
|
294
|
+
* still work because those don't depend on the frames.
|
|
295
|
+
*
|
|
296
|
+
* **Optional.** A process-exit handler also sweeps any un-disposed frame
|
|
297
|
+
* dirs, so casual scripts can skip this entirely. Call it explicitly when
|
|
298
|
+
* you want to release frames proactively (long-running services, batch
|
|
299
|
+
* jobs, or anywhere you want predictable disk usage).
|
|
300
|
+
*
|
|
301
|
+
* Idempotent. Safe to call on a Recording that never had a capture
|
|
302
|
+
* (timeline-only mode) — no-op there.
|
|
303
|
+
*
|
|
304
|
+
* Also wired to `Symbol.asyncDispose`, so the explicit-resource-management
|
|
305
|
+
* `await using` syntax (TypeScript ≥ 5.2 / Node ≥ 20.4) works:
|
|
306
|
+
*
|
|
307
|
+
* ```ts
|
|
308
|
+
* await using rec = await human.record(fn);
|
|
309
|
+
* await rec.toVideo('demo.mp4');
|
|
310
|
+
* await rec.toGif('demo.gif');
|
|
311
|
+
* // frames cleaned up automatically when `rec` goes out of scope
|
|
312
|
+
* ```
|
|
313
|
+
*/
|
|
314
|
+
dispose(): Promise<void>;
|
|
315
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
316
|
+
}
|
|
317
|
+
|
|
66
318
|
/**
|
|
67
319
|
* What / where to scroll. The chosen axis (`'y'` by default, `'x'` via
|
|
68
320
|
* `options.axis`) decides whether targets resolve along the vertical or
|
|
@@ -165,31 +417,6 @@ interface InstallMouseHelperOptions {
|
|
|
165
417
|
/** Halo opacity behind the cursor. Defaults to `0.18`. */
|
|
166
418
|
readonly haloOpacity?: number;
|
|
167
419
|
}
|
|
168
|
-
/**
|
|
169
|
-
* Installs a visual cursor overlay that follows every `mousemove` on each
|
|
170
|
-
* page in the target. Real synthetic motion from Playwright (e.g.
|
|
171
|
-
* `human.click()`, `human.read(..., { withMotion: true })`) is *already*
|
|
172
|
-
* happening — the page just doesn't render a system cursor for it. This
|
|
173
|
-
* helper injects a HumanJS-styled SVG cursor that listens to mousemove
|
|
174
|
-
* events and follows them, making the motion visible in headed demos and
|
|
175
|
-
* screen recordings.
|
|
176
|
-
*
|
|
177
|
-
* Re-runs on every navigation via `addInitScript`, so the overlay survives
|
|
178
|
-
* page reloads. Idempotent — guard flag on `window` prevents double-install.
|
|
179
|
-
*
|
|
180
|
-
* Accepts either a `Page` (overlay applies to that page) or a
|
|
181
|
-
* `BrowserContext` (overlay applies to every page in the context, including
|
|
182
|
-
* pages opened later).
|
|
183
|
-
*
|
|
184
|
-
* @example
|
|
185
|
-
* ```ts
|
|
186
|
-
* const browser = await chromium.launch({ headless: false });
|
|
187
|
-
* const context = await browser.newContext();
|
|
188
|
-
* await installMouseHelper(context);
|
|
189
|
-
* const page = await context.newPage();
|
|
190
|
-
* // human-driven actions are now visible in the page
|
|
191
|
-
* ```
|
|
192
|
-
*/
|
|
193
420
|
declare function installMouseHelper(target: BrowserContext | Page, options?: InstallMouseHelperOptions): Promise<void>;
|
|
194
421
|
|
|
195
422
|
/**
|
|
@@ -239,6 +466,53 @@ interface Human {
|
|
|
239
466
|
* native `locator.click()` is used directly.
|
|
240
467
|
*/
|
|
241
468
|
click(target: Locator | string): Promise<void>;
|
|
469
|
+
/**
|
|
470
|
+
* Right-click `target` — opens a native context menu. Same Bezier-path
|
|
471
|
+
* motion and hover dwell as `click()`; only the dispatched button differs.
|
|
472
|
+
*
|
|
473
|
+
* In `speed: 'instant'`, falls back to `locator.click({ button: 'right' })`.
|
|
474
|
+
*/
|
|
475
|
+
rightClick(target: Locator | string): Promise<void>;
|
|
476
|
+
/**
|
|
477
|
+
* Move the cursor to `target` along a humanized Bezier path and settle
|
|
478
|
+
* on it — no click is dispatched. Useful for hover-triggered UI
|
|
479
|
+
* (tooltips, dropdowns), for positioning the cursor before a non-target
|
|
480
|
+
* action, or for visible demos where the cursor should pause on
|
|
481
|
+
* something noteworthy.
|
|
482
|
+
*
|
|
483
|
+
* In `speed: 'instant'`, dispatches one `mouse.move()` to the element's
|
|
484
|
+
* center.
|
|
485
|
+
*/
|
|
486
|
+
hover(target: Locator | string): Promise<void>;
|
|
487
|
+
/**
|
|
488
|
+
* Move the cursor to `target` along a humanized Bezier path. Pure
|
|
489
|
+
* positioning — no settle dwell, no element interaction. `target` accepts
|
|
490
|
+
* a CSS selector, a `Locator`, or a literal `Point`; the `Point` form
|
|
491
|
+
* lets you position the cursor anywhere (canvas, SVG, dead space) without
|
|
492
|
+
* a DOM element to anchor on.
|
|
493
|
+
*
|
|
494
|
+
* Distinct from `hover()`: `hover` is element-bound and includes a settle
|
|
495
|
+
* dwell to let hover-state UI fire (tooltips, dropdowns). `move` is
|
|
496
|
+
* positional only — use it when you want the cursor placed somewhere
|
|
497
|
+
* without implying interaction with what's under it (pre-press
|
|
498
|
+
* placement, canvas painting, cinematic beats).
|
|
499
|
+
*
|
|
500
|
+
* In `speed: 'instant'`, dispatches one `mouse.move()` at the resolved
|
|
501
|
+
* coordinates.
|
|
502
|
+
*/
|
|
503
|
+
move(target: MouseTarget): Promise<void>;
|
|
504
|
+
/**
|
|
505
|
+
* Drag from `from` to `to`. Each endpoint accepts a CSS selector, a
|
|
506
|
+
* `Locator`, or a literal `Point` — the last form matters for canvas /
|
|
507
|
+
* SVG / slider drags where the destination isn't a DOM element.
|
|
508
|
+
*
|
|
509
|
+
* The motion is two humanized paths back-to-back: cursor → source,
|
|
510
|
+
* then source → destination with the left button held throughout.
|
|
511
|
+
*
|
|
512
|
+
* In `speed: 'instant'`, dispatches `mouse.down → move → up` at the
|
|
513
|
+
* resolved coordinates without humanized motion.
|
|
514
|
+
*/
|
|
515
|
+
drag(from: MouseTarget, to: MouseTarget): Promise<void>;
|
|
242
516
|
/**
|
|
243
517
|
* Type `value` into `target` with humanized per-key timing, optional typo
|
|
244
518
|
* injection (with backspace recovery), and occasional think-pauses.
|
|
@@ -250,6 +524,48 @@ interface Human {
|
|
|
250
524
|
* zero inter-key delay — events still fire, but humanization is skipped.
|
|
251
525
|
*/
|
|
252
526
|
type(target: Locator | string, value: string): Promise<void>;
|
|
527
|
+
/**
|
|
528
|
+
* Insert `value` into `target` in one shot — the Cmd-V semantic. No
|
|
529
|
+
* per-character timing. Like `type()`, drives an implicit click to focus
|
|
530
|
+
* the field first; unlike `type()`, dispatches the whole value via
|
|
531
|
+
* `keyboard.insertText` rather than per-key presses.
|
|
532
|
+
*
|
|
533
|
+
* Use this for long strings (code blocks, multi-line content, secrets)
|
|
534
|
+
* where the typing simulation would be slow and unnecessary. If you need
|
|
535
|
+
* the page's `paste` event handler to fire, call `human.press('Mod+V')`
|
|
536
|
+
* after setting clipboard contents yourself.
|
|
537
|
+
*
|
|
538
|
+
* In `speed: 'instant'`, behaves identically — paste is already instant
|
|
539
|
+
* by nature.
|
|
540
|
+
*/
|
|
541
|
+
paste(target: Locator | string, value: string): Promise<void>;
|
|
542
|
+
/**
|
|
543
|
+
* Press a single key (`'Tab'`, `'Enter'`, `'Escape'`, `'ArrowDown'`, …)
|
|
544
|
+
* or a keyboard chord (`'Mod+S'`, `'Cmd+Shift+P'`, `'Ctrl+C'`, …).
|
|
545
|
+
*
|
|
546
|
+
* Modifier rules:
|
|
547
|
+
*
|
|
548
|
+
* - `Mod` / `CmdOrCtrl` / `CommandOrControl` — magic: `Meta` on Mac,
|
|
549
|
+
* `Control` elsewhere. Use for cross-platform app shortcuts. The three
|
|
550
|
+
* are aliases; `Mod` is shortest.
|
|
551
|
+
* - `Cmd`, `Command`, `Meta`, `Win`, `Super` — literal `Meta` keycode
|
|
552
|
+
* (Command on Mac, Windows key on Windows, Super on Linux).
|
|
553
|
+
* - `Ctrl`, `Control` — literal Control. Stays Control on every OS.
|
|
554
|
+
* - `Alt`, `Option`, `Opt` — literal Alt.
|
|
555
|
+
* - `Shift` — literal Shift.
|
|
556
|
+
*
|
|
557
|
+
* Case-insensitive. Throws on unknown modifiers. The `KeyOrChord` type
|
|
558
|
+
* is a template-literal union of every modifier × key combination (up to
|
|
559
|
+
* two literal modifiers + a key), so IDEs autocomplete common bare keys
|
|
560
|
+
* and chords as you type. Less common keys (`BracketLeft`, `NumpadAdd`,
|
|
561
|
+
* locale-specific keys) still typecheck through the union's string
|
|
562
|
+
* escape hatch — they just don't autocomplete.
|
|
563
|
+
*
|
|
564
|
+
* Does **not** move the cursor — keyboard input dispatches against
|
|
565
|
+
* focus, not cursor position. Compose with `click` / `hover` / `move`
|
|
566
|
+
* when you need both.
|
|
567
|
+
*/
|
|
568
|
+
press(key: KeyOrChord): Promise<void>;
|
|
253
569
|
/**
|
|
254
570
|
* Dwell as if reading `target` — the third pillar of humanization after
|
|
255
571
|
* the cursor and the keyboard. Real users pause to read; HumanJS models
|
|
@@ -310,6 +626,65 @@ interface Human {
|
|
|
310
626
|
* Returns a {@link ScrollResult} for assertions in tests.
|
|
311
627
|
*/
|
|
312
628
|
scroll(target?: ScrollTarget, options?: ScrollOptions): Promise<ScrollResult>;
|
|
629
|
+
/**
|
|
630
|
+
* Pause for `ms` milliseconds. Equivalent to importing `sleep` from
|
|
631
|
+
* `@humanjs/playwright` and calling it — exposed on the Human instance
|
|
632
|
+
* so users who already have `human` in scope don't need an extra import.
|
|
633
|
+
*
|
|
634
|
+
* Not a humanized action: this is a raw `setTimeout` wait, not scaled
|
|
635
|
+
* by personality or speed mode, and no plugin events fire. Use it for
|
|
636
|
+
* generic pacing between humanized actions.
|
|
637
|
+
*/
|
|
638
|
+
sleep(ms: number): Promise<void>;
|
|
639
|
+
/**
|
|
640
|
+
* Records `fn`'s actions. Returns a {@link Recording} you can export
|
|
641
|
+
* to mp4/webm video (`toVideo`), JSON timeline (`toTimeline`), or both.
|
|
642
|
+
*
|
|
643
|
+
* By default, frames are captured from the browser via timer-polled
|
|
644
|
+
* `page.screenshot()` — fully controllable quality, not limited by
|
|
645
|
+
* Playwright's recordVideo bitrate ceiling. Pass `{ video: false }` to
|
|
646
|
+
* skip capture entirely (timeline-only mode, zero video overhead).
|
|
647
|
+
*
|
|
648
|
+
* Plugins observe `'record'` in `beforeAction` / `afterAction` so
|
|
649
|
+
* recording shows up alongside the other primitives in observability
|
|
650
|
+
* pipelines.
|
|
651
|
+
*
|
|
652
|
+
* Single-use per session: `Recording.toVideo()` finalizes the captured
|
|
653
|
+
* frames, so calling `human.record()` twice on the same human throws.
|
|
654
|
+
*
|
|
655
|
+
* @example
|
|
656
|
+
* ```ts
|
|
657
|
+
* // Default: video + timeline
|
|
658
|
+
* const rec = await human.record(async () => {
|
|
659
|
+
* await human.click('#login');
|
|
660
|
+
* });
|
|
661
|
+
* await rec.toVideo('demo.mp4');
|
|
662
|
+
* await rec.toTimeline('demo.json');
|
|
663
|
+
*
|
|
664
|
+
* // Timeline-only, no video overhead
|
|
665
|
+
* const rec = await human.record({ video: false }, async () => {
|
|
666
|
+
* await human.click('#login');
|
|
667
|
+
* });
|
|
668
|
+
* await rec.toTimeline('demo.json');
|
|
669
|
+
* ```
|
|
670
|
+
*/
|
|
671
|
+
record(fn: () => Promise<void>): Promise<Recording>;
|
|
672
|
+
record(options: HumanRecordOptions, fn: () => Promise<void>): Promise<Recording>;
|
|
673
|
+
}
|
|
674
|
+
/** Options for {@link Human.record}. */
|
|
675
|
+
interface HumanRecordOptions {
|
|
676
|
+
/**
|
|
677
|
+
* Whether to capture frames for video output. Defaults to `true`.
|
|
678
|
+
* Set to `false` for timeline-only recordings (no capture loop, no
|
|
679
|
+
* temp files, no encoding overhead — `toTimeline()` still works).
|
|
680
|
+
*/
|
|
681
|
+
readonly video?: boolean;
|
|
682
|
+
/**
|
|
683
|
+
* Capture quality preset. Controls per-frame JPEG quality (or PNG for
|
|
684
|
+
* lossless) AND the ffmpeg encode settings used by `toVideo()`.
|
|
685
|
+
* Defaults to `'high'`. Ignored when `video: false`.
|
|
686
|
+
*/
|
|
687
|
+
readonly quality?: RecordingQuality;
|
|
313
688
|
}
|
|
314
689
|
/**
|
|
315
690
|
* Creates a humanized session bound to a Playwright `Page`.
|
|
@@ -332,4 +707,4 @@ interface Human {
|
|
|
332
707
|
*/
|
|
333
708
|
declare function createHuman(page: Page, options?: CreateHumanOptions): Promise<Human>;
|
|
334
709
|
|
|
335
|
-
export { type CreateHumanOptions, type Human, type InstallMouseHelperOptions, type ReadOptions, type ReadResult, type ReadTarget, type ScrollOptions, type ScrollResult, type ScrollTarget, type Speed, createHuman, installMouseHelper };
|
|
710
|
+
export { type CreateHumanOptions, type FfmpegPreset, type FfmpegTune, type Human, type HumanRecordOptions, type InstallMouseHelperOptions, type KeyModifier, type KeyName, type KeyOrChord, type MouseTarget, type PressResult, type ReadOptions, type ReadResult, type ReadTarget, Recording, type RecordingQuality, type ScrollOptions, type ScrollResult, type ScrollTarget, type Speed, type Timeline, type TimelineEvent, type ToGifOptions, type ToVideoOptions, createHuman, installMouseHelper };
|