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:
@@ -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 == []
|
||||
Reference in New Issue
Block a user