fix: wait for Teams login redirect + universal auth selectors
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
3724e31a30
commit
08194fe241
2 changed files with 50 additions and 60 deletions
|
|
@ -121,22 +121,20 @@ export class AuthProcedure {
|
|||
/**
|
||||
* Wait for the email input field.
|
||||
*
|
||||
* Hybrid flow: Teams inline modal has input#emailOrPhonerm [data-testid="emailInput"]
|
||||
* Direct flow: MS login portal has input[name="loginfmt"]
|
||||
* Uses universal selectors that work on both:
|
||||
* - MS login portal (login.microsoftonline.com): input[name="loginfmt"]
|
||||
* - Teams inline modal (light-meetings): input#emailOrPhonerm
|
||||
*/
|
||||
private async _waitForEmailInput(isInlineFlow: boolean) {
|
||||
private async _waitForEmailInput(_isInlineFlow: boolean) {
|
||||
this._logger.info('Waiting for email input field...');
|
||||
|
||||
// Primary selectors — exact IDs/attributes from the real HTML
|
||||
const selectors = isInlineFlow
|
||||
? [
|
||||
// Universal selectors — match both MS login portal and Teams inline modal
|
||||
const selectors = [
|
||||
'input[name="loginfmt"]', // MS login portal (primary)
|
||||
'input[type="email"]', // MS login portal fallback
|
||||
'input#emailOrPhonerm', // Teams inline modal (exact ID)
|
||||
'input[data-testid="emailInput"]', // Teams inline modal (data-testid)
|
||||
'input[placeholder="Enter your email"]', // Teams inline modal (placeholder)
|
||||
]
|
||||
: [
|
||||
'input[name="loginfmt"]', // MS login portal
|
||||
'input[type="email"]', // MS login portal fallback
|
||||
];
|
||||
|
||||
const combinedSelector = selectors.join(', ');
|
||||
|
|
@ -161,53 +159,37 @@ export class AuthProcedure {
|
|||
/**
|
||||
* Click the "Next" button after entering email.
|
||||
*
|
||||
* Hybrid flow: button[data-testid="authLoginDialogNextButton"] — initially disabled,
|
||||
* becomes enabled after email is typed. We wait for it to be enabled.
|
||||
* Direct flow: input[type="submit"] on the MS login portal.
|
||||
* Tries all known button selectors from both MS login portal and Teams inline modal.
|
||||
* Works regardless of which page we're on.
|
||||
*/
|
||||
private async _clickNextButton(isInlineFlow: boolean): Promise<void> {
|
||||
if (isInlineFlow) {
|
||||
// Teams inline modal: wait for the Next button to become enabled
|
||||
const nextSelector = 'button[data-testid="authLoginDialogNextButton"]';
|
||||
this._logger.info('Waiting for Teams Next button to become enabled...');
|
||||
try {
|
||||
await this._page.waitForSelector(`${nextSelector}:not([disabled])`, {
|
||||
timeout: 10000,
|
||||
state: 'visible',
|
||||
});
|
||||
await this._page.click(nextSelector);
|
||||
this._logger.info('Clicked Teams Next button');
|
||||
// After clicking Next, Teams redirects to login.microsoftonline.com
|
||||
// Wait for the redirect to begin
|
||||
await this._page.waitForTimeout(3000);
|
||||
} catch {
|
||||
this._logger.warn('Teams Next button not found or not enabled, pressing Enter');
|
||||
await this._page.keyboard.press('Enter');
|
||||
await this._page.waitForTimeout(3000);
|
||||
}
|
||||
} else {
|
||||
// MS login portal: click submit button
|
||||
private async _clickNextButton(_isInlineFlow: boolean): Promise<void> {
|
||||
// Try all known Next/Submit button selectors (MS login portal + Teams inline modal)
|
||||
const selectors = [
|
||||
'input[type="submit"]',
|
||||
'button[type="submit"]',
|
||||
'input[type="submit"]', // MS login portal
|
||||
'button[type="submit"]', // MS login portal alt
|
||||
'button[data-testid="authLoginDialogNextButton"]', // Teams inline modal
|
||||
];
|
||||
|
||||
for (const selector of selectors) {
|
||||
try {
|
||||
const button = await this._page.$(selector);
|
||||
if (button && await button.isVisible()) {
|
||||
const button = await this._page.waitForSelector(selector, {
|
||||
timeout: 5000,
|
||||
state: 'visible',
|
||||
});
|
||||
if (button) {
|
||||
await button.click();
|
||||
this._logger.info(`Clicked Next: ${selector}`);
|
||||
await this._page.waitForTimeout(2000);
|
||||
await this._page.waitForTimeout(3000);
|
||||
return;
|
||||
}
|
||||
} catch {
|
||||
// Continue
|
||||
// Selector not found, try next
|
||||
}
|
||||
}
|
||||
this._logger.warn('No Next button found, pressing Enter');
|
||||
|
||||
this._logger.warn('No Next button found via selectors, pressing Enter');
|
||||
await this._page.keyboard.press('Enter');
|
||||
await this._page.waitForTimeout(2000);
|
||||
}
|
||||
await this._page.waitForTimeout(3000);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -195,18 +195,26 @@ async function _runVariant(
|
|||
waitUntil: 'domcontentloaded',
|
||||
timeout: 30000,
|
||||
});
|
||||
await page.waitForTimeout(3000);
|
||||
_log('info', `After Teams redirect: ${page.url().substring(0, 120)}`);
|
||||
|
||||
// Wait for Teams to redirect to login.microsoftonline.com (up to 30s)
|
||||
_log('info', 'Waiting for login redirect to login.microsoftonline.com...');
|
||||
try {
|
||||
await page.waitForURL('**/login.microsoftonline.com/**', { timeout: 30000 });
|
||||
_log('info', `Redirected to login: ${page.url().substring(0, 150)}`);
|
||||
} catch {
|
||||
_log('warn', `No login redirect after 30s, current URL: ${page.url().substring(0, 150)}`);
|
||||
}
|
||||
|
||||
// Step 2: Login
|
||||
if (botAccountEmail && botAccountPassword) {
|
||||
authAttempted = true;
|
||||
const onLoginPage = page.url().includes('login.microsoftonline.com') || page.url().includes('login.live.com');
|
||||
_log('info', `On login page: ${onLoginPage}, authenticating as ${botAccountEmail}`);
|
||||
_log('info', `Authenticating as ${botAccountEmail} (skipNavigation=true to preserve OAuth context)`);
|
||||
|
||||
const authProcedure = new AuthProcedure(page, logger);
|
||||
// skipNavigation=true because we're already on the login page after teams.microsoft.com redirect
|
||||
authSuccess = await authProcedure.authenticateWithMicrosoft(botAccountEmail, botAccountPassword, !onLoginPage);
|
||||
// Always skipNavigation=true: we're already on login.microsoftonline.com with the correct
|
||||
// OAuth parameters (client_id, redirect_uri for Teams). Navigating to plain
|
||||
// login.microsoftonline.com would lose this context.
|
||||
authSuccess = await authProcedure.authenticateWithMicrosoft(botAccountEmail, botAccountPassword, true);
|
||||
_log(authSuccess ? 'info' : 'warn', `Auth result: ${authSuccess ? 'success' : 'failed'}`);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue