@humanjs/playwright 0.5.0 → 0.6.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 +42 -0
- package/dist/index.cjs +60 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +112 -8
- package/dist/index.d.ts +112 -8
- package/dist/index.js +60 -8
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -458,21 +458,29 @@ interface Human {
|
|
|
458
458
|
/**
|
|
459
459
|
* Move the mouse along a humanized Bezier path to `target` and click.
|
|
460
460
|
*
|
|
461
|
-
* `target` accepts
|
|
462
|
-
* `'button:has-text("Buy now")'`)
|
|
463
|
-
*
|
|
461
|
+
* `target` accepts a Playwright-compatible selector string (e.g.
|
|
462
|
+
* `'button:has-text("Buy now")'`), a built `Locator`, or a raw `Point`.
|
|
463
|
+
* For element targets the click point is Gaussian-distributed around the
|
|
464
|
+
* center; for a raw `Point` the exact coordinates are clicked. The
|
|
465
|
+
* `Point` form is the fallback for things with no clean selector —
|
|
466
|
+
* icon-only buttons, canvas, SVG — where you can see the pixel position
|
|
467
|
+
* but can't address the element.
|
|
464
468
|
*
|
|
465
|
-
* In `speed: 'instant'`, all humanization is skipped
|
|
466
|
-
* native `locator.click()`
|
|
469
|
+
* In `speed: 'instant'`, all humanization is skipped: element targets use
|
|
470
|
+
* Playwright's native `locator.click()`; a `Point` dispatches one
|
|
471
|
+
* `mouse.click()` at the coordinates.
|
|
467
472
|
*/
|
|
468
|
-
click(target:
|
|
473
|
+
click(target: MouseTarget): Promise<void>;
|
|
469
474
|
/**
|
|
470
475
|
* Right-click `target` — opens a native context menu. Same Bezier-path
|
|
471
476
|
* motion and hover dwell as `click()`; only the dispatched button differs.
|
|
477
|
+
* Accepts the same selector / `Locator` / `Point` targets as `click()`.
|
|
472
478
|
*
|
|
473
|
-
* In `speed: 'instant'`,
|
|
479
|
+
* In `speed: 'instant'`, element targets fall back to
|
|
480
|
+
* `locator.click({ button: 'right' })`; a `Point` dispatches one
|
|
481
|
+
* `mouse.click({ button: 'right' })` at the coordinates.
|
|
474
482
|
*/
|
|
475
|
-
rightClick(target:
|
|
483
|
+
rightClick(target: MouseTarget): Promise<void>;
|
|
476
484
|
/**
|
|
477
485
|
* Move the cursor to `target` along a humanized Bezier path and settle
|
|
478
486
|
* on it — no click is dispatched. Useful for hover-triggered UI
|
|
@@ -670,6 +678,102 @@ interface Human {
|
|
|
670
678
|
*/
|
|
671
679
|
record(fn: () => Promise<void>): Promise<Recording>;
|
|
672
680
|
record(options: HumanRecordOptions, fn: () => Promise<void>): Promise<Recording>;
|
|
681
|
+
/**
|
|
682
|
+
* Take a screenshot of the page. Forwards to `page.screenshot(options)`
|
|
683
|
+
* unchanged — see Playwright docs for the full options shape.
|
|
684
|
+
*
|
|
685
|
+
* Not a humanized action: no plugin events fire. Pure ergonomic
|
|
686
|
+
* re-export so `human.*` stays a single surface.
|
|
687
|
+
*/
|
|
688
|
+
screenshot(options?: Parameters<Page['screenshot']>[0]): Promise<Buffer>;
|
|
689
|
+
/**
|
|
690
|
+
* Visible text content of the page (`document.body.innerText`). Forwards
|
|
691
|
+
* to `page.innerText('body')`. Useful for AI agents that need to
|
|
692
|
+
* understand what's on screen without parsing HTML.
|
|
693
|
+
*
|
|
694
|
+
* For a region instead of the whole page, use `page.innerText(selector)`.
|
|
695
|
+
*
|
|
696
|
+
* Not a humanized action: no plugin events fire.
|
|
697
|
+
*/
|
|
698
|
+
pageText(): Promise<string>;
|
|
699
|
+
/**
|
|
700
|
+
* Full HTML of the page. Forwards to `page.content()`. Often large
|
|
701
|
+
* (50–500 KB on typical sites) — prefer {@link Human.pageText} when
|
|
702
|
+
* passing to an LLM unless structure matters.
|
|
703
|
+
*
|
|
704
|
+
* Not a humanized action: no plugin events fire.
|
|
705
|
+
*/
|
|
706
|
+
content(): Promise<string>;
|
|
707
|
+
/**
|
|
708
|
+
* Current URL of the page. Forwards to `page.url()`. Synchronous return
|
|
709
|
+
* because Playwright's underlying API is sync.
|
|
710
|
+
*
|
|
711
|
+
* Not a humanized action: no plugin events fire.
|
|
712
|
+
*/
|
|
713
|
+
url(): string;
|
|
714
|
+
/**
|
|
715
|
+
* Current document title. Forwards to `page.title()`.
|
|
716
|
+
*
|
|
717
|
+
* Not a humanized action: no plugin events fire.
|
|
718
|
+
*/
|
|
719
|
+
title(): Promise<string>;
|
|
720
|
+
/**
|
|
721
|
+
* Reload the current page. Forwards to `page.reload(options)`. Real-user
|
|
722
|
+
* analog of hitting the refresh button — the click motion is *not*
|
|
723
|
+
* humanized (we treat reload as navigation, not a cursor action).
|
|
724
|
+
*
|
|
725
|
+
* Plugins observe a `'reload'` action.
|
|
726
|
+
*/
|
|
727
|
+
reload(options?: Parameters<Page['reload']>[0]): Promise<void>;
|
|
728
|
+
/**
|
|
729
|
+
* Navigate back in the browser history. Forwards to `page.goBack(options)`.
|
|
730
|
+
*
|
|
731
|
+
* Plugins observe a `'goBack'` action.
|
|
732
|
+
*/
|
|
733
|
+
goBack(options?: Parameters<Page['goBack']>[0]): Promise<void>;
|
|
734
|
+
/**
|
|
735
|
+
* Navigate forward in the browser history. Forwards to
|
|
736
|
+
* `page.goForward(options)`.
|
|
737
|
+
*
|
|
738
|
+
* Plugins observe a `'goForward'` action.
|
|
739
|
+
*/
|
|
740
|
+
goForward(options?: Parameters<Page['goForward']>[0]): Promise<void>;
|
|
741
|
+
/**
|
|
742
|
+
* Wait until the page reaches the specified load state. Forwards to
|
|
743
|
+
* `page.waitForLoadState(state, options)`. Common after a humanized
|
|
744
|
+
* click that triggers navigation — gives the page time to settle before
|
|
745
|
+
* the next action.
|
|
746
|
+
*
|
|
747
|
+
* Not a humanized action: no plugin events fire.
|
|
748
|
+
*/
|
|
749
|
+
waitForLoadState(state?: Parameters<Page['waitForLoadState']>[0], options?: Parameters<Page['waitForLoadState']>[1]): Promise<void>;
|
|
750
|
+
/**
|
|
751
|
+
* Wait until the page's URL matches `url` (string, RegExp, or predicate).
|
|
752
|
+
* Forwards to `page.waitForURL(url, options)`. Common post-action wait
|
|
753
|
+
* (e.g. after `human.click('#login')`, wait for `/dashboard`).
|
|
754
|
+
*
|
|
755
|
+
* Not a humanized action: no plugin events fire.
|
|
756
|
+
*/
|
|
757
|
+
waitForURL(url: Parameters<Page['waitForURL']>[0], options?: Parameters<Page['waitForURL']>[1]): Promise<void>;
|
|
758
|
+
/**
|
|
759
|
+
* Resize the viewport. Forwards to `page.setViewportSize(size)`. Useful
|
|
760
|
+
* for testing responsive layouts or switching between breakpoints
|
|
761
|
+
* mid-session.
|
|
762
|
+
*
|
|
763
|
+
* Not a humanized action: no plugin events fire.
|
|
764
|
+
*/
|
|
765
|
+
setViewportSize(size: {
|
|
766
|
+
width: number;
|
|
767
|
+
height: number;
|
|
768
|
+
}): Promise<void>;
|
|
769
|
+
/**
|
|
770
|
+
* Render the page as a PDF. Forwards to `page.pdf(options)`. Chromium
|
|
771
|
+
* only; works most reliably in headless mode (in headed mode, Playwright
|
|
772
|
+
* silently switches to a print-style render).
|
|
773
|
+
*
|
|
774
|
+
* Not a humanized action: no plugin events fire.
|
|
775
|
+
*/
|
|
776
|
+
pdf(options?: Parameters<Page['pdf']>[0]): Promise<Buffer>;
|
|
673
777
|
}
|
|
674
778
|
/** Options for {@link Human.record}. */
|
|
675
779
|
interface HumanRecordOptions {
|
package/dist/index.d.ts
CHANGED
|
@@ -458,21 +458,29 @@ interface Human {
|
|
|
458
458
|
/**
|
|
459
459
|
* Move the mouse along a humanized Bezier path to `target` and click.
|
|
460
460
|
*
|
|
461
|
-
* `target` accepts
|
|
462
|
-
* `'button:has-text("Buy now")'`)
|
|
463
|
-
*
|
|
461
|
+
* `target` accepts a Playwright-compatible selector string (e.g.
|
|
462
|
+
* `'button:has-text("Buy now")'`), a built `Locator`, or a raw `Point`.
|
|
463
|
+
* For element targets the click point is Gaussian-distributed around the
|
|
464
|
+
* center; for a raw `Point` the exact coordinates are clicked. The
|
|
465
|
+
* `Point` form is the fallback for things with no clean selector —
|
|
466
|
+
* icon-only buttons, canvas, SVG — where you can see the pixel position
|
|
467
|
+
* but can't address the element.
|
|
464
468
|
*
|
|
465
|
-
* In `speed: 'instant'`, all humanization is skipped
|
|
466
|
-
* native `locator.click()`
|
|
469
|
+
* In `speed: 'instant'`, all humanization is skipped: element targets use
|
|
470
|
+
* Playwright's native `locator.click()`; a `Point` dispatches one
|
|
471
|
+
* `mouse.click()` at the coordinates.
|
|
467
472
|
*/
|
|
468
|
-
click(target:
|
|
473
|
+
click(target: MouseTarget): Promise<void>;
|
|
469
474
|
/**
|
|
470
475
|
* Right-click `target` — opens a native context menu. Same Bezier-path
|
|
471
476
|
* motion and hover dwell as `click()`; only the dispatched button differs.
|
|
477
|
+
* Accepts the same selector / `Locator` / `Point` targets as `click()`.
|
|
472
478
|
*
|
|
473
|
-
* In `speed: 'instant'`,
|
|
479
|
+
* In `speed: 'instant'`, element targets fall back to
|
|
480
|
+
* `locator.click({ button: 'right' })`; a `Point` dispatches one
|
|
481
|
+
* `mouse.click({ button: 'right' })` at the coordinates.
|
|
474
482
|
*/
|
|
475
|
-
rightClick(target:
|
|
483
|
+
rightClick(target: MouseTarget): Promise<void>;
|
|
476
484
|
/**
|
|
477
485
|
* Move the cursor to `target` along a humanized Bezier path and settle
|
|
478
486
|
* on it — no click is dispatched. Useful for hover-triggered UI
|
|
@@ -670,6 +678,102 @@ interface Human {
|
|
|
670
678
|
*/
|
|
671
679
|
record(fn: () => Promise<void>): Promise<Recording>;
|
|
672
680
|
record(options: HumanRecordOptions, fn: () => Promise<void>): Promise<Recording>;
|
|
681
|
+
/**
|
|
682
|
+
* Take a screenshot of the page. Forwards to `page.screenshot(options)`
|
|
683
|
+
* unchanged — see Playwright docs for the full options shape.
|
|
684
|
+
*
|
|
685
|
+
* Not a humanized action: no plugin events fire. Pure ergonomic
|
|
686
|
+
* re-export so `human.*` stays a single surface.
|
|
687
|
+
*/
|
|
688
|
+
screenshot(options?: Parameters<Page['screenshot']>[0]): Promise<Buffer>;
|
|
689
|
+
/**
|
|
690
|
+
* Visible text content of the page (`document.body.innerText`). Forwards
|
|
691
|
+
* to `page.innerText('body')`. Useful for AI agents that need to
|
|
692
|
+
* understand what's on screen without parsing HTML.
|
|
693
|
+
*
|
|
694
|
+
* For a region instead of the whole page, use `page.innerText(selector)`.
|
|
695
|
+
*
|
|
696
|
+
* Not a humanized action: no plugin events fire.
|
|
697
|
+
*/
|
|
698
|
+
pageText(): Promise<string>;
|
|
699
|
+
/**
|
|
700
|
+
* Full HTML of the page. Forwards to `page.content()`. Often large
|
|
701
|
+
* (50–500 KB on typical sites) — prefer {@link Human.pageText} when
|
|
702
|
+
* passing to an LLM unless structure matters.
|
|
703
|
+
*
|
|
704
|
+
* Not a humanized action: no plugin events fire.
|
|
705
|
+
*/
|
|
706
|
+
content(): Promise<string>;
|
|
707
|
+
/**
|
|
708
|
+
* Current URL of the page. Forwards to `page.url()`. Synchronous return
|
|
709
|
+
* because Playwright's underlying API is sync.
|
|
710
|
+
*
|
|
711
|
+
* Not a humanized action: no plugin events fire.
|
|
712
|
+
*/
|
|
713
|
+
url(): string;
|
|
714
|
+
/**
|
|
715
|
+
* Current document title. Forwards to `page.title()`.
|
|
716
|
+
*
|
|
717
|
+
* Not a humanized action: no plugin events fire.
|
|
718
|
+
*/
|
|
719
|
+
title(): Promise<string>;
|
|
720
|
+
/**
|
|
721
|
+
* Reload the current page. Forwards to `page.reload(options)`. Real-user
|
|
722
|
+
* analog of hitting the refresh button — the click motion is *not*
|
|
723
|
+
* humanized (we treat reload as navigation, not a cursor action).
|
|
724
|
+
*
|
|
725
|
+
* Plugins observe a `'reload'` action.
|
|
726
|
+
*/
|
|
727
|
+
reload(options?: Parameters<Page['reload']>[0]): Promise<void>;
|
|
728
|
+
/**
|
|
729
|
+
* Navigate back in the browser history. Forwards to `page.goBack(options)`.
|
|
730
|
+
*
|
|
731
|
+
* Plugins observe a `'goBack'` action.
|
|
732
|
+
*/
|
|
733
|
+
goBack(options?: Parameters<Page['goBack']>[0]): Promise<void>;
|
|
734
|
+
/**
|
|
735
|
+
* Navigate forward in the browser history. Forwards to
|
|
736
|
+
* `page.goForward(options)`.
|
|
737
|
+
*
|
|
738
|
+
* Plugins observe a `'goForward'` action.
|
|
739
|
+
*/
|
|
740
|
+
goForward(options?: Parameters<Page['goForward']>[0]): Promise<void>;
|
|
741
|
+
/**
|
|
742
|
+
* Wait until the page reaches the specified load state. Forwards to
|
|
743
|
+
* `page.waitForLoadState(state, options)`. Common after a humanized
|
|
744
|
+
* click that triggers navigation — gives the page time to settle before
|
|
745
|
+
* the next action.
|
|
746
|
+
*
|
|
747
|
+
* Not a humanized action: no plugin events fire.
|
|
748
|
+
*/
|
|
749
|
+
waitForLoadState(state?: Parameters<Page['waitForLoadState']>[0], options?: Parameters<Page['waitForLoadState']>[1]): Promise<void>;
|
|
750
|
+
/**
|
|
751
|
+
* Wait until the page's URL matches `url` (string, RegExp, or predicate).
|
|
752
|
+
* Forwards to `page.waitForURL(url, options)`. Common post-action wait
|
|
753
|
+
* (e.g. after `human.click('#login')`, wait for `/dashboard`).
|
|
754
|
+
*
|
|
755
|
+
* Not a humanized action: no plugin events fire.
|
|
756
|
+
*/
|
|
757
|
+
waitForURL(url: Parameters<Page['waitForURL']>[0], options?: Parameters<Page['waitForURL']>[1]): Promise<void>;
|
|
758
|
+
/**
|
|
759
|
+
* Resize the viewport. Forwards to `page.setViewportSize(size)`. Useful
|
|
760
|
+
* for testing responsive layouts or switching between breakpoints
|
|
761
|
+
* mid-session.
|
|
762
|
+
*
|
|
763
|
+
* Not a humanized action: no plugin events fire.
|
|
764
|
+
*/
|
|
765
|
+
setViewportSize(size: {
|
|
766
|
+
width: number;
|
|
767
|
+
height: number;
|
|
768
|
+
}): Promise<void>;
|
|
769
|
+
/**
|
|
770
|
+
* Render the page as a PDF. Forwards to `page.pdf(options)`. Chromium
|
|
771
|
+
* only; works most reliably in headless mode (in headed mode, Playwright
|
|
772
|
+
* silently switches to a print-style render).
|
|
773
|
+
*
|
|
774
|
+
* Not a humanized action: no plugin events fire.
|
|
775
|
+
*/
|
|
776
|
+
pdf(options?: Parameters<Page['pdf']>[0]): Promise<Buffer>;
|
|
673
777
|
}
|
|
674
778
|
/** Options for {@link Human.record}. */
|
|
675
779
|
interface HumanRecordOptions {
|
package/dist/index.js
CHANGED
|
@@ -320,15 +320,22 @@ function clamp(value, min, max) {
|
|
|
320
320
|
// src/mouse/index.ts
|
|
321
321
|
async function executeClick(target, ctx, options = {}) {
|
|
322
322
|
const button = options.button ?? "left";
|
|
323
|
-
const locator = typeof target === "string" ? ctx.page.locator(target) : target;
|
|
324
323
|
if (ctx.speed === "instant") {
|
|
325
|
-
|
|
324
|
+
if (isPoint(target)) {
|
|
325
|
+
await ctx.page.mouse.click(target.x, target.y, { button });
|
|
326
|
+
ctx.setMousePosition(target);
|
|
327
|
+
return { target };
|
|
328
|
+
}
|
|
329
|
+
const locator = typeof target === "string" ? ctx.page.locator(target) : target;
|
|
330
|
+
const box2 = await locator.boundingBox();
|
|
326
331
|
await locator.click({ button });
|
|
327
|
-
const center =
|
|
332
|
+
const center = box2 ? { x: box2.x + box2.width / 2, y: box2.y + box2.height / 2 } : ctx.getMousePosition();
|
|
328
333
|
ctx.setMousePosition(center);
|
|
329
334
|
return { target: center };
|
|
330
335
|
}
|
|
331
|
-
const targetPoint = await
|
|
336
|
+
const { point: targetPoint, box } = await resolveTargetPointAndBox(target, ctx, "click");
|
|
337
|
+
await maybeMisclickBeat(ctx, box, targetPoint);
|
|
338
|
+
await walkBezierTo(targetPoint, ctx);
|
|
332
339
|
const preClickMs = computeDwellTime(
|
|
333
340
|
ctx.personality.dwell.preClickMs,
|
|
334
341
|
ctx.personality.dwell.preClickJitter,
|
|
@@ -357,7 +364,7 @@ async function executeHover(target, ctx) {
|
|
|
357
364
|
ctx.setMousePosition(center);
|
|
358
365
|
return { target: center };
|
|
359
366
|
}
|
|
360
|
-
const targetPoint = await moveToTarget(target, ctx
|
|
367
|
+
const targetPoint = await moveToTarget(target, ctx);
|
|
361
368
|
const dwellMs = computeDwellTime(
|
|
362
369
|
ctx.personality.dwell.preClickMs,
|
|
363
370
|
ctx.personality.dwell.preClickJitter,
|
|
@@ -440,10 +447,9 @@ async function executeMove(target, ctx) {
|
|
|
440
447
|
ctx.setMousePosition(point);
|
|
441
448
|
return { target: point };
|
|
442
449
|
}
|
|
443
|
-
async function moveToTarget(target, ctx
|
|
444
|
-
const box = await readBoxWithAutoScroll(target, ctx,
|
|
450
|
+
async function moveToTarget(target, ctx) {
|
|
451
|
+
const box = await readBoxWithAutoScroll(target, ctx, "hover");
|
|
445
452
|
const targetPoint = pickClickPoint(box, ctx.rng, ctx.personality.mouse.clickSpread);
|
|
446
|
-
if (action === "click") await maybeMisclickBeat(ctx, box, targetPoint);
|
|
447
453
|
await walkBezierTo(targetPoint, ctx);
|
|
448
454
|
return targetPoint;
|
|
449
455
|
}
|
|
@@ -1428,6 +1434,52 @@ async function createHuman(page, options = {}) {
|
|
|
1428
1434
|
speed,
|
|
1429
1435
|
events
|
|
1430
1436
|
});
|
|
1437
|
+
},
|
|
1438
|
+
// ────────────────────────────────────────────────────────────────────
|
|
1439
|
+
// Thin re-exports of common Playwright `Page` methods. See the `Human`
|
|
1440
|
+
// interface for the rationale; implementations forward unchanged.
|
|
1441
|
+
// ────────────────────────────────────────────────────────────────────
|
|
1442
|
+
screenshot(opts) {
|
|
1443
|
+
return page.screenshot(opts);
|
|
1444
|
+
},
|
|
1445
|
+
pageText() {
|
|
1446
|
+
return page.innerText("body");
|
|
1447
|
+
},
|
|
1448
|
+
content() {
|
|
1449
|
+
return page.content();
|
|
1450
|
+
},
|
|
1451
|
+
url() {
|
|
1452
|
+
return page.url();
|
|
1453
|
+
},
|
|
1454
|
+
title() {
|
|
1455
|
+
return page.title();
|
|
1456
|
+
},
|
|
1457
|
+
async reload(opts) {
|
|
1458
|
+
await performAction({ type: "reload", params: {} }, async () => {
|
|
1459
|
+
await page.reload(opts);
|
|
1460
|
+
});
|
|
1461
|
+
},
|
|
1462
|
+
async goBack(opts) {
|
|
1463
|
+
await performAction({ type: "goBack", params: {} }, async () => {
|
|
1464
|
+
await page.goBack(opts);
|
|
1465
|
+
});
|
|
1466
|
+
},
|
|
1467
|
+
async goForward(opts) {
|
|
1468
|
+
await performAction({ type: "goForward", params: {} }, async () => {
|
|
1469
|
+
await page.goForward(opts);
|
|
1470
|
+
});
|
|
1471
|
+
},
|
|
1472
|
+
waitForLoadState(state, opts) {
|
|
1473
|
+
return page.waitForLoadState(state, opts);
|
|
1474
|
+
},
|
|
1475
|
+
waitForURL(url, opts) {
|
|
1476
|
+
return page.waitForURL(url, opts);
|
|
1477
|
+
},
|
|
1478
|
+
setViewportSize(size) {
|
|
1479
|
+
return page.setViewportSize(size);
|
|
1480
|
+
},
|
|
1481
|
+
pdf(opts) {
|
|
1482
|
+
return page.pdf(opts);
|
|
1431
1483
|
}
|
|
1432
1484
|
};
|
|
1433
1485
|
}
|