mirror of
https://github.com/FoundationAgents/MetaGPT.git
synced 2026-04-25 00:36:55 +02:00
添加浏览器工具单测
This commit is contained in:
parent
8fe00a1788
commit
0831d3d501
2 changed files with 94 additions and 62 deletions
|
|
@ -4,4 +4,4 @@ llm:
|
|||
api_type: "openai" # or azure / ollama / open_llm etc. Check LLMType for more options
|
||||
model: "gpt-4-turbo-preview" # or gpt-3.5-turbo-1106 / gpt-4-1106-preview
|
||||
base_url: "https://api.openai.com/v1" # or forward url / other llm url
|
||||
api_key: "YOUR_API_KEY"
|
||||
api_key: "YOUR_API_KEY-hui"
|
||||
|
|
@ -1,90 +1,122 @@
|
|||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
|
||||
from metagpt.const import TEST_DATA_PATH
|
||||
from metagpt.tools.libs.browser import Browser, get_scroll_position
|
||||
from metagpt.tools.libs.browser import Browser
|
||||
|
||||
TEST_URL = "https://docs.deepwisdom.ai/main/en/guide/get_started/quickstart.html"
|
||||
|
||||
TEST_SCREENSHOT_PATH = TEST_DATA_PATH / "screenshot.png"
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def llm_mock(rsp_cache, mocker, request):
|
||||
# An empty fixture to overwrite the global llm_mock fixture
|
||||
# because in provider folder, we want to test the aask and aask functions for the specific models
|
||||
pass
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def browser():
|
||||
browser_instance = Browser()
|
||||
yield browser_instance
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_open_and_switch_page(browser):
|
||||
await browser.start()
|
||||
class TestBrowser:
|
||||
test_url = "https://juejin.cn/"
|
||||
|
||||
await browser.open_new_page("https://baidu.com")
|
||||
await browser.open_new_page("https://tencent.com")
|
||||
assert browser.current_page_url == "https://tencent.com"
|
||||
await browser.switch_page("https://baidu.com")
|
||||
assert browser.current_page_url == "https://baidu.com"
|
||||
@pytest_asyncio.fixture(autouse=True)
|
||||
async def browser_client(self):
|
||||
"""Setup before each test case."""
|
||||
print("browser_client")
|
||||
browser = await self.async_setup()
|
||||
yield browser
|
||||
await self.browser.stop()
|
||||
|
||||
await browser.close()
|
||||
async def async_setup(self):
|
||||
self.browser = Browser(headless=True)
|
||||
await self.browser.start()
|
||||
return self.browser
|
||||
|
||||
async def async_teardown(self):
|
||||
"""Teardown after each test case."""
|
||||
await self.browser.stop()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_search(browser):
|
||||
await browser.start()
|
||||
async def test_start_and_stop(self):
|
||||
"""Test browser start and stop functionality."""
|
||||
assert self.browser.playwright is not None
|
||||
assert self.browser.browser_instance is not None
|
||||
assert self.browser.browser_ctx is not None
|
||||
assert self.browser.page is not None
|
||||
|
||||
# search all
|
||||
await browser.open_new_page(TEST_URL)
|
||||
search_term = "startup example"
|
||||
search_results = await browser.search_content_all(search_term)
|
||||
print(search_results)
|
||||
# expected search result as of 20240410:
|
||||
# [{'index': 0, 'content': {'text_block': 'Below is a breakdown of the software startup example. If you install MetaGPT with the git clone approach, simply run', 'links': [{'text': 'software startup example', 'href': 'https://github.com/geekan/MetaGPT/blob/main/metagpt/software_company.py'}]}, 'position': {'from_top': 640, 'from_left': 225}, 'element_obj': <Locator frame=<Frame name= url='https://docs.deepwisdom.ai/main/en/guide/get_started/quickstart.html'> selector='text=startup example >> nth=0'>}]
|
||||
first_result = search_results[0]["content"]
|
||||
assert "software startup example" in first_result["text_block"]
|
||||
assert first_result["links"]
|
||||
assert first_result["links"][0]["href"] == "https://github.com/geekan/MetaGPT/blob/main/metagpt/software_company.py"
|
||||
assert search_results[0]["position"]
|
||||
await self.async_teardown()
|
||||
|
||||
# scroll to search result
|
||||
await browser.scroll_to_search_result(search_results, index=0)
|
||||
assert self.browser.playwright is None
|
||||
assert self.browser.browser_instance is None
|
||||
assert self.browser.browser_ctx is None
|
||||
|
||||
await browser.close()
|
||||
async def test_goto(self):
|
||||
"""Test navigating to a URL."""
|
||||
mock_reporter = AsyncMock()
|
||||
self.browser.reporter = mock_reporter
|
||||
|
||||
result = await self.browser.goto(self.test_url)
|
||||
assert "SUCCESS" in result
|
||||
assert self.test_url in self.browser.page.url
|
||||
|
||||
# @pytest.mark.asyncio
|
||||
# async def test_find_links(browser):
|
||||
# await browser.start()
|
||||
@patch("metagpt.tools.libs.browser.click_element", new_callable=AsyncMock)
|
||||
async def test_click(self, mock_click_element):
|
||||
"""Test clicking on an element."""
|
||||
self.browser.accessibility_tree = [
|
||||
{"nodeId": "1", "backendDOMNodeId": 101, "name": "Button"},
|
||||
{"nodeId": "2", "backendDOMNodeId": 102, "name": "Input"},
|
||||
]
|
||||
self.browser.page = AsyncMock()
|
||||
|
||||
# await browser.open_new_page(TEST_URL)
|
||||
# link_info = await browser.find_links()
|
||||
# assert link_info
|
||||
await self.browser.click(1)
|
||||
|
||||
# await browser.close()
|
||||
mock_click_element.assert_called_once()
|
||||
|
||||
@patch("metagpt.tools.libs.browser.click_element", new_callable=AsyncMock)
|
||||
@patch("metagpt.tools.libs.browser.type_text", new_callable=AsyncMock)
|
||||
async def test_type(self, mock_type_text, mock_click_element):
|
||||
"""Test typing text into an input field."""
|
||||
content = "Hello, world!"
|
||||
self.browser.accessibility_tree = [
|
||||
{"nodeId": "1", "backendDOMNodeId": 101, "name": "Button"},
|
||||
{"nodeId": "2", "backendDOMNodeId": 102, "name": "Input"},
|
||||
]
|
||||
self.browser.page = AsyncMock()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_scroll(browser):
|
||||
await browser.start()
|
||||
await self.browser.type(1, content)
|
||||
|
||||
await browser.open_new_page(TEST_URL)
|
||||
mock_click_element.assert_called_once()
|
||||
mock_type_text.assert_called_once_with(self.browser.page, content)
|
||||
|
||||
await browser.scroll_current_page(offset=-500)
|
||||
assert await get_scroll_position(browser.current_page) == {"x": 0, "y": 0} # no change if you scrol up from top
|
||||
initial_view = await browser._view()
|
||||
@patch("metagpt.tools.libs.browser.key_press", new_callable=AsyncMock)
|
||||
@patch("metagpt.tools.libs.browser.hover_element", new_callable=AsyncMock)
|
||||
async def test_hover_press(self, mock_hover_element, mock_key_press):
|
||||
"""Test Hover and press key"""
|
||||
self.browser.accessibility_tree = [
|
||||
{"nodeId": "1", "backendDOMNodeId": 101, "name": "Button"},
|
||||
{"nodeId": "2", "backendDOMNodeId": 102, "name": "Input"},
|
||||
]
|
||||
self.browser.page = AsyncMock()
|
||||
|
||||
await browser.scroll_current_page(offset=500) # scroll down
|
||||
assert await get_scroll_position(browser.current_page) == {"x": 0, "y": 500}
|
||||
scrolled_view = await browser._view()
|
||||
key_comb = "Enter"
|
||||
await self.browser.hover(1)
|
||||
await self.browser.press(key_comb)
|
||||
mock_hover_element.assert_called_once()
|
||||
mock_key_press.assert_called_once_with(self.browser.page, key_comb)
|
||||
|
||||
assert initial_view != scrolled_view
|
||||
async def test_scroll(self):
|
||||
"""Scroll the page up or down."""
|
||||
await self.browser.scroll("down")
|
||||
await self.browser.scroll("up")
|
||||
|
||||
await browser.scroll_current_page(offset=-200) # scroll up
|
||||
assert await get_scroll_position(browser.current_page) == {"x": 0, "y": 300}
|
||||
async def test_go_back_and_forward(self):
|
||||
await self.browser.go_back()
|
||||
await self.browser.go_forward()
|
||||
|
||||
await browser.close()
|
||||
async def test_tab_focus(self):
|
||||
await self.browser.tab_focus(0)
|
||||
|
||||
async def test_close_tab(self):
|
||||
"""Test closing a tab."""
|
||||
mock_close = AsyncMock()
|
||||
self.browser.page = AsyncMock()
|
||||
self.browser.page.close = mock_close
|
||||
|
||||
await self.browser.close_tab()
|
||||
|
||||
mock_close.assert_called_once()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue