debug: add forced screenshots at every auth-join step, disable mic toggle
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
dddf1cd970
commit
c93bce1b8b
1 changed files with 27 additions and 18 deletions
|
|
@ -220,13 +220,12 @@ export class BotOrchestrator {
|
||||||
this._setState('navigating');
|
this._setState('navigating');
|
||||||
|
|
||||||
// STEP 1: Navigate to teams.microsoft.com to trigger authentication
|
// STEP 1: Navigate to teams.microsoft.com to trigger authentication
|
||||||
this._logger.info('Auth join: navigating to teams.microsoft.com');
|
this._logger.info('STEP 1: navigating to teams.microsoft.com');
|
||||||
await this._page!.goto('https://teams.microsoft.com', {
|
await this._page!.goto('https://teams.microsoft.com', {
|
||||||
waitUntil: 'domcontentloaded',
|
waitUntil: 'domcontentloaded',
|
||||||
timeout: 30000,
|
timeout: 30000,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Poll for login page (redirect to login.microsoftonline.com)
|
|
||||||
const emailInput = await this._pollForElement(
|
const emailInput = await this._pollForElement(
|
||||||
['input[name="loginfmt"]', 'input[type="email"]'],
|
['input[name="loginfmt"]', 'input[type="email"]'],
|
||||||
30000,
|
30000,
|
||||||
|
|
@ -234,10 +233,11 @@ export class BotOrchestrator {
|
||||||
);
|
);
|
||||||
if (!emailInput) {
|
if (!emailInput) {
|
||||||
this._logger.warn(`No login page found, current URL: ${this._page!.url().substring(0, 150)}`);
|
this._logger.warn(`No login page found, current URL: ${this._page!.url().substring(0, 150)}`);
|
||||||
|
await this._takeScreenshot('step1-no-login-page', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 2: Microsoft Authentication
|
// STEP 2: Microsoft Authentication
|
||||||
this._logger.info(`Authenticating as ${this._options.botAccountEmail}`);
|
this._logger.info(`STEP 2: authenticating as ${this._options.botAccountEmail}`);
|
||||||
const authProcedure = new AuthProcedure(this._page!, this._logger);
|
const authProcedure = new AuthProcedure(this._page!, this._logger);
|
||||||
const authSuccess = await authProcedure.authenticateWithMicrosoft(
|
const authSuccess = await authProcedure.authenticateWithMicrosoft(
|
||||||
this._options.botAccountEmail!,
|
this._options.botAccountEmail!,
|
||||||
|
|
@ -246,12 +246,14 @@ export class BotOrchestrator {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!authSuccess) {
|
if (!authSuccess) {
|
||||||
|
await this._takeScreenshot('step2-auth-failed', true);
|
||||||
throw new Error('Microsoft authentication failed');
|
throw new Error('Microsoft authentication failed');
|
||||||
}
|
}
|
||||||
this._logger.info('Authentication successful');
|
this._logger.info('STEP 2: authentication successful');
|
||||||
|
await this._takeScreenshot('step2-auth-done', true);
|
||||||
|
|
||||||
// STEP 3: Wait for Teams to finish loading after auth
|
// STEP 3: Wait for Teams to load after auth
|
||||||
this._logger.info('Waiting for Teams to load after auth...');
|
this._logger.info('STEP 3: waiting for Teams to load after auth...');
|
||||||
try {
|
try {
|
||||||
await this._page!.waitForURL(
|
await this._page!.waitForURL(
|
||||||
(url) => url.hostname.includes('teams.microsoft.com') || url.hostname.includes('teams.cloud.microsoft'),
|
(url) => url.hostname.includes('teams.microsoft.com') || url.hostname.includes('teams.cloud.microsoft'),
|
||||||
|
|
@ -260,16 +262,18 @@ export class BotOrchestrator {
|
||||||
} catch {
|
} catch {
|
||||||
this._logger.warn(`Unexpected URL after auth: ${this._page!.url().substring(0, 150)}`);
|
this._logger.warn(`Unexpected URL after auth: ${this._page!.url().substring(0, 150)}`);
|
||||||
}
|
}
|
||||||
|
await this._takeScreenshot('step3-teams-loaded', true);
|
||||||
|
|
||||||
// STEP 4: Navigate to the meeting URL
|
// STEP 4: Navigate to the meeting URL
|
||||||
this._logger.info(`Auth join: navigating to meeting URL: ${this._meetingUrl.substring(0, 80)}...`);
|
this._logger.info(`STEP 4: navigating to meeting URL: ${this._meetingUrl.substring(0, 80)}...`);
|
||||||
await this._page!.goto(this._meetingUrl, {
|
await this._page!.goto(this._meetingUrl, {
|
||||||
waitUntil: 'domcontentloaded',
|
waitUntil: 'domcontentloaded',
|
||||||
timeout: 30000,
|
timeout: 30000,
|
||||||
});
|
});
|
||||||
this._logger.info(`Auth join: URL after navigation: ${this._page!.url().substring(0, 150)}`);
|
this._logger.info(`STEP 4: URL after navigation: ${this._page!.url().substring(0, 150)}`);
|
||||||
|
await this._takeScreenshot('step4-meeting-url-loaded', true);
|
||||||
|
|
||||||
// STEP 4a: Poll for the first actionable button (interstitial OR pre-join)
|
// STEP 4a: Poll for first actionable button (interstitial OR pre-join)
|
||||||
const interstitialSelectors = [
|
const interstitialSelectors = [
|
||||||
'button:has-text("Continue on this browser")',
|
'button:has-text("Continue on this browser")',
|
||||||
'button:has-text("In diesem Browser fortfahren")',
|
'button:has-text("In diesem Browser fortfahren")',
|
||||||
|
|
@ -299,28 +303,33 @@ export class BotOrchestrator {
|
||||||
|
|
||||||
if (!isPreJoin) {
|
if (!isPreJoin) {
|
||||||
await firstBtn.click();
|
await firstBtn.click();
|
||||||
this._logger.info(`Clicked interstitial: "${btnText}"`);
|
this._logger.info(`STEP 4a: clicked interstitial: "${btnText}"`);
|
||||||
|
await this._takeScreenshot('step4a-after-interstitial', true);
|
||||||
|
} else {
|
||||||
|
this._logger.info(`STEP 4a: pre-join button already visible: "${btnText}"`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await this._takeScreenshot('auth-no-buttons');
|
await this._takeScreenshot('step4a-no-buttons-found', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 5: Poll for "Join now" on the pre-join screen
|
// STEP 5: Poll for "Join now" on the pre-join screen (mic is NOT touched)
|
||||||
await this._ensureMicOn();
|
await this._takeScreenshot('step5-before-join-now', true);
|
||||||
|
|
||||||
const joinNowBtn = await this._pollForElement(preJoinSelectors, 30000, 'Join now button');
|
const joinNowBtn = await this._pollForElement(preJoinSelectors, 30000, 'Join now button');
|
||||||
if (!joinNowBtn) {
|
if (!joinNowBtn) {
|
||||||
await this._takeScreenshot('auth-no-join-now');
|
await this._takeScreenshot('step5-no-join-now', true);
|
||||||
throw new Error('"Join now" button not found on pre-join screen');
|
throw new Error('"Join now" button not found on pre-join screen');
|
||||||
}
|
}
|
||||||
await joinNowBtn.click();
|
await joinNowBtn.click();
|
||||||
this._logger.info('Clicked "Join now", waiting for meeting');
|
this._logger.info('STEP 5: clicked "Join now", waiting for meeting');
|
||||||
|
await this._takeScreenshot('step5-join-now-clicked', true);
|
||||||
|
|
||||||
// STEP 6: Wait for meeting admission (hangup button = in meeting)
|
// STEP 6: Wait for meeting admission (hangup button = in meeting)
|
||||||
await this._waitForMeetingAdmission();
|
await this._waitForMeetingAdmission();
|
||||||
|
|
||||||
this._setState('in_meeting');
|
this._setState('in_meeting');
|
||||||
this._logger.info(`Bot joined the meeting (authenticated as ${this._options.botAccountEmail})`);
|
this._logger.info(`STEP 6: bot joined the meeting (authenticated as ${this._options.botAccountEmail})`);
|
||||||
|
await this._takeScreenshot('step6-in-meeting', true);
|
||||||
|
|
||||||
this._startKeepAlive();
|
this._startKeepAlive();
|
||||||
await this._audioProcedure!.initialize();
|
await this._audioProcedure!.initialize();
|
||||||
|
|
@ -1183,8 +1192,8 @@ export class BotOrchestrator {
|
||||||
* Take a screenshot for debugging.
|
* Take a screenshot for debugging.
|
||||||
* Logs screenshot as base64 for easy viewing from Azure logs.
|
* Logs screenshot as base64 for easy viewing from Azure logs.
|
||||||
*/
|
*/
|
||||||
private async _takeScreenshot(name: string): Promise<void> {
|
private async _takeScreenshot(name: string, force: boolean = false): Promise<void> {
|
||||||
if (!config.screenshotOnError || !this._page) {
|
if ((!config.screenshotOnError && !force) || !this._page) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue