From 121c70e60ada89f5ac61ef504c0d7fb9883eca20 Mon Sep 17 00:00:00 2001 From: ValueOn AG Date: Mon, 16 Feb 2026 12:56:42 +0100 Subject: [PATCH] fix: wait up to 20s for 'Sign in' link on pre-join page (was only checking once after 3s) Co-authored-by: Cursor --- src/bot/orchestrator.ts | 70 +++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/src/bot/orchestrator.ts b/src/bot/orchestrator.ts index 0b2b84f..9970b3a 100644 --- a/src/bot/orchestrator.ts +++ b/src/bot/orchestrator.ts @@ -147,45 +147,42 @@ export class BotOrchestrator { // anonymous pre-join page. Clicking it triggers the Microsoft login flow, // which redirects back to an authenticated pre-join page within Teams v2. if (authenticate) { - this._logger.info('Authenticated join: looking for "Sign in" link on pre-join page...'); - - // Wait for the pre-join page to load - await this._page!.waitForTimeout(3000); - - // Dismiss mic/camera permission overlay if present - // The "Continue without audio or video" modal may appear here - await this._joinProcedure.dismissBrowserPermissionModals(); - - // Find and click the "Sign in" link at the bottom of the pre-join page - const signInSelectors = [ - 'a:has-text("Sign in")', - 'button:has-text("Sign in")', - 'a:has-text("Anmelden")', - 'button:has-text("Anmelden")', - 'a[href*="login"]', - ]; + this._logger.info('Authenticated join: waiting for pre-join page to load, then clicking "Sign in"...'); + // Wait for the pre-join page to fully load. + // After "Continue on this browser", Teams loads the light-meetings pre-join page. + // This can take 5-15 seconds and may show mic/camera permission overlays. + // The "Sign in" link appears at the bottom of the page once it's loaded. + + // Wait for "Sign in" link to appear (up to 20 seconds) let signInClicked = false; - for (const sel of signInSelectors) { - try { - const link = await this._page!.$(sel); - if (link) { - await link.click(); - this._logger.info(`Clicked "Sign in" link: ${sel}`); - signInClicked = true; - break; - } - } catch { /* continue */ } + const signInSelector = 'a:has-text("Sign in"), button:has-text("Sign in"), a:has-text("Anmelden"), button:has-text("Anmelden")'; + + try { + this._logger.info('Waiting for "Sign in" link to appear on pre-join page...'); + await this._page!.waitForSelector(signInSelector, { timeout: 20000, state: 'visible' }); + + // Click it + const signInLink = await this._page!.$(signInSelector); + if (signInLink) { + await signInLink.click(); + this._logger.info('Clicked "Sign in" link on pre-join page'); + signInClicked = true; + } + } catch { + this._logger.info('"Sign in" not found via waitForSelector, trying DOM scan...'); } + // Fallback: scan DOM for sign-in link if (!signInClicked) { - // Fallback: try to find "Sign in" by evaluating text content + // The page might have loaded but the selector didn't match exactly signInClicked = await this._page!.evaluate(() => { - const links = document.querySelectorAll('a, button'); - for (let i = 0; i < links.length; i++) { - const el = links[i] as HTMLElement; - const text = el.innerText?.trim().toLowerCase() || ''; - if (text === 'sign in' || text === 'anmelden') { + // Look for any link/button with "Sign in" or "Anmelden" text + const allElements = document.querySelectorAll('a, button, span[role="link"]'); + for (let i = 0; i < allElements.length; i++) { + const el = allElements[i] as HTMLElement; + const text = el.innerText?.trim() || ''; + if (text === 'Sign in' || text === 'Anmelden') { el.click(); return true; } @@ -193,7 +190,12 @@ export class BotOrchestrator { return false; }); if (signInClicked) { - this._logger.info('Clicked "Sign in" via DOM evaluation'); + this._logger.info('Clicked "Sign in" via DOM evaluation fallback'); + } else { + this._logger.warn('Could not find "Sign in" link on pre-join page'); + // Log page content for debugging + const pageText = await this._page!.evaluate(() => document.body?.innerText?.substring(0, 500) || ''); + this._logger.warn(`Pre-join page content: ${pageText.substring(0, 300)}`); } }