From fab600fa07509962e85325870fb823c9b49aaa2f Mon Sep 17 00:00:00 2001 From: Oliver Hofmann Date: Sun, 17 May 2026 17:58:01 +0200 Subject: [PATCH] fix: search slotted light DOM content, increase dialog timeout to 15s --- src/teampulse/resolver.py | 90 ++++++++++++++------------------------- 1 file changed, 31 insertions(+), 59 deletions(-) diff --git a/src/teampulse/resolver.py b/src/teampulse/resolver.py index a10fcc0..dced5db 100644 --- a/src/teampulse/resolver.py +++ b/src/teampulse/resolver.py @@ -107,74 +107,46 @@ class Resolver: print(f" '{display_name}' via '{strategy}' geklickt — warte auf Dialog...") try: - # Wait for the profile dialog to open - # Could be lpc_ip_root_class (hover card) or a role="dialog" modal - self._page.wait_for_selector( - ".lpc_ip_root_class, [role='dialog']", - timeout=6_000, - ) + # The dialog can take several seconds to fully load — wait up to 15s + self._page.wait_for_selector(".lpc_ip_root_class", timeout=15_000) except Exception: - print(f" Profil-Dialog für '{display_name}' erscheint nicht.") + print(f" Profil-Dialog für '{display_name}' erscheint nicht (Timeout).") self._page.keyboard.press("Escape") return None + # Wait for slotted content to load inside the lpc-card + time.sleep(2) + try: - # Check which dialog appeared and extract email - # Try shadow DOM of lpc-card first - email = self._page.evaluate("""() => { - // Check lpc-card shadow DOM + email = self._page.evaluate(r"""() => { const lpcCard = document.querySelector('.lpc_ip_root_class lpc-card'); - if (lpcCard && lpcCard.shadowRoot) { - const link = lpcCard.shadowRoot.querySelector('a[href*="mailto:"]'); - if (link) return link.href.replace('mailto:', '').trim(); - // Also check text content for email pattern - const text = lpcCard.shadowRoot.textContent; - const match = text.match(/[a-zA-Z0-9._%+\\-]+@[a-zA-Z0-9.\\-]+\\.[a-zA-Z]{2,}/); - if (match) return match[0]; + if (!lpcCard) return null; + + const EMAIL_RE = /[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}/; + + // 1. Slotted content = light DOM children of lpc-card (inserted into ) + const lightLink = lpcCard.querySelector('a[href*="mailto:"]'); + if (lightLink) return lightLink.href.replace('mailto:', '').trim(); + + const lightMatch = lpcCard.textContent.match(EMAIL_RE); + if (lightMatch) return lightMatch[0]; + + // 2. Shadow root of lpc-card + if (lpcCard.shadowRoot) { + const shadowLink = lpcCard.shadowRoot.querySelector('a[href*="mailto:"]'); + if (shadowLink) return shadowLink.href.replace('mailto:', '').trim(); + + const shadowMatch = lpcCard.shadowRoot.textContent.match(EMAIL_RE); + if (shadowMatch) return shadowMatch[0]; } - // Check regular dialog - const dialog = document.querySelector("[role='dialog']"); - if (dialog) { - const link = dialog.querySelector('a[href*="mailto:"]'); - if (link) return link.href.replace('mailto:', '').trim(); - const text = dialog.textContent; - const match = text.match(/[a-zA-Z0-9._%+\\-]+@[a-zA-Z0-9.\\-]+\\.[a-zA-Z]{2,}/); - if (match) return match[0]; - } - return null; + + // 3. Diagnostic: return light DOM text for inspection + return '__DEBUG__' + lpcCard.textContent.trim().substring(0, 300); }""") - if not email: - # Wait a bit more for the dialog to fully load (two-stage) - time.sleep(2) - email = self._page.evaluate("""() => { - function findEmail(root) { - const link = root.querySelector('a[href*="mailto:"]'); - if (link) return link.href.replace('mailto:', '').trim(); - const match = root.textContent.match(/[a-zA-Z0-9._%+\\-]+@[a-zA-Z0-9.\\-]+\\.[a-zA-Z]{2,}/); - if (match) return match[0]; - // Search shadow roots recursively - for (const el of root.querySelectorAll('*')) { - if (el.shadowRoot) { - const found = findEmail(el.shadowRoot); - if (found) return found; - } - } - return null; - } - return findEmail(document.body); - }""") - - if not email: - # Diagnostic: show what's in the dialog - content = self._page.evaluate("""() => { - const d = document.querySelector('.lpc_ip_root_class lpc-card'); - if (d && d.shadowRoot) return 'shadow: ' + d.shadowRoot.textContent.trim().substring(0, 200); - const r = document.querySelector("[role='dialog']"); - if (r) return 'dialog: ' + r.textContent.trim().substring(0, 200); - return '(nichts gefunden)'; - }""") - print(f" Dialog offen, E-Mail nicht gefunden. Inhalt: {content!r}") + if email and email.startswith('__DEBUG__'): + print(f" Dialog offen, E-Mail nicht gefunden. Inhalt: {email[9:200]!r}") + email = None self._page.keyboard.press("Escape") time.sleep(0.3)