import asyncio from app.routers.auth_capture import _sanitize_candidate 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 == [] def test_sanitize_candidate_strips_secret_fields_but_keeps_metadata(): sanitized = _sanitize_candidate({ "type": "cookie", "source": "cookie:session", "value": "Bearer secret-token", "preview": "Bearer s…token", "label": "session cookie", "confidence": 90, "cookie_name": "session", "cookie_value": "secret-cookie", "domain": "example.test", }) assert sanitized == { "type": "cookie", "source": "cookie:session", "preview": "Bearer s…token", "label": "session cookie", "confidence": 90, "cookie_name": "session", "domain": "example.test", }