Add remote browser pages and website sync

Enable managed remote browser custom pages with login autofill and add website sync workflows so external admin surfaces can be handled inside SmartUp.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
liumangmang
2026-05-15 15:43:58 +08:00
parent a13a0070a5
commit 7adc7c00ab
43 changed files with 6615 additions and 641 deletions
+104
View File
@@ -0,0 +1,104 @@
import asyncio
from app.services.browser_session_service import BrowserSessionService
class FakeLocator:
def __init__(self, *, visible=True, count=1):
self._visible = list(visible) if isinstance(visible, list) else [visible]
self._count = count
self.filled = []
self.clicked = 0
self.timeouts = []
@property
def first(self):
return self
async def count(self):
return self._count
async def is_visible(self, timeout=0):
self.timeouts.append(timeout)
if not self._visible:
return False
if len(self._visible) == 1:
return self._visible[0]
return self._visible.pop(0)
async def fill(self, value, timeout=0):
self.filled.append((value, timeout))
async def click(self, timeout=0):
self.clicked += 1
class FakePage:
url = "https://example.test/login"
def __init__(self, locators):
self.locators = locators
self.queries = []
def locator(self, selector):
self.queries.append(selector)
return self.locators.get(selector, FakeLocator(visible=False, count=0))
def run(coro):
return asyncio.run(coro)
def test_autofill_retries_until_delayed_fields_are_visible():
service = BrowserSessionService()
username = FakeLocator(visible=[False, True])
password = FakeLocator(visible=True)
submit = FakeLocator(visible=True)
page = FakePage({
"#user": username,
"#pass": password,
"#submit": submit,
})
run(service._autofill_login(
page,
{
"enabled": True,
"username": "alice",
"password": "secret",
"username_selector": "#user",
"password_selector": "#pass",
"submit_selector": "#submit",
},
max_wait_seconds=1,
poll_interval_seconds=0,
))
assert page.queries[0] == "#user"
assert "#pass" in page.queries
assert "input[type='password']" not in page.queries
assert username.filled == [("alice", 3000)]
assert password.filled == [("secret", 3000)]
assert submit.clicked == 1
def test_autofill_returns_without_selectors_when_disabled_or_missing_credentials():
service = BrowserSessionService()
disabled_page = FakePage({"#user": FakeLocator()})
run(service._autofill_login(
disabled_page,
{"enabled": False, "username": "alice", "password": "secret"},
max_wait_seconds=1,
poll_interval_seconds=0,
))
assert disabled_page.queries == []
missing_password_page = FakePage({"#user": FakeLocator()})
run(service._autofill_login(
missing_password_page,
{"enabled": True, "username": "alice", "password": ""},
max_wait_seconds=1,
poll_interval_seconds=0,
))
assert missing_password_page.queries == []