webview: add mouse.down/up/move primitives for drag automation - #29817
webview: add mouse.down/up/move primitives for drag automation#29817robobun wants to merge 9 commits into
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds low-level pointer primitives—mouseDown, mouseUp, mouseMove—to Bun.WebView across Chrome and WebKit backends. Introduces internal pointer state tracking, stepped movement interpolation, IPC/protocol additions, macOS ObjC runtime glue for synthetic mouse events, TypeScript typings, and tests exercising drag/hover/click/contextmenu behaviors and argument validation. Changes
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/bun-types/bun.d.ts`:
- Around line 8212-8222: The JSDoc for MouseMoveOptions.steps is misleading (it
suggests "intermediate events" count) but the runtime treats steps as the total
number of mousemove events; update the comment on the steps field in the
MouseMoveOptions interface to state that steps is the total number of dispatched
mousemove events including the final event (e.g., steps: 1 => a single event),
keep the default `@default` 1, and mention typical ranges (5–20) for smooth drags
so callers are not misled; reference MouseMoveOptions and the steps property
when making the change.
- Around line 8641-8665: The JSDoc for mouseMove incorrectly calls held-button
moves "dragover" (an HTML drag event); update the description in the mouseMove
comment (the block above mouseMove(x: number, y: number, options?:
WebView.MouseMoveOptions): Promise<void>) to say these are backend/native
dragged mouse/pointer events (e.g., "mouse drag"/"pointer drag" or "dragged
mouse/pointer events") rather than the DOM "dragover" event and add a short note
that this is not the HTML Drag and Drop API; keep references to
mouseDown/mouseUp and the examples intact.
In `@src/bun.js/webview/JSWebView.cpp`:
- Around line 228-287: mouseDown/mouseUp/mouseMove currently mutate
m_mouseButtons/m_mouseX/m_mouseY immediately; change them to only update
internal state after the dispatched JSPromise resolves successfully.
Specifically, in JSWebView::mouseDown, JSWebView::mouseUp and
JSWebView::mouseMove, do not assign m_mouseButtons/m_mouseX/m_mouseY before
calling CDP::Ops::... or WK::Ops::...; instead attach a success continuation to
the returned JSPromise that updates the appropriate members (m_mouseButtons for
mouseDown/mouseUp, m_mouseX/m_mouseY for mouseMove) and leave state unchanged on
rejection. Ensure you reference the same promise returned from
CDP::Ops::mouseDown/mouseUp/mouseMove and WK::Ops::mouseDown/mouseUp/mouseMove
when wiring the continuation so non-Darwin/Chrome branches still return a
promise.
In `@src/bun.js/webview/JSWebViewPrototype.cpp`:
- Around line 557-605: The jsWebViewProtoFuncMouseMove handler currently
defaults steps to 1 and uses s.toInt32(), which allows huge inputs to wrap and
prevents the host's special steps==0 single-final-event path; change this by
defaulting uint32_t steps = 0, read the "steps" field using
s.toNumber(globalObject) (check std::isfinite on the resulting double), convert
to an integer type safely (e.g. truncate/floor via static_cast<int64_t> after
the finite check), then clamp into the range [0, 1000] (allowing zero) before
assigning steps; keep the rest (mods via parseModifiers, checkSlot, and calling
thisObject->mouseMove) unchanged so the normalized steps is forwarded correctly.
In `@test/js/bun/webview/webview-chrome.test.ts`:
- Line 601: The test title is misleading: the it(...) call currently says
"chrome: mouseDown validates — x/y must be finite in mouseMove" but the test
body actually validates mouseMove finite-coordinate guards; update the string in
the it(...) declaration to reflect that (e.g., "chrome: mouseMove validates —
x/y must be finite" or "chrome: mouseMove validates — x/y must be finite in
mouseMove") so the test name matches the validation being performed.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 4757273d-e8d6-4dc0-904b-834639dc5d27
📒 Files selected for processing (16)
packages/bun-types/bun.d.tssrc/bun.js/webview/ChromeBackend.cppsrc/bun.js/webview/ChromeBackend.hsrc/bun.js/webview/JSWebView.cppsrc/bun.js/webview/JSWebView.hsrc/bun.js/webview/JSWebViewPrototype.cppsrc/bun.js/webview/ObjCRuntime.cppsrc/bun.js/webview/ObjCRuntime.hsrc/bun.js/webview/WebKitBackend.cppsrc/bun.js/webview/WebKitBackend.hsrc/bun.js/webview/WebViewHost.cppsrc/bun.js/webview/WebViewHost.hsrc/bun.js/webview/host_main.cppsrc/bun.js/webview/ipc_protocol.htest/js/bun/webview/webview-chrome.test.tstest/js/bun/webview/webview.test.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/bun.js/webview/WebViewHost.cpp`:
- Around line 418-480: The comment above mouseMoveIPC that reads "`steps`
intermediate events + one final" is misleading—given the loop (for i = 1; i <
steps; ++i) the code emits steps-1 intermediate events and then one final event
(total of steps events); update that comment near the steps handling/for-loop in
mouseMoveIPC to explicitly state "emits steps-1 intermediate events and one
final event (total = steps events)" so future readers match the actual loop
behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 83dbfbfa-ec63-45d1-8d9e-c619bc430902
📒 Files selected for processing (2)
src/bun.js/webview/ChromeBackend.cppsrc/bun.js/webview/WebViewHost.cpp
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/bun-types/bun.d.ts (1)
8203-8696: 🧹 Nitpick | 🔵 TrivialRun declaration tests directly for this
.d.tschange before merge.Please validate via bun-types type declaration tests directly (without
bun bd) for this file change.As per coding guidelines
packages/bun-types/**/*.d.ts: Run TypeScript type declaration tests directly withoutbun bdsince they don't touch compiled code.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/bun-types/bun.d.ts` around lines 8203 - 8696, Summary: The PR changed .d.ts typings and the reviewer asks you to run the bun-types declaration tests directly (not via `bun bd`) to validate the type changes. Fix: run the TypeScript declaration checks for the changed file(s) directly by invoking the TypeScript compiler (e.g. tsc --project packages/bun-types/tsconfig.json --noEmit) or your repository's direct type-test command against packages/bun-types so that the updated declarations (notably types/interfaces like WebView, Backend, ConsoleCapture, ConstructorOptions, MouseMoveOptions) compile without errors; do not run through `bun bd`; if errors appear, iterate on the affected symbols (e.g., WebView.evaluate, WebView.screenshot overloads, Backend union variants) until tsc --noEmit succeeds.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@packages/bun-types/bun.d.ts`:
- Around line 8203-8696: Summary: The PR changed .d.ts typings and the reviewer
asks you to run the bun-types declaration tests directly (not via `bun bd`) to
validate the type changes. Fix: run the TypeScript declaration checks for the
changed file(s) directly by invoking the TypeScript compiler (e.g. tsc --project
packages/bun-types/tsconfig.json --noEmit) or your repository's direct type-test
command against packages/bun-types so that the updated declarations (notably
types/interfaces like WebView, Backend, ConsoleCapture, ConstructorOptions,
MouseMoveOptions) compile without errors; do not run through `bun bd`; if errors
appear, iterate on the affected symbols (e.g., WebView.evaluate,
WebView.screenshot overloads, Backend union variants) until tsc --noEmit
succeeds.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 7face990-b5ce-4a87-920e-8b2b0bcb92fc
📒 Files selected for processing (4)
packages/bun-types/bun.d.tssrc/bun.js/webview/JSWebView.cppsrc/bun.js/webview/JSWebViewPrototype.cpptest/js/bun/webview/webview-chrome.test.ts
There was a problem hiding this comment.
♻️ Duplicate comments (1)
src/bun.js/webview/WebViewHost.cpp (1)
418-425:⚠️ Potential issue | 🟡 MinorFix stale event-count wording in the
mouseMoveheader comment.Line 418 says "
stepsintermediate events + one final", but the loop emitssteps - 1intermediates plus the final event. This is the same mismatch previously flagged.Proposed comment-only fix
-// mouseMove: dispatch `steps` intermediate events + one final. When +// mouseMove: dispatch `steps - 1` intermediate events + one final. When🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/bun.js/webview/WebViewHost.cpp` around lines 418 - 425, The header comment for mouseMove is incorrect about the number of intermediate events: update the comment in WebViewHost.cpp (mouseMove) to state that the loop emits steps - 1 intermediate events plus one final event (not "steps" intermediates), and adjust surrounding phrasing that references "intermediate events + one final" so it consistently reflects "steps - 1 intermediates and one final"; keep existing references to buttonsMask, mouseMoved:, mouseDragged and mouseEventQueue to preserve context.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@src/bun.js/webview/WebViewHost.cpp`:
- Around line 418-425: The header comment for mouseMove is incorrect about the
number of intermediate events: update the comment in WebViewHost.cpp (mouseMove)
to state that the loop emits steps - 1 intermediate events plus one final event
(not "steps" intermediates), and adjust surrounding phrasing that references
"intermediate events + one final" so it consistently reflects "steps - 1
intermediates and one final"; keep existing references to buttonsMask,
mouseMoved:, mouseDragged and mouseEventQueue to preserve context.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 3af6d572-fdb0-48a8-b833-a76e5deade67
📒 Files selected for processing (1)
src/bun.js/webview/WebViewHost.cpp
|
Updated analysis after looking at the darwin logs:
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/bun.js/webview/ObjCRuntime.cpp`:
- Around line 448-467: The comment says the swizzle failure is "Logged via
m_loadError" but the code using getClassMethod(NSEvent::cls,
sel("pressedMouseButtons")) does not set m_loadError or otherwise log on
failure; update the code to set m_loadError (or call the existing diagnostic
logger) when getClassMethod returns null so a clear message is recorded (include
class NSEvent and selector "pressedMouseButtons" and that
methodSetImplementation was not applied), referencing pressedMouseButtonsImpl,
getClassMethod, methodSetImplementation and m_loadError; alternatively, if you
prefer no runtime diagnostic, change the comment to state the swizzle silently
falls back instead of claiming it is logged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: f7f56745-93e8-4b57-858e-173a91e08343
📒 Files selected for processing (3)
src/bun.js/webview/ObjCRuntime.cppsrc/bun.js/webview/ObjCRuntime.hsrc/bun.js/webview/WebViewHost.cpp
|
✅ Build 48494: all 6 darwin test-bun shards pass — my WebKit fix works on macOS 14/15/26 aarch64 and 14 x64. Full The 9 remaining CI failures are all pre-existing flakes on unrelated shards:
None of the flaky failures touch WebView code. |
Adds three low-level pointer primitives to Bun.WebView:
view.mouseDown(options?) — press button at current position
view.mouseUp(options?) — release button at current position
view.mouseMove(x, y, options?) — move to (x,y), optional steps
Canvas drag-and-drop tests that rely on intermediate pointermove
events can now run on both Chrome and WebKit backends without
dropping to raw CDP:
await view.mouseMove(from.x, from.y);
await view.mouseDown();
await view.mouseMove(to.x, to.y, { steps: 5 });
await view.mouseUp();
- Parent tracks cursor position (m_mouseX/Y) and pressed-button mask
(m_mouseButtons) on JSWebView; down/up/move update accordingly.
- Chrome backend emits Input.dispatchMouseEvent with the right
button/buttons fields; multi-step moves send (steps-1) fire-and-
forget events + a tracked final that resolves the promise.
- WebKit backend synthesizes NSEvents (LeftMouseDown/Up,
LeftMouseDragged/RightMouseDragged/OtherMouseDragged) and uses
_simulateMouseMove: SPI for plain hovers. Events go through the
existing _doAfterProcessingAllPendingMouseEvents: barrier — the
promise resolves only after WebContent has dispatched every
handler, same guarantee click() provides.
All events fire with isTrusted:true.
…p steps via double - JSWebView.cpp: mouseDown/Up/Move only mutate m_mouseX/Y/Buttons when the returned promise isn't synchronously rejected (dead transport). Async rejections still stale the state, but the view is unusable past that point so every follow-up op will reject too. - JSWebViewPrototype.cpp: read steps as a double, clamp in [1, 1000], then cast. toInt32() on values above 2^31 wraps to negative, so steps: 1e12 previously clamped-up to 1 instead of the 1000 cap. - bun.d.ts: clarify that `steps` is the TOTAL event count (1 = single event at target), not an intermediate count; clarify mouseMove with a button held fires native dragged mouse/pointer events, not the HTML5 Drag and Drop API's dragover. - test: rename 'mouseDown validates' -> 'mouseMove validates' (the body tests mouseMove guards, not mouseDown).
The loop emits (steps - 1) intermediates + 1 final = steps total events, not 'steps intermediate + one final' as the comment suggested. Matches ChromeBackend.cpp's wording.
…Kit) CI surfaced a spec-correctness gap in the WebKit backend: event.buttons in mousedown/mouseup/contextmenu handlers always read as 0 for synthesized events, breaking drag tests that observe the button-held bitmask to distinguish hover-move from drag-move. The cause: WebCore's PlatformEventFactoryMac computes event.buttons via '+[NSEvent pressedMouseButtons]', which is the system-wide HID state. For NSEvent objects we synthesize at the WKWebView responder level, no physical button is down, so this returns 0. Fix, same mechanism Safari's WebDriver uses (WebAutomationSessionMac.mm:80): swap the class method implementation of '+[NSEvent pressedMouseButtons]' to return a global 'NSEvent::s_trackedButtonsMask' that the host sets before each mouseDown/Up/Move dispatch. Theirs is scope-limited with a scope_exit; ours is permanent — the WebView host is a headless subprocess, we never want real HID state. - ObjCRuntime.h/.cpp: declare s_trackedButtonsMask, dlsym class_getClassMethod + method_setImplementation, swap the impl at load() time. Permanent, non-fatal if the swap fails (event.buttons just stays 0 in that case). - WebViewHost.cpp: stamp the mask before mouseDownIPC/mouseUpIPC/ mouseMoveIPC dispatch. JSWebView already computes the post-op mask (mousedown sees buttons WITH the pressed bit, mouseup WITHOUT) and threads it through IPC. - click()/doNativeClick unchanged — its callers don't observe event.buttons, only button/detail/modifiers.
Drag-sequence test timed out on macOS 14/15 aarch64 only: the first view.mouseMove(x, y) call (no button held) uses _simulateMouseMove: which enqueues into mouseEventQueue but WebContent never drains it on that OS/arch combo. The _doAfterProcessingAllPendingMouseEvents: barrier then waits forever and bun:test hits its 90s timeout. Fix: on WebKit, skip the NSEvent dispatch for hover (buttonsMask==0) moves. Parent-side cursor tracking (m_mouseX/Y on JSWebView) already runs, so a following mouseDown fires at the correct position — which is the primary use case (drag automation). DOM :hover / cursor CSS won't update on WebKit until someone wires a CGEvent-based hover (screen-level, following WebAutomationSessionMac's wheel path); left for a future PR. Drag moves (button held) still dispatch normally via mouseDragged: / rightMouseDragged: / otherMouseDragged: — those route through the responder chain and the barrier drains them because the prior mouseDown: already queued onto WebContent. Test update: the drag-sequence test no longer asserts on an initial hover mousemove event (it's not dispatched anymore). Chrome-backend tests are unchanged since CDP's mouseMoved dispatch works for hover at any button state. Confirmed working on macOS 26 aarch64 (full suite passed last run) and the reference darwin-14 aarch64 shard hung specifically at the test's first view.mouseMove(40, 40) call.
Four fixes from review: - WebViewHost::mouseMoveIPC picked RightMouseDragged when buttonsMask had bit 0 AND bit 1 set (left + right held) — the 0x2 check landed first and there was no explicit 0x1 guard before it, so the LeftDrag default only survived when bit 0 was the ONLY bit set, not when it was the lowest set bit. Same for 0x5 (left + middle) falling through to OtherDrag. Adds an explicit `if (buttonsMask & 0x1)` branch that keeps LeftDrag so 0x3/0x5/0x7 all dispatch as left-drag NSEvents, matching the Chrome backend's selector priority in ChromeBackend::mouseMove. - Function header above mouseMoveIPC was stale: said "steps intermediate events + one final" (now correctly "(steps-1) intermediate + 1 final = steps total") and "fire MouseMoved via mouseMoved:" when buttonsMask==0 (actually sync-Acks without dispatching — _simulateMouseMove: hangs the barrier on macOS 14/15 aarch64). - ipc_protocol.h MouseMovePayload comment said "the parent expands before send" (host does the interpolation) and "fires steps+1 NSEvents" (fires exactly `steps`). - ObjCRuntime.cpp comment claimed swizzle failure is "Logged via m_loadError" but the getClassMethod branch is silent — clarified that failure is intentionally silent because every AppKit target has the method. - bun.d.ts JSDoc promised standalone hover "works for :hover styles" unconditionally, but WebKit short-circuits no-button moves (see the hover-path rationale in WebViewHost.cpp). Qualified to say Chrome only; users needing :hover on WebKit know to pick the Chrome backend.
Same stale wording swept out of bun.d.ts in c120e99 and WebViewHost.cpp / ipc_protocol.h in 6b13ba6 survived in ChromeBackend.cpp's mouseMove function header. CDP `Input.dispatchMouseEvent type:"mouseMoved"` with a non-zero `buttons` field fires `mousemove`/`pointermove` only — HTML5 DnD events require a `draggable` element starting the drag page-side (or `Input.dispatchDragEvent`, not used). Comment-only.
The process-wide +[NSEvent pressedMouseButtons] swizzle (from ObjCRuntime.cpp) lets synthesized NSEvents report the correct DOM event.buttons. The low-level mouseDown/Up/Move primitives stamp the static before dispatch; doNativeClick (backing view.click(x,y) / view.click(selector)) did not, so a prior unbalanced mouseDown on this view or a sibling view would leak its mask into click()'s DOM events — mousedown/mouseup would report whatever the static was last set to. Fix: stamp the pressing bit before each mouseDown and clear before each mouseUp in doNativeClick, matching the primitives. Bonus: click()'s event.buttons is now spec-correct (mousedown includes the pressing bit, mouseup excludes it) instead of whatever the real HID state was pre-PR (always 0 in a headless host).
ff0a5d6 to
c9237ab
Compare
There was a problem hiding this comment.
No issues found on this pass — all prior review feedback has been addressed — but this adds a new public Bun.WebView API surface plus process-wide +[NSEvent pressedMouseButtons] swizzling and cross-backend native input synthesis, so it's worth a human sign-off on the API shape and the WebKit hover-is-a-no-op limitation before merge.
Extended reasoning...
Overview
This PR adds three new public methods to Bun.WebView (mouseDown, mouseUp, mouseMove) for drag automation, spanning 16 files: TypeScript declarations, the JSWebView prototype/state layer, both the Chrome (CDP) and WebKit (WKWebView host subprocess) backends, the IPC wire protocol, ObjC runtime glue (including a permanent method-swizzle of +[NSEvent pressedMouseButtons]), and ~270 lines of new tests across both backend suites.
Security risks
None identified. Inputs are validated (finite x/y, clamped steps to [1,1000], clamped clickCount), the IPC payloads are fixed-size POD structs with static_assert size checks, and the swizzle is confined to the headless WebKit host subprocess which never handles real user input. No injection, auth, or data-exposure surface.
Level of scrutiny
High. This is a new user-facing API (Playwright-style page.mouse.* semantics) with backend-divergent behavior that's now documented (Chrome fires hover mousemove; WebKit intentionally no-ops hover and only updates internal cursor position). The ObjC method swizzle is process-global and affects the pre-existing click() path (now stamps s_trackedButtonsMask per the fix in c9237ab). The cross-backend event-count semantics, the parent-side state tracking (m_mouseX/Y/Buttons), and the fire-and-forget intermediate CDP events are all design choices a maintainer should ratify.
Other factors
The PR has been through several review rounds (CodeRabbit + claude inline comments) and every flagged issue — steps toInt32 wrap, sync-rejection state guard, multi-button drag selector priority, stale comments in three files, the doNativeClick cross-view mask leak, and JSDoc accuracy for the WebKit hover limitation — has been addressed in follow-up commits with all threads resolved. CI darwin shards pass per the author's build-48494 note; remaining failures are documented as unrelated flakes. Test coverage looks solid (drag sequence, hover, click synthesis, contextmenu+modifiers, NaN/Inf validation, prototype existence). The remaining reason to defer is purely scope: new public API + native input synthesis + ObjC swizzling is the kind of change that benefits from a human reviewer confirming the API contract and the documented WebKit limitation are acceptable.
Closes #29815.
Adds three low-level pointer primitives to
Bun.WebViewso canvasdrag-and-drop tests (and other flows that need intermediate
pointermoveevents while a button is held) no longer have todrop to raw CDP:
Use case
The classic canvas drag pattern from the issue now runs unchanged on
both Chrome and WebKit backends:
Behavior
mouseDown/mouseUptake no coords — they use the positionlast set by
mouseMove(defaulting to(0,0)if never moved).Matches Playwright's
page.mouse.*semantics.mouseMovedispatchesstepsintermediate events interpolatedlinearly from the current position to
(x, y), plus one finalevent at the target. Default
steps: 1= single event.mouseDown), moves fire asmousedrag/dragover(WebKit usesmouseDragged:variants;Chrome sends
mouseMovedwith non-zerobuttonsfield).Without a prior down,
mouseMoveis a plain hover — useful for:hoverstyle assertions.m_mouseX,m_mouseY, andm_mouseButtons(bitmask of held buttons).Backend details
Chrome (CDP):
Input.dispatchMouseEventwith the correctbutton/buttonsfields. Multi-step moves sendsteps-1fire-and-forget events + one tracked final event that resolves the
promise — Chrome processes events in order, so the final reply means
all previous ones landed too.
WebKit (WKWebView host subprocess): Synthesized
NSEvents(
LeftMouseDown/Up,LeftMouseDragged/RightMouseDragged/OtherMouseDragged) dispatched via the public responder selectors.Plain moves (no button held) use the
_simulateMouseMove:SPI —the public
mouseMoved:doesn't route to WebContent withoutacceptsMouseMovedEvents:YESand a tracking area. Every op waitson
_doAfterProcessingAllPendingMouseEvents:— the promiseresolves only after WebContent has processed every event and run all
JS handlers (same barrier
click()uses).Tests
test/js/bun/webview/webview.test.ts(WebKit, macOS) andtest/js/bun/webview/webview-chrome.test.ts(cross-platform) eachcover:
contextmenuwith the rightbutton/buttonsbitmaskx/yNaN/Infinity validation inmouseMoveMethod-existence test (
WebView prototype exposes mouseDown/mouseUp/ mouseMove) runs on every platform — fails on pre-fix main, passesafter.