From a981ae6bd8b96a8f1aa5e2e098935cb38ea4b042 Mon Sep 17 00:00:00 2001
From: ValueOn AG
Date: Wed, 18 Feb 2026 21:37:15 +0100
Subject: [PATCH] fix: poll for interstitial buttons instead of one-shot check,
race all selectors
Co-authored-by: Cursor
---
src/bot/orchestrator.ts | 63 ++++++++++++++++++++++++-----------------
1 file changed, 37 insertions(+), 26 deletions(-)
diff --git a/src/bot/orchestrator.ts b/src/bot/orchestrator.ts
index 43d21b3..86c414a 100644
--- a/src/bot/orchestrator.ts
+++ b/src/bot/orchestrator.ts
@@ -250,40 +250,51 @@ export class BotOrchestrator {
timeout: 30000,
});
- // Teams might show a "Continue on this browser" interstitial or redirect
- // Wait for the page to settle
- await this._page!.waitForTimeout(3000);
+ // Teams may show interstitials before the pre-join screen.
+ // Poll for ALL possible next-step buttons simultaneously so we don't
+ // miss one if it appears slowly.
const currentUrl = this._page!.url();
this._logger.info(`Auth join: URL after meeting navigation: ${currentUrl.substring(0, 150)}`);
- // Handle "Continue on this browser" if shown (same as anonymous flow)
- try {
- const continueBtn = await this._page!.$('button:has-text("Continue on this browser"), button:has-text("In diesem Browser fortfahren")');
- if (continueBtn) {
- await continueBtn.click();
- this._logger.info('Clicked "Continue on this browser"');
- await this._page!.waitForTimeout(3000);
- }
- } catch { /* not shown for auth users — expected */ }
-
- // Handle "Join" button if Teams shows the chat view first
- // (some meeting URLs redirect to the chat thread with a Join button)
- const chatJoinSelectors = [
+ // Race: wait for whichever button appears first (interstitial OR pre-join)
+ const interstitialSelectors = [
+ 'button:has-text("Continue on this browser")',
+ 'button:has-text("In diesem Browser fortfahren")',
+ 'button:has-text("Weiter in diesem Browser")',
'button[data-tid="chat-join-button"]',
'button[data-tid="join-call-button"]',
];
- let chatJoinClicked = false;
- for (const selector of chatJoinSelectors) {
- try {
- const btn = await this._page!.$(selector);
- if (btn) {
- await btn.click();
- chatJoinClicked = true;
- this._logger.info(`Clicked chat "Join" button: ${selector}`);
+ const preJoinSelectors = [
+ 'button:has-text("Join now")',
+ 'button:has-text("Jetzt teilnehmen")',
+ 'button[data-tid="prejoin-join-button"]',
+ ];
+ const allSelectors = [...interstitialSelectors, ...preJoinSelectors].join(', ');
+
+ // Poll up to 30s for ANY of these buttons
+ this._logger.info('Waiting for interstitial or pre-join button...');
+ try {
+ const firstBtn = await this._page!.waitForSelector(allSelectors, {
+ timeout: 30000, state: 'visible',
+ });
+ if (firstBtn) {
+ const btnText = await firstBtn.textContent().catch(() => '');
+ const btnTid = await firstBtn.getAttribute('data-tid').catch(() => '');
+ this._logger.info(`First visible button: "${btnText?.trim()}" (data-tid="${btnTid}")`);
+
+ // If it's an interstitial button (not pre-join), click it and wait for the next screen
+ const isPreJoin = preJoinSelectors.some(s =>
+ s.includes(btnTid || '__none__') || (btnText && s.includes(btnText.trim()))
+ );
+ if (!isPreJoin) {
+ await firstBtn.click();
+ this._logger.info('Clicked interstitial button, waiting for pre-join screen...');
await this._page!.waitForTimeout(3000);
- break;
}
- } catch { /* continue */ }
+ }
+ } catch {
+ this._logger.warn('No interstitial or pre-join button found within 30s');
+ await this._takeScreenshot('auth-no-buttons');
}
// STEP 5: Pre-Join screen → Click "Join now"