* test: add hover command cases
* test: add hover text error coverage
* feat: implement browser hover command
Add the `browser hover <selector>` command. Resolves the selector to a
DOM node via the shared element module, then dispatches mouseenter,
mouseover, and mousemove events via Runtime.callFunctionOn for reliable
hover semantics in headless Chrome. Wired up across CLI parsing, action
enum, router, and output formatting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: add focus command cases
* feat: implement browser focus command
Add the `browser focus <selector>` command. Resolves the selector via
the shared element module, uses DOM.focus to set focus on the target,
and compares pre/post active element by JS reference identity (===) to
correctly report focus_changed even for anonymous elements. Wired up
across CLI parsing, action enum, router, and output formatting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: add press command cases
* feat: implement browser press command
Add the `browser press <key-or-chord>` command. Parses single keys and
chord combinations (e.g. Control+A, Shift+Tab), validates modifier
segments, and dispatches keyDown/keyUp via CDP Input.dispatchKeyEvent
with the appropriate modifiers bitmask. Wired up across CLI parsing,
action enum, router, and output formatting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: add drag command cases
* feat: implement browser drag command
Adds drag-and-drop via CDP Input.dispatchMouseEvent sequence:
mousePressed at source → mouseMoved along path → mouseReleased at
destination. Destination accepts either a selector or x,y coordinates.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: drag dispatch via viewport resize + CDP Input events
CDP Input.dispatchMouseEvent requires elements to be within the visible
viewport. The drag fixture positions elements at top:780px which exceeds
the default headless Chrome viewport (~469px). Fix by temporarily
enlarging the viewport via Emulation.setDeviceMetricsOverride before
the drag sequence, then clearing the override after completion.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: resize viewport before resolving drag coordinates
Move Emulation.setDeviceMetricsOverride before element resolution so
coordinates are captured under the final viewport. Avoids stale
coordinates on responsive pages where a post-resolution resize could
shift element positions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: preserve viewport width during drag, only expand height if needed
Read the current viewport dimensions and only override if the height is
too short for the drag endpoints. Width is preserved to avoid flipping
responsive breakpoints or triggering resize handlers. The override is
skipped entirely when the viewport is already tall enough.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: add upload command cases
* feat: implement browser upload command
Adds `browser upload <selector> <file...> --session --tab` which sets
files on a file input via CDP DOM.setFileInputFiles. Validates that all
paths are absolute, resolves the target node, and returns a value_summary
with file list and count. All 10 e2e tests pass.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: require at least one file path in browser upload
Adds `#[arg(required = true, num_args = 1..)]` to the `files` field so
Clap rejects invocations with zero files at parse time, matching the
spec's `<file...>` contract. Adds a unit test for the missing-files case.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: add eval command cases
* fix: update browser eval to return typed value, type, and preview per spec
- Return `data.value` as typed JSON (number/bool/string) instead of
always stringifying
- Add `data.type` (JS type from CDP) and `data.preview` (string repr)
- Return null context for SESSION_NOT_FOUND
- Extract exception description for better EVAL_FAILED error messages
- Update cloud eval tests to assert typed values
All 11 eval tests pass (8 interaction + 3 cloud).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: add eval context coverage
* fix: include tab URL and title in browser eval context
Fetches the current page URL and title after eval execution and returns
them in the response context, matching the spec contract for tab-scoped
commands. Tests now assert context.url and context.title are present.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: add mouse-move command cases
* feat: implement browser mouse-move command
Adds `browser mouse-move <x,y> --session --tab` which dispatches a CDP
Input.dispatchMouseEvent (mouseMoved) at the given coordinates. Parses
and validates x,y format, tracks url/focus changes, returns context with
tab URL and title. All 8 e2e tests pass.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: add cursor-position command cases
* test: add cursor-position text status check
* feat: implement browser cursor-position command
Adds cursor-position command that returns the last known cursor position
for a tab. Position is stored in SessionRegistry when mouse-move is
executed, using the existing session_id\0tab_id composite key pattern.
Wired in all 6 registration points: mod.rs, action.rs, cli.rs (enum +
to_action + command_name + context), router.rs, output.rs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: track cursor position in click, drag, and hover commands
cursor-position was only updated by mouse-move. Now click, drag, and
hover also store the final pointer coordinates in SessionRegistry so
that cursor-position reflects the true position after any mouse action.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: add regression test for click -> cursor-position tracking
Verifies that cursor-position reflects coordinates from a click action,
not just mouse-move. Covers the contract gap identified in review.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: add scroll command cases
* test: add scroll changed field checks
* feat: implement browser scroll commands
Adds scroll command with three subcommand forms:
- Directional: scroll up|down|left|right <pixels>
- Edge: scroll top|bottom
- Into-view: scroll into-view <selector> [--align start|center|end|nearest]
All forms support --container for scrolling within a specific element.
Tracks scroll_changed, url_changed, focus_changed in response data.
Wired in all 6 registration points.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: add scroll xpath selector coverage
* fix: use resolved CDP nodes for scroll selectors instead of querySelector
Refactored scroll to resolve selectors via element::resolve_node +
DOM.resolveNode → objectId, then use Runtime.callFunctionOn for all
scroll operations. This correctly supports CSS, XPath, and @eN selectors
per the API contract, instead of raw querySelector which only handles CSS.
Added DOM.getDocument init call to ensure XPath DOM.requestNode works.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- SoloEnv::Drop: wait for daemon exit + clean up daemon.sock/ready/pid
files (SIGKILL prevents daemon's own cleanup)
- cloud_crash_recovery_endpoint_gone: add real assertions to all branches
(was a no-op test that could never fail)
- Restore cloud_crash_recovery_reconnect test (was deleted in refactor)
- Add SessionGuard to lifecycle_close_s1t2 and lifecycle_double_close
tests (prevent session leak on panic)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Extract common helpers to harness.rs (assert_meta, assert_error_envelope,
assert_tab_id, start_session, close_session, new_tab_json, etc.)
- Add local HTTP server to eliminate external network dependency
- Introduce SoloEnv for tests needing isolated ACTIONBOOK_HOME
- Replace fixed sleep(500ms) with per-test session isolation
- Fix TempDir leak in cloud_mode (ChromeGuard now owns TempDir)
- Add PID to unique_session IDs to prevent cross-run collisions
- HTTP server: thread-per-connection + Connection: close header
- Restore all cloud_mode tests (groups 5b-15) that were missing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>