mirror of
https://github.com/browser-use/browser-use.git
synced 2026-10-02 04:04:36 +08:00
Merge branch 'main' into fix_gemini_system_in_user_drops_parts
This commit is contained in:
@@ -19,7 +19,7 @@ The key product of Browser Use Cloud is the completion of user tasks.
|
||||
- Profile Sync is the best way to handle authentication for tasks. This feature allows users to upload their local browser cookies (where the user is already logged into the services they need authentication for) to a Browser Profile that can be used for tasks on the cloud. To initiate a Profile Sync, a user must run `export BROWSER_USE_API_KEY=<your_key> && curl -fsSL https://browser-use.com/profile.sh | sh` and follow the steps in the interactive terminal.
|
||||
|
||||
## Quickstart
|
||||
To get started, direct the user to first must create an account, purchase credits (or simply claim the five free tasks given on account creation), and generate an API key on the Browser Use online platform: https://cloud.browser-use.com/. These are the only steps that can only be done on the platform.
|
||||
To get started, direct the user to first create an account, claim the $15 one-time signup credit if eligible (or purchase credits), and generate an API key on the Browser Use online platform: https://cloud.browser-use.com/. These are the only steps that can only be done on the platform.
|
||||
|
||||
Avoid giving the user all of the following steps at once as it may seem overwheling. Instead present one step at a time and only continue when asked. Do as much for the user as you are able to.
|
||||
|
||||
|
||||
@@ -25,6 +25,14 @@ def _get_enable_default_extensions_default() -> bool:
|
||||
return True
|
||||
|
||||
|
||||
def _get_headless_default() -> bool | None:
|
||||
"""Get the default value for headless from BROWSER_USE_HEADLESS env var, or None to fall back to display detection."""
|
||||
env_val = os.getenv('BROWSER_USE_HEADLESS')
|
||||
if env_val is not None:
|
||||
return env_val.lower() not in ('0', 'false', 'no', 'off', '')
|
||||
return None
|
||||
|
||||
|
||||
CHROME_DEBUG_PORT = 9242 # use a non-default port to avoid conflicts with other tools / devs using 9222
|
||||
DOMAIN_OPTIMIZATION_THRESHOLD = 100 # Convert domain lists to sets for O(1) lookup when >= this size
|
||||
CHROME_PROFILE_TRANSIENT_FILE_PATTERNS = (
|
||||
@@ -419,7 +427,10 @@ class BrowserLaunchArgs(BaseModel):
|
||||
validation_alias=AliasChoices('browser_binary_path', 'chrome_binary_path'),
|
||||
description='Path to the chromium-based browser executable to use.',
|
||||
)
|
||||
headless: bool | None = Field(default=None, description='Whether to run the browser in headless or windowed mode.')
|
||||
headless: bool | None = Field(
|
||||
default_factory=_get_headless_default,
|
||||
description='Whether to run the browser in headless or windowed mode. Can be set via BROWSER_USE_HEADLESS environment variable.',
|
||||
)
|
||||
args: list[CliArgStr] = Field(
|
||||
default_factory=list, description='List of *extra* CLI args to pass to the browser when launching.'
|
||||
)
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ dependencies = [
|
||||
"httpx==0.28.1",
|
||||
"posthog==7.7.0",
|
||||
"psutil==7.2.2",
|
||||
"pydantic==2.12.5",
|
||||
"pydantic>=2.12.5,<2.14",
|
||||
"pyobjc==12.1; platform_system == 'darwin'",
|
||||
"python-dotenv==1.2.2",
|
||||
"requests==2.33.0",
|
||||
|
||||
+55
-143
@@ -1,179 +1,91 @@
|
||||
---
|
||||
name: remote-browser
|
||||
description: Controls a local browser from a sandboxed remote machine. Use when the agent is running in a sandbox (no GUI) and needs to navigate websites, interact with web pages, fill forms, take screenshots, or expose local dev servers via tunnels.
|
||||
description: Controls an isolated Browser Use Cloud browser from a sandboxed machine with the current Browser Use CLI.
|
||||
allowed-tools: Bash(browser-use:*)
|
||||
---
|
||||
|
||||
# Browser Automation for Sandboxed Agents
|
||||
# Remote Browser
|
||||
|
||||
This skill is for agents running on **sandboxed remote machines** (cloud VMs, CI, coding agents) that need to control a headless browser.
|
||||
Use this skill when an agent runs on a machine without a usable local Chrome and needs an isolated browser. The current Browser Use CLI runs Python from stdin. Do not use the removed `open`, `state`, `click`, `input`, `tab`, `cloud connect`, or `--connect` commands.
|
||||
|
||||
## Prerequisites
|
||||
## Check the CLI
|
||||
|
||||
```bash
|
||||
browser-use doctor # Verify installation
|
||||
browser-use --doctor
|
||||
browser-use skill show
|
||||
```
|
||||
|
||||
For setup details, see https://github.com/browser-use/browser-use/blob/main/browser_use/skill_cli/README.md
|
||||
If setup fails, follow the current [Browser Use skill](../browser-use/SKILL.md).
|
||||
|
||||
## Core Workflow
|
||||
## Start an isolated browser
|
||||
|
||||
1. **Navigate**: `browser-use open <url>` — starts headless browser if needed
|
||||
2. **Inspect**: `browser-use state` — returns clickable elements with indices
|
||||
3. **Interact**: use indices from state (`browser-use click 5`, `browser-use input 3 "text"`)
|
||||
4. **Verify**: `browser-use state` or `browser-use screenshot` to confirm
|
||||
5. **Repeat**: browser stays open between commands
|
||||
6. **Cleanup**: `browser-use close` when done
|
||||
|
||||
## Browser Modes
|
||||
Authenticate once:
|
||||
|
||||
```bash
|
||||
browser-use open <url> # Default: headless Chromium
|
||||
browser-use cloud connect # Provision cloud browser and connect
|
||||
browser-use --connect open <url> # Auto-discover running Chrome via CDP
|
||||
browser-use --cdp-url ws://localhost:9222/... open <url> # Connect via CDP URL
|
||||
browser-use auth login
|
||||
```
|
||||
|
||||
## Commands
|
||||
Pick a short unique name. `r7k2` below is only an example.
|
||||
|
||||
```bash
|
||||
# Navigation
|
||||
browser-use open <url> # Navigate to URL
|
||||
browser-use back # Go back in history
|
||||
browser-use scroll down # Scroll down (--amount N for pixels)
|
||||
browser-use scroll up # Scroll up
|
||||
browser-use tab list # List all tabs with lock status
|
||||
browser-use tab new [url] # Open a new tab (blank or with URL)
|
||||
browser-use tab switch <index> # Switch to tab by index
|
||||
browser-use tab close <index> [index...] # Close one or more tabs
|
||||
|
||||
# Page State — always run state first to get element indices
|
||||
browser-use state # URL, title, clickable elements with indices
|
||||
browser-use screenshot [path.png] # Screenshot (base64 if no path, --full for full page)
|
||||
|
||||
# Interactions — use indices from state
|
||||
browser-use click <index> # Click element by index
|
||||
browser-use click <x> <y> # Click at pixel coordinates
|
||||
browser-use type "text" # Type into focused element
|
||||
browser-use input <index> "text" # Click element, then type
|
||||
browser-use keys "Enter" # Send keyboard keys (also "Control+a", etc.)
|
||||
browser-use select <index> "option" # Select dropdown option
|
||||
browser-use upload <index> <path> # Upload file to file input
|
||||
browser-use hover <index> # Hover over element
|
||||
browser-use dblclick <index> # Double-click element
|
||||
browser-use rightclick <index> # Right-click element
|
||||
|
||||
# Data Extraction
|
||||
browser-use eval "js code" # Execute JavaScript, return result
|
||||
browser-use get title # Page title
|
||||
browser-use get html [--selector "h1"] # Page HTML (or scoped to selector)
|
||||
browser-use get text <index> # Element text content
|
||||
browser-use get value <index> # Input/textarea value
|
||||
browser-use get attributes <index> # Element attributes
|
||||
browser-use get bbox <index> # Bounding box (x, y, width, height)
|
||||
|
||||
# Wait
|
||||
browser-use wait selector "css" # Wait for element (--state visible|hidden|attached|detached, --timeout ms)
|
||||
browser-use wait text "text" # Wait for text to appear
|
||||
|
||||
# Cookies
|
||||
browser-use cookies get [--url <url>] # Get cookies (optionally filtered)
|
||||
browser-use cookies set <name> <value> # Set cookie (--domain, --secure, --http-only, --same-site, --expires)
|
||||
browser-use cookies clear [--url <url>] # Clear cookies
|
||||
browser-use cookies export <file> # Export to JSON
|
||||
browser-use cookies import <file> # Import from JSON
|
||||
|
||||
# Python — persistent session with browser access
|
||||
browser-use python "code" # Execute Python (variables persist across calls)
|
||||
browser-use python --file script.py # Run file
|
||||
browser-use python --vars # Show defined variables
|
||||
browser-use python --reset # Clear namespace
|
||||
|
||||
# Session
|
||||
browser-use close # Close browser and stop daemon
|
||||
browser-use sessions # List active sessions
|
||||
browser-use close --all # Close all sessions
|
||||
browser-use <<'PY'
|
||||
start_remote_daemon("r7k2")
|
||||
PY
|
||||
```
|
||||
|
||||
The Python `browser` object provides: `browser.url`, `browser.title`, `browser.html`, `browser.goto(url)`, `browser.back()`, `browser.click(index)`, `browser.type(text)`, `browser.input(index, text)`, `browser.keys(keys)`, `browser.upload(index, path)`, `browser.screenshot(path)`, `browser.scroll(direction, amount)`, `browser.wait(seconds)`.
|
||||
|
||||
## Tunnels
|
||||
|
||||
Expose local dev servers to the browser via Cloudflare tunnels.
|
||||
Use the same name for every command in this browser:
|
||||
|
||||
```bash
|
||||
browser-use tunnel <port> # Start tunnel (idempotent)
|
||||
browser-use tunnel list # Show active tunnels
|
||||
browser-use tunnel stop <port> # Stop tunnel
|
||||
browser-use tunnel stop --all # Stop all tunnels
|
||||
BU_NAME=r7k2 browser-use <<'PY'
|
||||
new_tab("https://example.com")
|
||||
wait_for_load()
|
||||
print(page_info())
|
||||
PY
|
||||
```
|
||||
|
||||
## Command Chaining
|
||||
Each remote daemon is a separate Browser Use Cloud browser. Use a different name for each parallel task. Remote browsers can bill until they stop or time out.
|
||||
|
||||
Commands can be chained with `&&`. The browser persists via the daemon, so chaining is safe and efficient.
|
||||
## Inspect and interact
|
||||
|
||||
Helpers are pre-imported. Keep multi-step work in one heredoc when practical.
|
||||
|
||||
```bash
|
||||
browser-use open https://example.com && browser-use state
|
||||
browser-use input 5 "user@example.com" && browser-use input 6 "password" && browser-use click 7
|
||||
BU_NAME=r7k2 browser-use <<'PY'
|
||||
print(page_info())
|
||||
print(js("document.title"))
|
||||
|
||||
fill_input('input[name="q"]', "browser automation")
|
||||
press_key("Enter")
|
||||
wait_for_load()
|
||||
|
||||
print(page_info())
|
||||
PY
|
||||
```
|
||||
|
||||
Chain when you don't need intermediate output. Run separately when you need to parse `state` to discover indices first.
|
||||
Useful helpers:
|
||||
|
||||
## Common Workflows
|
||||
- Navigate: `new_tab(url)`, `goto_url(url)`, `wait_for_load()`
|
||||
- Inspect: `page_info()`, `js(code)`, `cdp(method, ...)`
|
||||
- Interact: `click_at_xy(x, y)`, `type_text(text)`, `fill_input(selector, text)`, `press_key(key)`, `scroll(x, y)`
|
||||
- Tabs: `list_tabs()`, `switch_tab(target)`, `close_tab(target)`
|
||||
- Files and proof: `capture_screenshot()`, `wait_for_element(selector)`
|
||||
|
||||
### Exposing Local Dev Servers
|
||||
Prefer the accessibility tree for element discovery:
|
||||
|
||||
```python
|
||||
nodes = cdp("Accessibility.getFullAXTree")["nodes"]
|
||||
```
|
||||
|
||||
Use a targeted `js(...)` query when the accessibility tree lacks the element. Verify each action with `page_info()`, a focused DOM check, or a screenshot.
|
||||
|
||||
## Stop the browser
|
||||
|
||||
When the work is done, stop the exact named browser:
|
||||
|
||||
```bash
|
||||
python -m http.server 3000 & # Start dev server
|
||||
browser-use tunnel 3000 # → https://abc.trycloudflare.com
|
||||
browser-use open https://abc.trycloudflare.com # Browse the tunnel
|
||||
browser-use <<'PY'
|
||||
stop_remote_daemon("r7k2")
|
||||
PY
|
||||
```
|
||||
|
||||
Tunnels are independent of browser sessions and persist across `browser-use close`.
|
||||
|
||||
## Multi-Agent (--connect mode)
|
||||
|
||||
Multiple agents can share one browser via `--connect`. Each agent gets its own tab — other agents can't interfere.
|
||||
|
||||
**Setup**: Register once, then pass the index with every `--connect` command:
|
||||
|
||||
```bash
|
||||
INDEX=$(browser-use register) # → prints "1"
|
||||
browser-use --connect $INDEX open <url> # Navigate in agent's own tab
|
||||
browser-use --connect $INDEX state # Get state from agent's tab
|
||||
browser-use --connect $INDEX click <element> # Click in agent's tab
|
||||
```
|
||||
|
||||
- **Tab locking**: When an agent mutates a tab (click, type, navigate), that tab is locked to it. Other agents get an error if they try to mutate the same tab.
|
||||
- **Read-only access**: `state`, `screenshot`, `get`, and `wait` commands work on any tab regardless of locks.
|
||||
- **Agent sessions expire** after 5 minutes of inactivity. Run `browser-use register` again to get a new index.
|
||||
|
||||
## Global Options
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--headed` | Show browser window |
|
||||
| `--connect` | Auto-discover running Chrome via CDP |
|
||||
| `--cdp-url <url>` | Connect via CDP URL (`http://` or `ws://`) |
|
||||
| `--session NAME` | Target a named session (default: "default") |
|
||||
| `--json` | Output as JSON |
|
||||
|
||||
## Tips
|
||||
|
||||
1. **Always run `state` first** to see available elements and their indices
|
||||
2. **Sessions persist** — browser stays open between commands until you close it
|
||||
3. **Tunnels are independent** — they persist across `browser-use close`
|
||||
4. **`tunnel` is idempotent** — calling again for the same port returns the existing URL
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Browser won't start?** `browser-use close` then retry. Run `browser-use doctor` to check.
|
||||
- **Element not found?** `browser-use scroll down` then `browser-use state`
|
||||
- **Tunnel not working?** `which cloudflared` to check, `browser-use tunnel list` to see active tunnels
|
||||
|
||||
## Cleanup
|
||||
|
||||
```bash
|
||||
browser-use close # Close browser session
|
||||
browser-use tunnel stop --all # Stop tunnels (if any)
|
||||
```
|
||||
Do not leave an unused remote browser running.
|
||||
|
||||
@@ -57,6 +57,40 @@ def test_docs_install_browser_use_skill_from_package_alias():
|
||||
assert 'raw.githubusercontent.com/browser-use/browser-harness/main/SKILL.md' not in readme
|
||||
|
||||
|
||||
def test_remote_browser_skill_uses_current_cli():
|
||||
remote_skill = (ROOT / 'skills' / 'remote-browser' / 'SKILL.md').read_text(encoding='utf-8')
|
||||
|
||||
for removed_command in (
|
||||
'browser-use open',
|
||||
'browser-use state',
|
||||
'browser-use click',
|
||||
'browser-use input',
|
||||
'browser-use tab',
|
||||
'browser-use screenshot',
|
||||
'browser-use eval',
|
||||
'browser-use cookies',
|
||||
'browser-use close',
|
||||
'browser-use sessions',
|
||||
'browser-use tunnel',
|
||||
'browser-use wait',
|
||||
'browser-use register',
|
||||
'browser-use cloud connect',
|
||||
'browser-use --connect',
|
||||
'browser_use/skill_cli/README.md',
|
||||
):
|
||||
assert removed_command not in remote_skill
|
||||
|
||||
for current_command in (
|
||||
"browser-use <<'PY'",
|
||||
'start_remote_daemon("r7k2")',
|
||||
'BU_NAME=r7k2 browser-use',
|
||||
'new_tab("https://example.com")',
|
||||
'print(page_info())',
|
||||
'stop_remote_daemon("r7k2")',
|
||||
):
|
||||
assert current_command in remote_skill
|
||||
|
||||
|
||||
def test_browser_use_cli_installs_browser_harness_package_skill(tmp_path):
|
||||
bin_dir = _fake_browser_harness_tools(tmp_path, '---\nname: browser-harness\n---\n\n# Browser Harness\n')
|
||||
|
||||
|
||||
+101
-108
@@ -1,123 +1,116 @@
|
||||
"""Tests for extension configuration environment variables."""
|
||||
|
||||
import os
|
||||
"""Tests for browser configuration environment variables."""
|
||||
|
||||
import pytest
|
||||
|
||||
from browser_use.browser import BrowserSession
|
||||
from browser_use.browser.profile import (
|
||||
BrowserProfile,
|
||||
_get_enable_default_extensions_default,
|
||||
_get_headless_default,
|
||||
)
|
||||
|
||||
class TestDisableExtensionsEnvVar:
|
||||
"""Test BROWSER_USE_DISABLE_EXTENSIONS environment variable."""
|
||||
TRUTHY_STRINGS = ['true', 'True', 'TRUE', '1', 'yes', 'on']
|
||||
FALSY_STRINGS = ['false', 'False', 'FALSE', '0', 'no', 'off', '']
|
||||
|
||||
def test_default_value_is_true(self):
|
||||
"""Without env var set, enable_default_extensions should default to True."""
|
||||
# Clear the env var if it exists
|
||||
original = os.environ.pop('BROWSER_USE_DISABLE_EXTENSIONS', None)
|
||||
try:
|
||||
# Import fresh to get the default
|
||||
from browser_use.browser.profile import _get_enable_default_extensions_default
|
||||
|
||||
assert _get_enable_default_extensions_default() is True
|
||||
finally:
|
||||
if original is not None:
|
||||
os.environ['BROWSER_USE_DISABLE_EXTENSIONS'] = original
|
||||
class TestConfigEnvVars:
|
||||
"""Tests for browser profile env var configuration."""
|
||||
|
||||
def test_default_values_without_env(self, monkeypatch: pytest.MonkeyPatch):
|
||||
"""Verify default values when environment variables are unset."""
|
||||
monkeypatch.delenv('BROWSER_USE_DISABLE_EXTENSIONS', raising=False)
|
||||
monkeypatch.delenv('BROWSER_USE_HEADLESS', raising=False)
|
||||
|
||||
assert _get_enable_default_extensions_default() is True
|
||||
assert _get_headless_default() is None
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'env_value,expected_enabled',
|
||||
'env_var,getter,expected',
|
||||
[
|
||||
# Truthy values for DISABLE = extensions disabled (False)
|
||||
('true', False),
|
||||
('True', False),
|
||||
('TRUE', False),
|
||||
('1', False),
|
||||
('yes', False),
|
||||
('on', False),
|
||||
# Falsy values for DISABLE = extensions enabled (True)
|
||||
('false', True),
|
||||
('False', True),
|
||||
('FALSE', True),
|
||||
('0', True),
|
||||
('no', True),
|
||||
('off', True),
|
||||
('', True),
|
||||
('BROWSER_USE_DISABLE_EXTENSIONS', _get_enable_default_extensions_default, False),
|
||||
('BROWSER_USE_HEADLESS', _get_headless_default, True),
|
||||
],
|
||||
)
|
||||
def test_env_var_values(self, env_value: str, expected_enabled: bool):
|
||||
"""Test various env var values are parsed correctly."""
|
||||
original = os.environ.get('BROWSER_USE_DISABLE_EXTENSIONS')
|
||||
try:
|
||||
os.environ['BROWSER_USE_DISABLE_EXTENSIONS'] = env_value
|
||||
from browser_use.browser.profile import _get_enable_default_extensions_default
|
||||
def test_env_var_truthy_values(
|
||||
self,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
env_var: str,
|
||||
getter,
|
||||
expected: bool,
|
||||
):
|
||||
"""Test truthy env var values are parsed correctly."""
|
||||
for val in TRUTHY_STRINGS:
|
||||
monkeypatch.setenv(env_var, val)
|
||||
assert getter() is expected, f'Failed for {env_var}={val}'
|
||||
|
||||
result = _get_enable_default_extensions_default()
|
||||
assert result is expected_enabled, (
|
||||
f"Expected enable_default_extensions={expected_enabled} for DISABLE_EXTENSIONS='{env_value}', got {result}"
|
||||
)
|
||||
finally:
|
||||
if original is not None:
|
||||
os.environ['BROWSER_USE_DISABLE_EXTENSIONS'] = original
|
||||
else:
|
||||
os.environ.pop('BROWSER_USE_DISABLE_EXTENSIONS', None)
|
||||
@pytest.mark.parametrize(
|
||||
'env_var,getter,expected',
|
||||
[
|
||||
('BROWSER_USE_DISABLE_EXTENSIONS', _get_enable_default_extensions_default, True),
|
||||
('BROWSER_USE_HEADLESS', _get_headless_default, False),
|
||||
],
|
||||
)
|
||||
def test_env_var_falsy_values(
|
||||
self,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
env_var: str,
|
||||
getter,
|
||||
expected: bool,
|
||||
):
|
||||
"""Test falsy env var values are parsed correctly."""
|
||||
for val in FALSY_STRINGS:
|
||||
monkeypatch.setenv(env_var, val)
|
||||
assert getter() is expected, f'Failed for {env_var}={val}'
|
||||
|
||||
def test_browser_profile_uses_env_var(self):
|
||||
"""Test that BrowserProfile picks up the env var."""
|
||||
original = os.environ.get('BROWSER_USE_DISABLE_EXTENSIONS')
|
||||
try:
|
||||
# Test with env var set to true (disable extensions)
|
||||
os.environ['BROWSER_USE_DISABLE_EXTENSIONS'] = 'true'
|
||||
@pytest.mark.parametrize(
|
||||
'env_var,attr_name,truthy_val,falsy_val',
|
||||
[
|
||||
('BROWSER_USE_DISABLE_EXTENSIONS', 'enable_default_extensions', False, True),
|
||||
('BROWSER_USE_HEADLESS', 'headless', True, False),
|
||||
],
|
||||
)
|
||||
def test_browser_profile_and_session_env_var(
|
||||
self,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
env_var: str,
|
||||
attr_name: str,
|
||||
truthy_val: bool,
|
||||
falsy_val: bool,
|
||||
):
|
||||
"""Test that BrowserProfile and BrowserSession pick up env vars."""
|
||||
# Test truthy env value
|
||||
monkeypatch.setenv(env_var, 'true')
|
||||
profile = BrowserProfile()
|
||||
assert getattr(profile, attr_name) is truthy_val
|
||||
session = BrowserSession()
|
||||
assert getattr(session.browser_profile, attr_name) is truthy_val
|
||||
|
||||
from browser_use.browser.profile import BrowserProfile
|
||||
# Test falsy env value
|
||||
monkeypatch.setenv(env_var, 'false')
|
||||
profile_falsy = BrowserProfile()
|
||||
assert getattr(profile_falsy, attr_name) is falsy_val
|
||||
session_falsy = BrowserSession()
|
||||
assert getattr(session_falsy.browser_profile, attr_name) is falsy_val
|
||||
|
||||
profile = BrowserProfile(headless=True)
|
||||
assert profile.enable_default_extensions is False, (
|
||||
'BrowserProfile should disable extensions when BROWSER_USE_DISABLE_EXTENSIONS=true'
|
||||
)
|
||||
|
||||
# Test with env var set to false (enable extensions)
|
||||
os.environ['BROWSER_USE_DISABLE_EXTENSIONS'] = 'false'
|
||||
profile2 = BrowserProfile(headless=True)
|
||||
assert profile2.enable_default_extensions is True, (
|
||||
'BrowserProfile should enable extensions when BROWSER_USE_DISABLE_EXTENSIONS=false'
|
||||
)
|
||||
|
||||
finally:
|
||||
if original is not None:
|
||||
os.environ['BROWSER_USE_DISABLE_EXTENSIONS'] = original
|
||||
else:
|
||||
os.environ.pop('BROWSER_USE_DISABLE_EXTENSIONS', None)
|
||||
|
||||
def test_explicit_param_overrides_env_var(self):
|
||||
"""Test that explicit enable_default_extensions parameter overrides env var."""
|
||||
original = os.environ.get('BROWSER_USE_DISABLE_EXTENSIONS')
|
||||
try:
|
||||
os.environ['BROWSER_USE_DISABLE_EXTENSIONS'] = 'true'
|
||||
|
||||
from browser_use.browser.profile import BrowserProfile
|
||||
|
||||
# Explicitly set to True should override env var
|
||||
profile = BrowserProfile(headless=True, enable_default_extensions=True)
|
||||
assert profile.enable_default_extensions is True, 'Explicit param should override env var'
|
||||
|
||||
finally:
|
||||
if original is not None:
|
||||
os.environ['BROWSER_USE_DISABLE_EXTENSIONS'] = original
|
||||
else:
|
||||
os.environ.pop('BROWSER_USE_DISABLE_EXTENSIONS', None)
|
||||
|
||||
def test_browser_session_uses_env_var(self):
|
||||
"""Test that BrowserSession picks up the env var via BrowserProfile."""
|
||||
original = os.environ.get('BROWSER_USE_DISABLE_EXTENSIONS')
|
||||
try:
|
||||
os.environ['BROWSER_USE_DISABLE_EXTENSIONS'] = '1'
|
||||
|
||||
from browser_use.browser import BrowserSession
|
||||
|
||||
session = BrowserSession(headless=True)
|
||||
assert session.browser_profile.enable_default_extensions is False, (
|
||||
'BrowserSession should disable extensions when BROWSER_USE_DISABLE_EXTENSIONS=1'
|
||||
)
|
||||
|
||||
finally:
|
||||
if original is not None:
|
||||
os.environ['BROWSER_USE_DISABLE_EXTENSIONS'] = original
|
||||
else:
|
||||
os.environ.pop('BROWSER_USE_DISABLE_EXTENSIONS', None)
|
||||
@pytest.mark.parametrize(
|
||||
'env_var,attr_name,env_val,explicit_arg,expected',
|
||||
[
|
||||
('BROWSER_USE_DISABLE_EXTENSIONS', 'enable_default_extensions', 'true', {'enable_default_extensions': True}, True),
|
||||
('BROWSER_USE_DISABLE_EXTENSIONS', 'enable_default_extensions', 'false', {'enable_default_extensions': False}, False),
|
||||
('BROWSER_USE_HEADLESS', 'headless', 'true', {'headless': False}, False),
|
||||
('BROWSER_USE_HEADLESS', 'headless', 'false', {'headless': True}, True),
|
||||
],
|
||||
)
|
||||
def test_explicit_parameter_overrides_env_var(
|
||||
self,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
env_var: str,
|
||||
attr_name: str,
|
||||
env_val: str,
|
||||
explicit_arg: dict,
|
||||
expected: bool,
|
||||
):
|
||||
"""Test that explicit constructor parameters override env vars."""
|
||||
monkeypatch.setenv(env_var, env_val)
|
||||
profile = BrowserProfile(**explicit_arg)
|
||||
assert getattr(profile, attr_name) is expected
|
||||
|
||||
Reference in New Issue
Block a user