Auto-generated PR for branch: new-tests
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Improve CI test discovery using recursive find and remove several
obsolete/legacy debug tests.
>
> - **CI (GitHub Actions)**:
> - Use `find tests/ci -name 'test_*.py' -type f` for recursive test
discovery in `find_tests` job, replacing `ls`-based globbing.
> - Update missing-file diagnostics to use `find` for listing current
tests.
> - **Tests**:
> - Remove legacy/debug tests:
`tests/ci/test_browser_session_element_cache.py`,
`tests/ci/test_browser_watchdog_crash.py`,
`tests/ci/test_browser_watchdog_screenshots.py`,
`tests/ci/test_llm_custom_structured_ouput.py`, and
`tests/ci/test_sync_client_legacy.py.disabled`.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
4db51f9e24. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
- Simplified test implementations by replacing ActionModel usage with direct calls to Tools methods (e.g., navigate, click, upload_file).
- Enhanced readability and maintainability of test code by removing unnecessary model definitions.
- Utilized new helper methods for element lookup by ID, improving efficiency in finding elements during tests.
This change aligns with recent updates to the Tools API, making tests cleaner and more intuitive.
Auto-generated PR for branch: update-tests
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Refactors CI tests to call Tools actions directly and use DOM index
helpers, removing ActionModel-based invocations and manual selector
scanning.
>
> - **Tests (CI)**:
> - **Tools API usage**:
> - Replace `tools.act(ActionModel(...))` with direct calls:
`tools.navigate`, `tools.click`, `tools.scroll`,
`tools.dropdown_options`, `tools.select_dropdown`, `tools.search`,
`tools.go_back`, `tools.wait`, `tools.done`, `tools.upload_file`.
> - Remove imports/usages of `browser_use.tools.views` action classes
and `ActionModel` where not needed.
> - **DOM selection helpers**:
> - Replace manual `selector_map` scans with
`browser_session.get_index_by_id` and
`browser_session.get_index_by_class`.
> - **Click/Dropdown/File Upload tests**
(`tests/ci/test_browser_event_ClickElementEvent.py`,
`...GetDropdownOptionsEvent*.py`):
> - Update navigation/click/selection flows to new API; validate results
via CDP where applicable.
> - For file inputs, assert error on click; for `<select>`, return
dropdown options; use `tools.upload_file` with `file_system` and
`available_file_paths`.
> - **Navigation tests**
(`tests/ci/test_browser_event_NavigateToUrlEvent.py`):
> - Use direct navigate calls for normal, new-tab, data/javascript URLs,
redirects, hashes, query params; keep direct event tests.
> - **Scroll tests** (`tests/ci/test_browser_event_ScrollEvent.py`):
> - Use `tools.scroll` and assert success/error; retain direct
`ScrollEvent` cases.
> - **Tools integration** (`tests/ci/test_tools.py`):
> - Register and call a custom action directly; update
search/done/wait/go_back/dropdown tests to new API; remove ActionModel
scaffolding.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
e04e3fcdc8. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!-- This is an auto-generated description by cubic. -->
## Summary by cubic
Exports now include JavaScript code blocks captured during sessions, so
notebooks and scripts preserve client-side logic. The API now takes a
CodeAgent to access the namespace.
- **New Features**
- Jupyter export: adds JS code blocks from agent.namespace as variables
at the top of the notebook.
- Python script export: includes the same JS blocks as triple-quoted
strings with a short JS detection.
- Updated setup cell and imports (adds json).
- Reads cells from agent.session.cells.
- **Migration**
- Use export_to_ipynb(agent, path) instead of export_to_ipynb(session,
path).
- Use session_to_python_script(agent) instead of
session_to_python_script(session).
- Ensure JS blocks are registered in agent.namespace['_code_block_vars']
and mapped to their code strings.
<!-- End of auto-generated description by cubic. -->
## Summary
- Added `get_index_by_id()` method to find element indices by id
attribute
- Added `get_index_by_class()` method to find element indices by class
name
## Motivation
Simplifies common DOM element lookup patterns when working with selector
maps. Instead of manually iterating through the selector map to find
elements, these helper methods provide a clean API:
```python
# Find element by id
index = await browser_session.get_index_by_id('submit-button')
# Find element by class name
index = await browser_session.get_index_by_class('dropdown-menu')
```
Both methods return the element index or `None` if not found, and
automatically call `get_selector_map()` internally.
## Test plan
- Verified type checking passes with pyright
- Methods follow existing code patterns and style
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Adds async helpers on `BrowserSession` to retrieve element indices
from the selector map by `id` or by contained `class` name.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
4c4bc40476. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## Summary
Adds a simpler, more ergonomic API for calling actions directly on Tools
instances, making tests much cleaner and easier to write.
## Changes
**Before (verbose):**
```python
class NavigateActionModel(ActionModel):
navigate: GoToUrlAction | None = None
action = NavigateActionModel(navigate=GoToUrlAction(url=f'{base_url}/react-dropdown', new_tab=False))
result = await tools.act(action, browser_session)
```
**After (clean):**
```python
result = await tools.navigate(url=f'{base_url}/react-dropdown', new_tab=False, browser_session=browser_session)
```
## Implementation Details
- Added `__getattr__` method to `Tools` class that dynamically creates
action wrappers
- Delegates to existing `registry.execute_action()` to avoid code
duplication
- Works with all Tools subclasses (Tools, CodeAgentTools, custom
subclasses)
- Works with custom registered actions via `@tools.action()`
- Maintains full backward compatibility with existing `act()` API
## Benefits
- ✅ Significantly reduces boilerplate in tests
- ✅ More intuitive and Pythonic API
- ✅ All existing code continues to work unchanged
- ✅ No code duplication (delegates to registry)
- ✅ Works everywhere: Tools, CodeAgentTools, custom subclasses
- ✅ Supports all actions: navigate, click, input, scroll, etc.
## Testing
All existing tests pass. The implementation has been verified to work
with:
- Regular `Tools()` instances
- `CodeAgentTools()` instances
- Custom Tools subclasses
- Custom registered actions
- Actions with excluded actions
- Actions with default parameters
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Adds a dynamic __getattr__ wrapper on Tools to call registered actions
directly (e.g., tools.navigate(...)) while delegating to act() for
handling.
>
> - **Tools API** (`browser_use/tools/service.py`):
> - **Direct Action Calls**: Implement `__getattr__` to expose
registered actions as methods (e.g., `tools.navigate(...)`).
> - Constructs action params instance and dynamic `ActionModel` via
`pydantic.create_model` with `Union[...]`.
> - Separates action params from special deps (`browser_session`,
`page_extraction_llm`, `file_system`, `available_file_paths`,
`sensitive_data`).
> - Delegates execution to `act(...)` for error handling, result
normalization, and observability.
> - Raises `AttributeError` for unknown attributes; remains compatible
with existing `act()` and custom actions.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
e1e8003c24. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
The action_wrapper now delegates to act() instead of calling registry.execute_action() directly.
This ensures:
- Consistent error handling (returns ActionResult with error, not raw exceptions)
- Consistent result normalization (always returns ActionResult)
- Full observability (Laminar spans, logging)
- Proper handling of BrowserError and TimeoutError
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added two convenience methods for finding element indices:
- get_index_by_id: Find element by its id attribute
- get_index_by_class: Find element by class name
These methods simplify common DOM element lookup patterns when
working with selector maps.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Enable simpler, more ergonomic action calls in tests and direct usage:
- Old API: tools.act(NavigateActionModel(navigate=GoToUrlAction(...)), browser_session)
- New API: tools.navigate(url=..., browser_session=browser_session)
Implementation:
- Added __getattr__ method to Tools class that dynamically creates action wrappers
- Delegates to existing registry.execute_action() to avoid code duplication
- Works with all Tools subclasses (Tools, CodeAgentTools, custom subclasses)
- Works with custom registered actions
- Maintains full backward compatibility with existing act() API
Benefits:
- Significantly reduces boilerplate in tests
- More intuitive and Pythonic API
- All existing code continues to work unchanged
- No code duplication (delegates to registry)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
## Summary
Fixes dropdown selections not persisting in Vue.js, React, and other
reactive frameworks. The issue was that dropdown selections appeared to
work briefly but would reset before form submission.
Closes#3415
## Root Cause
The dropdown selection handler was only dispatching `change` events, but
Vue's `v-model` directive (and React's controlled components) require
`input` events to register changes in their reactive state systems.
## Solution
Enhanced the event dispatching sequence in `default_action_watchdog.py`
to properly trigger reactive framework updates:
1. **Focus element first** - Prepares the element for interaction
2. **Set value and selected state** - Updates the DOM
3. **Dispatch `input` event** - Critical for Vue's v-model and React
controlled components
4. **Dispatch `change` event** - Standard for select elements
5. **Blur element** - Triggers validation and completes the interaction
The key insight is that the `input` event is what reactive frameworks
listen to for updating their internal state, while `change` is the
traditional browser event.
## Testing
Added comprehensive integration tests in `tests/ci/interaction/`:
### Vue.js Test (`test_dropdown_vue_submit.py`)
- Tests Vue 3 with v-model directive
- Verifies dropdown selections persist through Vue's reactive system
- Validates form submission contains correct values (both client and
server-side)
- Confirms results display correctly on page
### React Test (`test_dropdown_react_submit.py`)
- Tests React 18 with controlled components
- Verifies dropdown selections persist through React state management
- Validates form submission contains correct values (both client and
server-side)
- Confirms results display correctly on page
Both tests use real browser automation (not mocks) and validate the
complete flow from selection to submission.
## Test Results
```
tests/ci/interaction/test_dropdown_vue_submit.py::TestVueDropdownSubmit::test_vue_dropdown_selection_with_submit PASSED
tests/ci/interaction/test_dropdown_react_submit.py::TestReactDropdownSubmit::test_react_dropdown_selection_with_submit PASSED
```
## Files Changed
- `browser_use/browser/watchdogs/default_action_watchdog.py` - Enhanced
dropdown event dispatching
- `tests/ci/interaction/` - New test directory with Vue.js and React
integration tests
## Compatibility
This fix ensures compatibility with:
- ✅ Vue.js (all versions with v-model)
- ✅ React (controlled components)
- ✅ Angular (reactive forms)
- ✅ Svelte (reactive bindings)
- ✅ Native HTML forms (backward compatible)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Ensures dropdown selections persist in Vue/React by focusing selects
and dispatching input/change/blur events, with new integration tests
validating end-to-end submission.
>
> - **Fix**
> - Update dropdown selection logic in
`browser_use/browser/watchdogs/default_action_watchdog.py` to focus the
`select` element and dispatch `input`, `change`, and `blur` events for
native selects, improving compatibility with Vue/React reactivity.
> - **Tests**
> - Add interaction tests in `tests/ci/interaction/`:
> - `test_dropdown_vue_submit.py`: Verifies Vue 3 `v-model` persists
selection and submits correct values.
> - `test_dropdown_react_submit.py`: Verifies React controlled
components persist selection and submit correct values.
> - Add `conftest.py` fixture and package `__init__.py`.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
95716350ef. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Fixes dropdown selections not persisting in Vue.js, React, and other
reactive frameworks. The issue was that only 'change' events were
dispatched, but Vue's v-model requires 'input' events to register changes.
**Root Cause:**
Dropdown selection handler only dispatched 'change' events, missing the
'input' event required by reactive frameworks.
**Solution:**
Enhanced event dispatching sequence in default_action_watchdog.py:
1. Focus element first
2. Set value and selected state
3. Dispatch 'input' event (critical for Vue v-model and React)
4. Dispatch 'change' event (standard for select elements)
5. Blur element for validation
**Tests:**
Added comprehensive integration tests in tests/ci/interaction/:
- test_dropdown_vue_submit.py: Vue.js 3 with v-model
- test_dropdown_react_submit.py: React 18 with controlled components
Both tests verify dropdown selections persist through the reactive
framework's state management and form submission works correctly.
Closes#3415🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Auto-generated PR for: fix evaluate test
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes the CI evaluate test by switching the judge model to Gemini for
more reliable scoring. Adds the ChatGoogle import and updates judge
initialization.
- **Bug Fixes**
- Import ChatGoogle from browser_use.llm.google.chat.
- Use ChatGoogle(model='gemini-flash-lite-latest') for judge_llm instead
of ChatBrowserUse.
<!-- End of auto-generated description by cubic. -->
Auto-generated PR for branch: bug-template
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Adds final outcome guidance logs to Agent runs and streamlines the bug
report template (free-form model input, optional OS/logs).
>
> - **Agent runtime (`browser_use/agent/service.py`)**:
> - Add `_log_final_outcome_messages()` to emit helpful messages after
run completion, including CAPTCHA/Cloudflare guidance and issue link.
> - Invoke outcome logging at end of `run()` before event bus shutdown.
> - **GitHub Issue Template
(`.github/ISSUE_TEMPLATE/2_bug_report.yml`)**:
> - Replace `LLM Model` dropdown with free-form input; make it optional
with placeholder.
> - Make `Operating System & Browser Versions` optional (remove required
validation).
> - Soften `Full DEBUG Log Output` description text.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
fafc274dde. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->