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)}`);
}
}