mirror of
https://github.com/browser-use/browser-use
synced 2026-05-06 17:52:15 +02:00
fix tests
This commit is contained in:
@@ -50,6 +50,7 @@ dev = [
|
||||
"langchain-aws>=0.2.11",
|
||||
"langchain-fireworks>=0.2.6",
|
||||
"langchain-google-genai==2.0.8",
|
||||
"pytest>=8.3.5",
|
||||
]
|
||||
|
||||
[tool.ruff]
|
||||
|
||||
@@ -1,243 +1,240 @@
|
||||
import pytest
|
||||
from unittest.mock import MagicMock
|
||||
from playwright.async_api import Page
|
||||
|
||||
from browser_use.controller.registry.views import ActionRegistry, RegisteredAction
|
||||
import pytest
|
||||
from playwright.async_api import Page
|
||||
from pydantic import BaseModel
|
||||
|
||||
from browser_use.controller.registry.service import Registry
|
||||
from browser_use.controller.registry.views import ActionRegistry, RegisteredAction
|
||||
|
||||
|
||||
class EmptyParamModel(BaseModel):
|
||||
pass
|
||||
|
||||
|
||||
class TestActionFilters:
|
||||
def test_get_prompt_description_no_filters(self):
|
||||
"""Test that system prompt only includes actions with no filters"""
|
||||
registry = ActionRegistry()
|
||||
|
||||
# Add actions with and without filters
|
||||
no_filter_action = RegisteredAction(
|
||||
name="no_filter_action",
|
||||
description="Action with no filters",
|
||||
function=lambda: None,
|
||||
param_model=MagicMock(),
|
||||
domains=None,
|
||||
page_filter=None
|
||||
)
|
||||
|
||||
page_filter_action = RegisteredAction(
|
||||
name="page_filter_action",
|
||||
description="Action with page filter",
|
||||
function=lambda: None,
|
||||
param_model=MagicMock(),
|
||||
domains=None,
|
||||
page_filter=lambda page: True
|
||||
)
|
||||
|
||||
domain_filter_action = RegisteredAction(
|
||||
name="domain_filter_action",
|
||||
description="Action with domain filter",
|
||||
function=lambda: None,
|
||||
param_model=MagicMock(),
|
||||
domains=["example.com"],
|
||||
page_filter=None
|
||||
)
|
||||
|
||||
registry.actions = {
|
||||
"no_filter_action": no_filter_action,
|
||||
"page_filter_action": page_filter_action,
|
||||
"domain_filter_action": domain_filter_action
|
||||
}
|
||||
|
||||
# System prompt (no page) should only include actions with no filters
|
||||
system_description = registry.get_prompt_description()
|
||||
assert "no_filter_action" in system_description
|
||||
assert "page_filter_action" not in system_description
|
||||
assert "domain_filter_action" not in system_description
|
||||
|
||||
def test_page_filter_matching(self):
|
||||
"""Test that page filters work correctly"""
|
||||
registry = ActionRegistry()
|
||||
|
||||
# Create a mock page
|
||||
mock_page = MagicMock(spec=Page)
|
||||
mock_page.url = "https://example.com/page"
|
||||
|
||||
# Create actions with different page filters
|
||||
matching_action = RegisteredAction(
|
||||
name="matching_action",
|
||||
description="Action with matching page filter",
|
||||
function=lambda: None,
|
||||
param_model=MagicMock(),
|
||||
domains=None,
|
||||
page_filter=lambda page: "example.com" in page.url
|
||||
)
|
||||
|
||||
non_matching_action = RegisteredAction(
|
||||
name="non_matching_action",
|
||||
description="Action with non-matching page filter",
|
||||
function=lambda: None,
|
||||
param_model=MagicMock(),
|
||||
domains=None,
|
||||
page_filter=lambda page: "other.com" in page.url
|
||||
)
|
||||
|
||||
registry.actions = {
|
||||
"matching_action": matching_action,
|
||||
"non_matching_action": non_matching_action
|
||||
}
|
||||
|
||||
# Page-specific description should only include matching actions
|
||||
page_description = registry.get_prompt_description(mock_page)
|
||||
assert "matching_action" in page_description
|
||||
assert "non_matching_action" not in page_description
|
||||
|
||||
def test_domain_filter_matching(self):
|
||||
"""Test that domain filters work correctly with glob patterns"""
|
||||
registry = ActionRegistry()
|
||||
|
||||
# Create actions with different domain patterns
|
||||
actions = {
|
||||
"exact_match": RegisteredAction(
|
||||
name="exact_match",
|
||||
description="Exact domain match",
|
||||
function=lambda: None,
|
||||
param_model=MagicMock(),
|
||||
domains=["example.com"],
|
||||
page_filter=None
|
||||
),
|
||||
"subdomain_match": RegisteredAction(
|
||||
name="subdomain_match",
|
||||
description="Subdomain wildcard match",
|
||||
function=lambda: None,
|
||||
param_model=MagicMock(),
|
||||
domains=["*.example.com"],
|
||||
page_filter=None
|
||||
),
|
||||
"prefix_match": RegisteredAction(
|
||||
name="prefix_match",
|
||||
description="Prefix wildcard match",
|
||||
function=lambda: None,
|
||||
param_model=MagicMock(),
|
||||
domains=["example*"],
|
||||
page_filter=None
|
||||
),
|
||||
"non_matching": RegisteredAction(
|
||||
name="non_matching",
|
||||
description="Non-matching domain",
|
||||
function=lambda: None,
|
||||
param_model=MagicMock(),
|
||||
domains=["other.com"],
|
||||
page_filter=None
|
||||
)
|
||||
}
|
||||
|
||||
registry.actions = actions
|
||||
|
||||
# Test exact domain match
|
||||
mock_page = MagicMock(spec=Page)
|
||||
mock_page.url = "https://example.com/page"
|
||||
|
||||
exact_match_description = registry.get_prompt_description(mock_page)
|
||||
assert "exact_match" in exact_match_description
|
||||
assert "non_matching" not in exact_match_description
|
||||
|
||||
# Test subdomain match
|
||||
mock_page.url = "https://sub.example.com/page"
|
||||
subdomain_match_description = registry.get_prompt_description(mock_page)
|
||||
assert "subdomain_match" in subdomain_match_description
|
||||
assert "exact_match" not in subdomain_match_description
|
||||
|
||||
# Test prefix match
|
||||
mock_page.url = "https://example123.org/page"
|
||||
prefix_match_description = registry.get_prompt_description(mock_page)
|
||||
assert "prefix_match" in prefix_match_description
|
||||
|
||||
def test_domain_and_page_filter_together(self):
|
||||
"""Test that actions can be filtered by both domain and page filter"""
|
||||
registry = ActionRegistry()
|
||||
|
||||
# Create a mock page
|
||||
mock_page = MagicMock(spec=Page)
|
||||
mock_page.url = "https://example.com/admin"
|
||||
|
||||
# Actions with different combinations of filters
|
||||
actions = {
|
||||
"domain_only": RegisteredAction(
|
||||
name="domain_only",
|
||||
description="Domain filter only",
|
||||
function=lambda: None,
|
||||
param_model=MagicMock(),
|
||||
domains=["example.com"],
|
||||
page_filter=None
|
||||
),
|
||||
"page_only": RegisteredAction(
|
||||
name="page_only",
|
||||
description="Page filter only",
|
||||
function=lambda: None,
|
||||
param_model=MagicMock(),
|
||||
domains=None,
|
||||
page_filter=lambda page: "admin" in page.url
|
||||
),
|
||||
"both_matching": RegisteredAction(
|
||||
name="both_matching",
|
||||
description="Both filters matching",
|
||||
function=lambda: None,
|
||||
param_model=MagicMock(),
|
||||
domains=["example.com"],
|
||||
page_filter=lambda page: "admin" in page.url
|
||||
),
|
||||
"both_one_fail": RegisteredAction(
|
||||
name="both_one_fail",
|
||||
description="One filter fails",
|
||||
function=lambda: None,
|
||||
param_model=MagicMock(),
|
||||
domains=["other.com"],
|
||||
page_filter=lambda page: "admin" in page.url
|
||||
),
|
||||
}
|
||||
|
||||
registry.actions = actions
|
||||
|
||||
# Check that all matching filters are included
|
||||
description = registry.get_prompt_description(mock_page)
|
||||
assert "domain_only" in description
|
||||
assert "page_only" in description
|
||||
assert "both_matching" in description
|
||||
assert "both_one_fail" in description # Should match because page_filter matches
|
||||
def test_get_prompt_description_no_filters(self):
|
||||
"""Test that system prompt only includes actions with no filters"""
|
||||
registry = ActionRegistry()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_registry_action_decorator(self):
|
||||
"""Test the action decorator with filters"""
|
||||
registry = Registry()
|
||||
|
||||
# Define actions with different filters
|
||||
@registry.action(
|
||||
description="No filter action",
|
||||
)
|
||||
def no_filter_action():
|
||||
pass
|
||||
|
||||
@registry.action(
|
||||
description="Domain filter action",
|
||||
domains=["example.com"]
|
||||
)
|
||||
def domain_filter_action():
|
||||
pass
|
||||
|
||||
@registry.action(
|
||||
description="Page filter action",
|
||||
page_filter=lambda page: "admin" in page.url
|
||||
)
|
||||
def page_filter_action():
|
||||
pass
|
||||
|
||||
# Check that system prompt only includes the no_filter_action
|
||||
system_description = registry.get_prompt_description()
|
||||
assert "No filter action" in system_description
|
||||
assert "Domain filter action" not in system_description
|
||||
assert "Page filter action" not in system_description
|
||||
|
||||
# Check that page-specific prompt includes the right actions
|
||||
mock_page = MagicMock(spec=Page)
|
||||
mock_page.url = "https://example.com/admin"
|
||||
|
||||
page_description = registry.get_prompt_description(mock_page)
|
||||
assert "Domain filter action" in page_description
|
||||
assert "Page filter action" in page_description
|
||||
# Add actions with and without filters
|
||||
no_filter_action = RegisteredAction(
|
||||
name='no_filter_action',
|
||||
description='Action with no filters',
|
||||
function=lambda: None,
|
||||
param_model=EmptyParamModel,
|
||||
domains=None,
|
||||
page_filter=None,
|
||||
)
|
||||
|
||||
page_filter_action = RegisteredAction(
|
||||
name='page_filter_action',
|
||||
description='Action with page filter',
|
||||
function=lambda: None,
|
||||
param_model=EmptyParamModel,
|
||||
domains=None,
|
||||
page_filter=lambda page: True,
|
||||
)
|
||||
|
||||
domain_filter_action = RegisteredAction(
|
||||
name='domain_filter_action',
|
||||
description='Action with domain filter',
|
||||
function=lambda: None,
|
||||
param_model=EmptyParamModel,
|
||||
domains=['example.com'],
|
||||
page_filter=None,
|
||||
)
|
||||
|
||||
registry.actions = {
|
||||
'no_filter_action': no_filter_action,
|
||||
'page_filter_action': page_filter_action,
|
||||
'domain_filter_action': domain_filter_action,
|
||||
}
|
||||
|
||||
# System prompt (no page) should only include actions with no filters
|
||||
system_description = registry.get_prompt_description()
|
||||
assert 'no_filter_action' in system_description
|
||||
assert 'page_filter_action' not in system_description
|
||||
assert 'domain_filter_action' not in system_description
|
||||
|
||||
def test_page_filter_matching(self):
|
||||
"""Test that page filters work correctly"""
|
||||
registry = ActionRegistry()
|
||||
|
||||
# Create a mock page
|
||||
mock_page = MagicMock(spec=Page)
|
||||
mock_page.url = 'https://example.com/page'
|
||||
|
||||
# Create actions with different page filters
|
||||
matching_action = RegisteredAction(
|
||||
name='matching_action',
|
||||
description='Action with matching page filter',
|
||||
function=lambda: None,
|
||||
param_model=EmptyParamModel,
|
||||
domains=None,
|
||||
page_filter=lambda page: 'example.com' in page.url,
|
||||
)
|
||||
|
||||
non_matching_action = RegisteredAction(
|
||||
name='non_matching_action',
|
||||
description='Action with non-matching page filter',
|
||||
function=lambda: None,
|
||||
param_model=EmptyParamModel,
|
||||
domains=None,
|
||||
page_filter=lambda page: 'other.com' in page.url,
|
||||
)
|
||||
|
||||
registry.actions = {'matching_action': matching_action, 'non_matching_action': non_matching_action}
|
||||
|
||||
# Page-specific description should only include matching actions
|
||||
page_description = registry.get_prompt_description(mock_page)
|
||||
assert 'matching_action' in page_description
|
||||
assert 'non_matching_action' not in page_description
|
||||
|
||||
def test_domain_filter_matching(self):
|
||||
"""Test that domain filters work correctly with glob patterns"""
|
||||
registry = ActionRegistry()
|
||||
|
||||
# Create actions with different domain patterns
|
||||
actions = {
|
||||
'exact_match': RegisteredAction(
|
||||
name='exact_match',
|
||||
description='Exact domain match',
|
||||
function=lambda: None,
|
||||
param_model=EmptyParamModel,
|
||||
domains=['example.com'],
|
||||
page_filter=None,
|
||||
),
|
||||
'subdomain_match': RegisteredAction(
|
||||
name='subdomain_match',
|
||||
description='Subdomain wildcard match',
|
||||
function=lambda: None,
|
||||
param_model=EmptyParamModel,
|
||||
domains=['*.example.com'],
|
||||
page_filter=None,
|
||||
),
|
||||
'prefix_match': RegisteredAction(
|
||||
name='prefix_match',
|
||||
description='Prefix wildcard match',
|
||||
function=lambda: None,
|
||||
param_model=EmptyParamModel,
|
||||
domains=['example*'],
|
||||
page_filter=None,
|
||||
),
|
||||
'non_matching': RegisteredAction(
|
||||
name='non_matching',
|
||||
description='Non-matching domain',
|
||||
function=lambda: None,
|
||||
param_model=EmptyParamModel,
|
||||
domains=['other.com'],
|
||||
page_filter=None,
|
||||
),
|
||||
}
|
||||
|
||||
registry.actions = actions
|
||||
|
||||
# Test exact domain match
|
||||
mock_page = MagicMock(spec=Page)
|
||||
mock_page.url = 'https://example.com/page'
|
||||
|
||||
exact_match_description = registry.get_prompt_description(mock_page)
|
||||
assert 'exact_match' in exact_match_description
|
||||
assert 'non_matching' not in exact_match_description
|
||||
|
||||
# Test subdomain match
|
||||
mock_page.url = 'https://sub.example.com/page'
|
||||
subdomain_match_description = registry.get_prompt_description(mock_page)
|
||||
assert 'subdomain_match' in subdomain_match_description
|
||||
assert 'exact_match' not in subdomain_match_description
|
||||
|
||||
# Test prefix match
|
||||
mock_page.url = 'https://example123.org/page'
|
||||
prefix_match_description = registry.get_prompt_description(mock_page)
|
||||
assert 'prefix_match' in prefix_match_description
|
||||
|
||||
def test_domain_and_page_filter_together(self):
|
||||
"""Test that actions can be filtered by both domain and page filter"""
|
||||
registry = ActionRegistry()
|
||||
|
||||
# Create a mock page
|
||||
mock_page = MagicMock(spec=Page)
|
||||
mock_page.url = 'https://example.com/admin'
|
||||
|
||||
# Actions with different combinations of filters
|
||||
actions = {
|
||||
'domain_only': RegisteredAction(
|
||||
name='domain_only',
|
||||
description='Domain filter only',
|
||||
function=lambda: None,
|
||||
param_model=EmptyParamModel,
|
||||
domains=['example.com'],
|
||||
page_filter=None,
|
||||
),
|
||||
'page_only': RegisteredAction(
|
||||
name='page_only',
|
||||
description='Page filter only',
|
||||
function=lambda: None,
|
||||
param_model=EmptyParamModel,
|
||||
domains=None,
|
||||
page_filter=lambda page: 'admin' in page.url,
|
||||
),
|
||||
'both_matching': RegisteredAction(
|
||||
name='both_matching',
|
||||
description='Both filters matching',
|
||||
function=lambda: None,
|
||||
param_model=EmptyParamModel,
|
||||
domains=['example.com'],
|
||||
page_filter=lambda page: 'admin' in page.url,
|
||||
),
|
||||
'both_one_fail': RegisteredAction(
|
||||
name='both_one_fail',
|
||||
description='One filter fails',
|
||||
function=lambda: None,
|
||||
param_model=EmptyParamModel,
|
||||
domains=['other.com'],
|
||||
page_filter=lambda page: 'admin' in page.url,
|
||||
),
|
||||
}
|
||||
|
||||
registry.actions = actions
|
||||
|
||||
# Check that all matching filters are included
|
||||
description = registry.get_prompt_description(mock_page)
|
||||
assert 'domain_only' in description
|
||||
assert 'page_only' in description
|
||||
assert 'both_matching' in description
|
||||
assert 'both_one_fail' in description # Should match because page_filter matches
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_registry_action_decorator(self):
|
||||
"""Test the action decorator with filters"""
|
||||
registry = Registry()
|
||||
|
||||
# Define actions with different filters
|
||||
@registry.action(
|
||||
description='No filter action',
|
||||
)
|
||||
def no_filter_action():
|
||||
pass
|
||||
|
||||
@registry.action(description='Domain filter action', domains=['example.com'])
|
||||
def domain_filter_action():
|
||||
pass
|
||||
|
||||
@registry.action(description='Page filter action', page_filter=lambda page: 'admin' in page.url)
|
||||
def page_filter_action():
|
||||
pass
|
||||
|
||||
# Check that system prompt only includes the no_filter_action
|
||||
system_description = registry.get_prompt_description()
|
||||
assert 'No filter action' in system_description
|
||||
assert 'Domain filter action' not in system_description
|
||||
assert 'Page filter action' not in system_description
|
||||
|
||||
# Check that page-specific prompt includes the right actions
|
||||
mock_page = MagicMock(spec=Page)
|
||||
mock_page.url = 'https://example.com/admin'
|
||||
|
||||
page_description = registry.get_prompt_description(mock_page)
|
||||
assert 'Domain filter action' in page_description
|
||||
assert 'Page filter action' in page_description
|
||||
|
||||
Reference in New Issue
Block a user