refactor: drastically shortened auth test flow - direct login to chat to pre-join to meeting
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
68cf43c5fa
commit
35dd781d90
1 changed files with 88 additions and 254 deletions
|
|
@ -234,7 +234,7 @@ async function _runVariant(
|
|||
}
|
||||
|
||||
// =====================================================================
|
||||
// STEP 1: Navigate to teams.microsoft.com
|
||||
// STEP 1: Navigate to teams.microsoft.com → MS Login
|
||||
// =====================================================================
|
||||
_log('info', 'Step 1: Navigate to teams.microsoft.com');
|
||||
await page.goto('https://teams.microsoft.com', {
|
||||
|
|
@ -242,7 +242,6 @@ async function _runVariant(
|
|||
timeout: 30000,
|
||||
});
|
||||
|
||||
// Wait for login redirect OR the Teams landing page to appear
|
||||
_log('info', 'Waiting for login.microsoftonline.com redirect...');
|
||||
try {
|
||||
await page.waitForURL('**/login.microsoftonline.com/**', { timeout: 30000 });
|
||||
|
|
@ -251,37 +250,31 @@ async function _runVariant(
|
|||
_log('warn', `No login redirect, current URL: ${page.url().substring(0, 150)}`);
|
||||
}
|
||||
|
||||
// Wait for the login page to FULLY RENDER (email input visible)
|
||||
_log('info', 'Waiting for login page to fully render...');
|
||||
// Wait for login page to render
|
||||
try {
|
||||
await page.waitForSelector(
|
||||
'input[name="loginfmt"], input[type="email"], button:has-text("Sign in"), button:has-text("Join a meeting")',
|
||||
{ timeout: 15000, state: 'visible' },
|
||||
);
|
||||
await page.waitForSelector('input[name="loginfmt"], input[type="email"]', { timeout: 15000, state: 'visible' });
|
||||
await page.waitForTimeout(1000);
|
||||
} catch {
|
||||
_log('warn', 'Login page elements not found, taking screenshot anyway');
|
||||
_log('warn', 'Login page elements not found');
|
||||
await page.waitForTimeout(2000);
|
||||
}
|
||||
await _screenshotStep('1 - Login-Seite');
|
||||
|
||||
// =====================================================================
|
||||
// STEP 2: Microsoft Login
|
||||
// STEP 2: Microsoft Authentication
|
||||
// =====================================================================
|
||||
if (botAccountEmail && botAccountPassword) {
|
||||
authAttempted = true;
|
||||
|
||||
// Check if we're on login.microsoftonline.com or on the Teams landing page
|
||||
const currentUrl = page.url();
|
||||
const onMsLogin = currentUrl.includes('login.microsoftonline.com') || currentUrl.includes('login.live.com');
|
||||
|
||||
if (onMsLogin) {
|
||||
_log('info', `On MS login page, authenticating as ${botAccountEmail}`);
|
||||
_log('info', `Authenticating as ${botAccountEmail}`);
|
||||
const authProcedure = new AuthProcedure(page, logger);
|
||||
authSuccess = await authProcedure.authenticateWithMicrosoft(botAccountEmail, botAccountPassword, true);
|
||||
_log(authSuccess ? 'info' : 'warn', `Auth result: ${authSuccess ? 'success' : 'failed'}`);
|
||||
} else {
|
||||
_log('info', 'Not on MS login page — Teams may already be loaded. Skipping auth step.');
|
||||
_log('info', 'Not on MS login page, skipping auth');
|
||||
authSuccess = null;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -289,11 +282,11 @@ async function _runVariant(
|
|||
}
|
||||
|
||||
// =====================================================================
|
||||
// STEP 3: Wait for Teams landing page to fully render
|
||||
// STEP 3: Wait for Teams Chat page (= landing page after auth)
|
||||
// After login, bot lands directly on the Teams chat page with "Join" button
|
||||
// =====================================================================
|
||||
_log('info', 'Waiting for Teams landing page to fully render...');
|
||||
_log('info', 'Step 3: Waiting for Teams chat page to load...');
|
||||
|
||||
// Wait for redirect back to Teams (if we were on login page)
|
||||
if (authSuccess) {
|
||||
try {
|
||||
await page.waitForURL('**/teams.microsoft.com/**', { timeout: 30000 });
|
||||
|
|
@ -302,243 +295,37 @@ async function _runVariant(
|
|||
}
|
||||
}
|
||||
|
||||
// Wait for either "Sign in" or "Join a meeting" button to be visible
|
||||
// This is the Teams landing page ("Everyone together in Teams")
|
||||
_log('info', 'Waiting for "Sign in" or "Join a meeting" button to appear...');
|
||||
try {
|
||||
await page.waitForSelector(
|
||||
'button:has-text("Sign in"), button:has-text("Join a meeting"), button:has-text("Anmelden"), button:has-text("An Besprechung teilnehmen")',
|
||||
{ timeout: 30000, state: 'visible' },
|
||||
);
|
||||
await page.waitForTimeout(1000);
|
||||
_log('info', 'Teams landing page loaded');
|
||||
} catch {
|
||||
_log('warn', 'Landing page buttons not found after 30s');
|
||||
await page.waitForTimeout(2000);
|
||||
}
|
||||
await _screenshotStep('2 - Teams Landingpage');
|
||||
|
||||
// Log all visible buttons for debugging
|
||||
try {
|
||||
const buttons = await page.evaluate(() => {
|
||||
const btns = document.querySelectorAll('button, a[role="button"]');
|
||||
return Array.from(btns).slice(0, 20).map(b => {
|
||||
const text = (b.textContent || '').trim().substring(0, 80);
|
||||
const tid = b.getAttribute('data-tid') || '';
|
||||
return `[${b.tagName} tid="${tid}"] ${text}`;
|
||||
});
|
||||
});
|
||||
buttons.forEach(b => _log('info', ` Visible button: ${b}`));
|
||||
} catch {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
// =====================================================================
|
||||
// STEP 4: Click "Join a meeting"
|
||||
// =====================================================================
|
||||
_log('info', 'Step 4: Clicking "Join a meeting" on Teams landing page...');
|
||||
const joinSelectors = [
|
||||
'button:has-text("Join a meeting")',
|
||||
'button:has-text("An Besprechung teilnehmen")',
|
||||
'a:has-text("Join a meeting")',
|
||||
'a:has-text("An Besprechung teilnehmen")',
|
||||
];
|
||||
|
||||
let clicked = false;
|
||||
for (const selector of joinSelectors) {
|
||||
try {
|
||||
const btn = await page.waitForSelector(selector, { timeout: 5000, state: 'visible' });
|
||||
if (btn) {
|
||||
await btn.click();
|
||||
_log('info', `Clicked: ${selector}`);
|
||||
clicked = true;
|
||||
break;
|
||||
}
|
||||
} catch {
|
||||
// Try next
|
||||
}
|
||||
}
|
||||
|
||||
if (!clicked) {
|
||||
_log('warn', '"Join a meeting" button not found on landing page');
|
||||
}
|
||||
|
||||
// Wait for the "Join a meeting" form to load (wait for Meeting ID input)
|
||||
_log('info', 'Waiting for Join a meeting form to load...');
|
||||
try {
|
||||
await page.waitForSelector('input[placeholder*="meeting" i], input[placeholder*="Meeting" i], input[placeholder*="ID" i]', {
|
||||
timeout: 15000, state: 'visible',
|
||||
});
|
||||
await page.waitForTimeout(1000);
|
||||
} catch {
|
||||
_log('warn', 'Meeting form input not found, continuing');
|
||||
await page.waitForTimeout(2000);
|
||||
}
|
||||
await _screenshotStep('3 - Join a meeting Formular');
|
||||
|
||||
// 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 joinClicked = false;
|
||||
for (const selector of joinBtnSelectors) {
|
||||
try {
|
||||
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 {
|
||||
// Try next
|
||||
}
|
||||
}
|
||||
|
||||
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(3000);
|
||||
try {
|
||||
await page.waitForLoadState('networkidle', { timeout: 20000 });
|
||||
} catch {
|
||||
_log('warn', 'networkidle timeout after Join, continuing');
|
||||
}
|
||||
await page.waitForTimeout(5000);
|
||||
}
|
||||
await _screenshotStep('5 - Nach Join meeting');
|
||||
|
||||
// =====================================================================
|
||||
// STEP 6: Click "Join" button in Teams chat header to join the call
|
||||
// =====================================================================
|
||||
_log('info', 'Step 6: Looking for "Join" button in Teams chat header...');
|
||||
|
||||
// Wait for the Teams chat page to fully render
|
||||
// Wait for the "Join" button in the chat header — this confirms we're on the chat page
|
||||
try {
|
||||
await page.waitForSelector(
|
||||
'button[data-tid="chat-join-button"], button[data-tid="join-call-button"]',
|
||||
{ timeout: 30000, state: 'visible' },
|
||||
);
|
||||
_log('info', 'Teams chat page loaded, "Join" button found');
|
||||
_log('info', 'Teams chat page loaded, "Join" button found in header');
|
||||
} catch {
|
||||
_log('warn', '"Join" button not found in chat header after 30s — logging all buttons');
|
||||
_log('warn', '"Join" button not found in chat header after 30s');
|
||||
// Log all visible buttons for debugging
|
||||
try {
|
||||
const buttons = await page.evaluate(() => {
|
||||
const btns = document.querySelectorAll('button');
|
||||
return Array.from(btns).slice(0, 30).map(b => {
|
||||
return Array.from(btns).slice(0, 25).map(b => {
|
||||
const text = (b.textContent || '').trim().substring(0, 80);
|
||||
const tid = b.getAttribute('data-tid') || '';
|
||||
return `[BUTTON tid="${tid}"] ${text}`;
|
||||
});
|
||||
});
|
||||
buttons.forEach(b => _log('info', ` ${b}`));
|
||||
} catch {
|
||||
// Ignore
|
||||
}
|
||||
} catch { /* ignore */ }
|
||||
}
|
||||
await _screenshotStep('2 - Teams Chat');
|
||||
|
||||
await _screenshotStep('6 - Teams Chat (vor Join-Klick)');
|
||||
|
||||
// Click the "Join" button in the chat header
|
||||
// =====================================================================
|
||||
// STEP 4: Click "Join" in chat header → Pre-Join screen
|
||||
// =====================================================================
|
||||
_log('info', 'Step 4: Clicking "Join" in chat header...');
|
||||
const chatJoinSelectors = [
|
||||
'button[data-tid="chat-join-button"]',
|
||||
'button[data-tid="join-call-button"]',
|
||||
'button:has-text("Join")',
|
||||
'button:has-text("Beitreten")',
|
||||
];
|
||||
|
||||
let chatJoinClicked = false;
|
||||
|
|
@ -547,40 +334,89 @@ async function _runVariant(
|
|||
const btn = await page.waitForSelector(selector, { timeout: 5000, state: 'visible' });
|
||||
if (btn) {
|
||||
await btn.click();
|
||||
_log('info', `Clicked chat "Join" button: ${selector}`);
|
||||
_log('info', `Clicked: ${selector}`);
|
||||
chatJoinClicked = true;
|
||||
break;
|
||||
}
|
||||
} catch {
|
||||
// Try next
|
||||
}
|
||||
} catch { /* try next */ }
|
||||
}
|
||||
|
||||
if (!chatJoinClicked) {
|
||||
_log('warn', '"Join" button in chat header not found');
|
||||
}
|
||||
|
||||
// Wait for the meeting to load after clicking Join
|
||||
// Wait for pre-join screen (camera preview, "Join now" button)
|
||||
if (chatJoinClicked) {
|
||||
_log('info', 'Waiting for meeting view to load...');
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
// Wait for meeting UI elements (hangup button, video controls, etc.)
|
||||
_log('info', 'Waiting for pre-join screen...');
|
||||
try {
|
||||
await page.waitForSelector(
|
||||
'button[id="hangup-button"], button[data-tid="hangup-button"], [data-tid="prejoin-join-button"], [data-tid="calling-prejoin"]',
|
||||
'button:has-text("Join now"), button:has-text("Jetzt teilnehmen"), button[data-tid="prejoin-join-button"]',
|
||||
{ timeout: 30000, state: 'visible' },
|
||||
);
|
||||
_log('info', 'Meeting UI elements detected');
|
||||
_log('info', 'Pre-join screen loaded');
|
||||
} catch {
|
||||
_log('warn', 'Meeting UI elements not found after 30s');
|
||||
_log('warn', 'Pre-join "Join now" button not found after 30s');
|
||||
}
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
await page.waitForTimeout(2000);
|
||||
}
|
||||
await _screenshotStep('7 - Nach Join (Meeting-Ansicht)');
|
||||
await _screenshotStep('3 - Pre-Join Ansicht');
|
||||
|
||||
// Log all visible buttons on the final page for debugging
|
||||
// =====================================================================
|
||||
// STEP 5: Click "Join now" → Enter the meeting
|
||||
// =====================================================================
|
||||
_log('info', 'Step 5: Clicking "Join now"...');
|
||||
const joinNowSelectors = [
|
||||
'button:has-text("Join now")',
|
||||
'button:has-text("Jetzt teilnehmen")',
|
||||
'button[data-tid="prejoin-join-button"]',
|
||||
];
|
||||
|
||||
let joinNowClicked = false;
|
||||
for (const selector of joinNowSelectors) {
|
||||
try {
|
||||
const btn = await page.waitForSelector(selector, { timeout: 5000, state: 'visible' });
|
||||
if (btn) {
|
||||
await btn.click();
|
||||
_log('info', `Clicked "Join now": ${selector}`);
|
||||
joinNowClicked = true;
|
||||
break;
|
||||
}
|
||||
} catch { /* try next */ }
|
||||
}
|
||||
|
||||
if (!joinNowClicked) {
|
||||
_log('warn', '"Join now" button not found — logging all buttons');
|
||||
try {
|
||||
const buttons = await page.evaluate(() => {
|
||||
const btns = document.querySelectorAll('button');
|
||||
return Array.from(btns).slice(0, 25).map(b => {
|
||||
const text = (b.textContent || '').trim().substring(0, 80);
|
||||
const tid = b.getAttribute('data-tid') || '';
|
||||
return `[BUTTON tid="${tid}"] ${text}`;
|
||||
});
|
||||
});
|
||||
buttons.forEach(b => _log('info', ` ${b}`));
|
||||
} catch { /* ignore */ }
|
||||
}
|
||||
|
||||
// Wait for the actual meeting view (hangup button = we're in the meeting)
|
||||
if (joinNowClicked) {
|
||||
_log('info', 'Waiting for meeting to load...');
|
||||
await page.waitForTimeout(5000);
|
||||
try {
|
||||
await page.waitForSelector(
|
||||
'button[id="hangup-button"], button[data-tid="hangup-button"], #hangup-button',
|
||||
{ timeout: 30000, state: 'visible' },
|
||||
);
|
||||
_log('info', 'IN THE MEETING — hangup button visible!');
|
||||
} catch {
|
||||
_log('warn', 'Hangup button not found after 30s');
|
||||
}
|
||||
await page.waitForTimeout(3000);
|
||||
}
|
||||
await _screenshotStep('4 - Im Meeting');
|
||||
|
||||
// Log final page buttons for debugging
|
||||
try {
|
||||
const buttons = await page.evaluate(() => {
|
||||
const btns = document.querySelectorAll('button');
|
||||
|
|
@ -590,10 +426,8 @@ async function _runVariant(
|
|||
return `[BUTTON tid="${tid}"] ${text}`;
|
||||
});
|
||||
});
|
||||
buttons.forEach(b => _log('info', ` Final page button: ${b}`));
|
||||
} catch {
|
||||
// Ignore
|
||||
}
|
||||
buttons.forEach(b => _log('info', ` Final: ${b}`));
|
||||
} catch { /* ignore */ }
|
||||
|
||||
// =====================================================================
|
||||
// FINAL: Log result
|
||||
|
|
|
|||
Loading…
Reference in a new issue