From f7e0c194d5090183ae73aa88a612ab308cd6c99f Mon Sep 17 00:00:00 2001
From: ValueOn AG
Date: Tue, 17 Feb 2026 12:41:24 +0100
Subject: [PATCH] fix: parse meeting ID + passcode separately, fill both
fields, click Join meeting
Co-authored-by: Cursor
---
src/bot/authTestProcedure.ts | 177 ++++++++++++++++++++++++++++++-----
1 file changed, 151 insertions(+), 26 deletions(-)
diff --git a/src/bot/authTestProcedure.ts b/src/bot/authTestProcedure.ts
index 60cbaae..e10c0f3 100644
--- a/src/bot/authTestProcedure.ts
+++ b/src/bot/authTestProcedure.ts
@@ -363,37 +363,105 @@ async function _runVariant(
_log('warn', '"Join a meeting" button not found on landing page');
}
- // Wait for the resulting page to FULLY load
- _log('info', 'Waiting for resulting page to fully load...');
+ // Wait for the "Join a meeting" form to FULLY load
+ _log('info', 'Waiting for Join a meeting form to load...');
await page.waitForTimeout(5000);
try {
await page.waitForLoadState('networkidle', { timeout: 20000 });
} catch {
_log('warn', 'networkidle timeout, continuing');
}
- await page.waitForTimeout(5000);
- await _screenshotStep('3 - Nach "Join a meeting"');
+ await page.waitForTimeout(3000);
+ await _screenshotStep('3 - Join a meeting Formular');
- // If there's an input for meeting URL, enter it
- _log('info', 'Looking for meeting URL input...');
- const meetingInputSelectors = [
- 'input[placeholder*="meeting" i]',
- 'input[placeholder*="code" i]',
- 'input[placeholder*="link" i]',
- 'input[placeholder*="ID" i]',
- 'input[type="text"]',
- 'input[type="url"]',
+ // Parse meeting URL to extract Meeting ID and Passcode
+ // URL format: https://teams.microsoft.com/meet/36438888781520?p=5fGqrujxzewPFjJacW
+ const { meetingId, passcode } = _parseMeetingUrl(meetingUrl);
+ _log('info', `Parsed meeting URL: ID="${meetingId}", Passcode="${passcode ? passcode.substring(0, 5) + '...' : 'none'}"`);
+
+ // Fill Meeting ID field
+ if (meetingId) {
+ _log('info', 'Looking for Meeting ID input...');
+ const idInputSelectors = [
+ 'input[placeholder*="meeting" i]',
+ 'input[placeholder*="Meeting ID" i]',
+ 'input[placeholder*="ID" i]',
+ 'input[aria-label*="Meeting ID" i]',
+ 'input[type="text"]:first-of-type',
+ ];
+
+ let idFilled = false;
+ for (const selector of idInputSelectors) {
+ try {
+ const input = await page.waitForSelector(selector, { timeout: 5000, state: 'visible' });
+ if (input) {
+ await input.fill(meetingId);
+ _log('info', `Entered Meeting ID in: ${selector}`);
+ idFilled = true;
+ await page.waitForTimeout(1000);
+ break;
+ }
+ } catch {
+ // Try next
+ }
+ }
+ if (!idFilled) {
+ _log('warn', 'Meeting ID input not found');
+ }
+ }
+
+ // Fill Passcode field
+ if (passcode) {
+ _log('info', 'Looking for Passcode input...');
+ const passcodeSelectors = [
+ 'input[placeholder*="passcode" i]',
+ 'input[placeholder*="Passcode" i]',
+ 'input[placeholder*="password" i]',
+ 'input[aria-label*="passcode" i]',
+ 'input[aria-label*="Passcode" i]',
+ ];
+
+ let passcodeFilled = false;
+ for (const selector of passcodeSelectors) {
+ try {
+ const input = await page.waitForSelector(selector, { timeout: 5000, state: 'visible' });
+ if (input) {
+ await input.fill(passcode);
+ _log('info', `Entered Passcode in: ${selector}`);
+ passcodeFilled = true;
+ await page.waitForTimeout(1000);
+ break;
+ }
+ } catch {
+ // Try next
+ }
+ }
+ if (!passcodeFilled) {
+ _log('warn', 'Passcode input not found');
+ }
+ }
+
+ await _screenshotStep('4 - Meeting-Daten eingegeben');
+
+ // Click "Join meeting" button
+ _log('info', 'Looking for "Join meeting" button...');
+ const joinBtnSelectors = [
+ 'button:has-text("Join meeting")',
+ 'button:has-text("Besprechung beitreten")',
+ 'button:has-text("Join now")',
+ 'button:has-text("Jetzt teilnehmen")',
+ 'button[data-tid="joinMeetingButton"]',
+ 'button[data-tid="join-meeting-button"]',
];
- let meetingInputFound = false;
- for (const selector of meetingInputSelectors) {
+ let joinClicked = false;
+ for (const selector of joinBtnSelectors) {
try {
- const input = await page.waitForSelector(selector, { timeout: 5000, state: 'visible' });
- if (input) {
- await input.fill(meetingUrl);
- _log('info', `Entered meeting URL in: ${selector}`);
- meetingInputFound = true;
- await page.waitForTimeout(3000);
+ const btn = await page.waitForSelector(selector, { timeout: 5000, state: 'visible' });
+ if (btn) {
+ await btn.click();
+ _log('info', `Clicked "Join meeting": ${selector}`);
+ joinClicked = true;
break;
}
} catch {
@@ -401,12 +469,36 @@ async function _runVariant(
}
}
- if (meetingInputFound) {
- await page.waitForTimeout(5000);
- await _screenshotStep('4 - Meeting URL eingegeben');
- } else {
- _log('warn', 'No meeting URL input field found');
+ if (!joinClicked) {
+ _log('warn', '"Join meeting" button not found — logging all visible buttons');
+ try {
+ const buttons = await page.evaluate(() => {
+ const btns = document.querySelectorAll('button');
+ return Array.from(btns).slice(0, 20).map(b => {
+ const text = (b.textContent || '').trim().substring(0, 80);
+ const tid = b.getAttribute('data-tid') || '';
+ const disabled = b.disabled ? ' DISABLED' : '';
+ return `[BUTTON tid="${tid}"${disabled}] ${text}`;
+ });
+ });
+ buttons.forEach(b => _log('info', ` ${b}`));
+ } catch {
+ // Ignore
+ }
}
+
+ // Wait for resulting page after clicking Join
+ if (joinClicked) {
+ _log('info', 'Waiting for page after Join meeting...');
+ await page.waitForTimeout(5000);
+ try {
+ await page.waitForLoadState('networkidle', { timeout: 30000 });
+ } catch {
+ _log('warn', 'networkidle timeout after Join, continuing');
+ }
+ await page.waitForTimeout(10000);
+ }
+ await _screenshotStep('5 - Nach Join meeting');
}
// =====================================================================
@@ -753,6 +845,39 @@ function _getDeviceSpoofScript(): void {
}
}
+// ============================================================================
+// MEETING URL PARSER
+// ============================================================================
+
+/**
+ * Parse a Teams meeting URL to extract Meeting ID and Passcode.
+ * URL format: https://teams.microsoft.com/meet/36438888781520?p=5fGqrujxzewPFjJacW
+ * Meeting ID: 36438888781520 (from path)
+ * Passcode: 5fGqrujxzewPFjJacW (from ?p= parameter)
+ */
+function _parseMeetingUrl(meetingUrl: string): { meetingId: string; passcode: string | null } {
+ try {
+ const parsed = new URL(meetingUrl.trim());
+
+ // Extract meeting ID from path: /meet/36438888781520
+ let meetingId = '';
+ if (parsed.pathname.includes('/meet/')) {
+ meetingId = parsed.pathname.split('/meet/')[1] || '';
+ // Remove trailing slashes
+ meetingId = meetingId.replace(/\/$/, '');
+ }
+
+ // Extract passcode from ?p= parameter
+ const passcode = parsed.searchParams.get('p') || null;
+
+ return { meetingId, passcode };
+ } catch {
+ // If URL parsing fails, try to extract digits as meeting ID
+ const digits = meetingUrl.replace(/\D/g, '');
+ return { meetingId: digits, passcode: null };
+ }
+}
+
// ============================================================================
// URL RESOLUTION
// ============================================================================