From 2d9526d2610fe88ab0d367946469bb531373697d Mon Sep 17 00:00:00 2001 From: bbbugg Date: Fri, 23 Jan 2026 23:58:56 +0800 Subject: [PATCH 1/3] refactor: enhance popup detection with intelligent polling mechanism --- src/core/BrowserManager.js | 101 ++++++++++++++++++++++++++----------- 1 file changed, 71 insertions(+), 30 deletions(-) diff --git a/src/core/BrowserManager.js b/src/core/BrowserManager.js index 25029b5..8f44940 100644 --- a/src/core/BrowserManager.js +++ b/src/core/BrowserManager.js @@ -841,39 +841,80 @@ class BrowserManager { throw new Error("🚨 Page load failed (about:blank), possibly network timeout or browser crash."); } - // Handle various popups - this.logger.info(`[Browser] Checking for Cookie consent banner...`); - try { - const agreeButton = this.page.locator('button:text("Agree")'); - if (await agreeButton.isVisible({ timeout: 5000 })) { - await this.page.waitForTimeout(500 + Math.random() * 1000); - this.logger.info(`[Browser] ✅ Found Cookie consent banner, clicking "Agree"...`); - await agreeButton.click({ force: true }); + // Handle various popups with intelligent detection + // Use short polling instead of long hard-coded timeouts + this.logger.info(`[Browser] 🔍 Starting intelligent popup detection (max 5s)...`); + + const popupConfigs = [ + { + logFound: `[Browser] ✅ Found Cookie consent banner, clicking "Agree"...`, + name: "Cookie consent", + selector: 'button:text("Agree")', + }, + { + logFound: `[Browser] ✅ Found "Got it" popup, clicking...`, + name: "Got it dialog", + selector: 'div.dialog button:text("Got it")', + }, + { + logFound: `[Browser] ✅ Found onboarding tutorial popup, clicking close button...`, + name: "Onboarding tutorial", + selector: 'button[aria-label="Close"]', + }, + ]; + + // Polling-based detection with smart exit conditions + // - Initial wait: give popups time to render after page load + // - Consecutive idle tracking: exit after N consecutive iterations with no new popups + const maxIterations = 12; // Max polling iterations + const pollInterval = 500; // Interval between polls (ms) + const minIterations = 4; // Min iterations (2s), ensure slow popups have time to load + const idleThreshold = 2; // Exit after N consecutive iterations with no new popups + const handledPopups = new Set(); + let consecutiveIdleCount = 0; // Counter for consecutive idle iterations + + for (let i = 0; i < maxIterations; i++) { + let foundAny = false; + + for (const popup of popupConfigs) { + if (handledPopups.has(popup.name)) continue; + + try { + const element = this.page.locator(popup.selector).first(); + // Quick visibility check with very short timeout + if (await element.isVisible({ timeout: 100 })) { + this.logger.info(popup.logFound); + await element.click({ force: true }); + handledPopups.add(popup.name); + foundAny = true; + // Short pause after clicking to let next popup appear + await this.page.waitForTimeout(300); + } + } catch { + // Element not visible or doesn't exist, continue + } } - } catch (error) { - this.logger.info(`[Browser] No Cookie consent banner found, skipping.`); - } - this.logger.info(`[Browser] Checking for "Got it" popup...`); - try { - const gotItButton = this.page.locator('div.dialog button:text("Got it")'); - await gotItButton.waitFor({ state: "visible", timeout: 15000 }); - this.logger.info(`[Browser] ✅ Found "Got it" popup, clicking...`); - await gotItButton.click({ force: true }); - await this.page.waitForTimeout(1000); - } catch (error) { - this.logger.info(`[Browser] No "Got it" popup found, skipping.`); - } + // Update consecutive idle counter + if (foundAny) { + consecutiveIdleCount = 0; // Found popup, reset counter + } else { + consecutiveIdleCount++; + } - this.logger.info(`[Browser] Checking for onboarding tutorial...`); - try { - const closeButton = this.page.locator('button[aria-label="Close"]'); - await closeButton.waitFor({ state: "visible", timeout: 15000 }); - this.logger.info(`[Browser] ✅ Found onboarding tutorial popup, clicking close button...`); - await closeButton.click({ force: true }); - await this.page.waitForTimeout(1000); - } catch (error) { - this.logger.info(`[Browser] No "It's time to build" onboarding tutorial found, skipping.`); + // Exit conditions: + // 1. Must have completed minimum iterations (ensure slow popups have time to load) + // 2. Consecutive idle count exceeds threshold (no new popups appearing) + if (i >= minIterations - 1 && consecutiveIdleCount >= idleThreshold) { + this.logger.info( + `[Browser] ✅ Popup detection complete (${i + 1} iterations, ${handledPopups.size} popups handled)` + ); + break; + } + + if (i < maxIterations - 1) { + await this.page.waitForTimeout(pollInterval); + } } this.logger.info("[Browser] Preparing UI interaction, forcefully removing all possible overlay layers..."); From 77dc108628b282fb5963081e00a6bb4dfae4cc51 Mon Sep 17 00:00:00 2001 From: bbbugg <80089841+bbbugg@users.noreply.github.com> Date: Fri, 23 Jan 2026 09:26:48 -0800 Subject: [PATCH 2/3] Update src/core/BrowserManager.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/core/BrowserManager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/BrowserManager.js b/src/core/BrowserManager.js index 8f44940..3a03c4f 100644 --- a/src/core/BrowserManager.js +++ b/src/core/BrowserManager.js @@ -843,7 +843,7 @@ class BrowserManager { // Handle various popups with intelligent detection // Use short polling instead of long hard-coded timeouts - this.logger.info(`[Browser] 🔍 Starting intelligent popup detection (max 5s)...`); + this.logger.info(`[Browser] 🔍 Starting intelligent popup detection (max 6s)...`); const popupConfigs = [ { From e225843dabe0ac4c2caceed0bf4dcf1027af6bf2 Mon Sep 17 00:00:00 2001 From: bbbugg Date: Sat, 24 Jan 2026 20:34:22 +0800 Subject: [PATCH 3/3] refactor: improve popup handling logic and error propagation in BrowserManager --- src/core/BrowserManager.js | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/core/BrowserManager.js b/src/core/BrowserManager.js index 3a03c4f..48c3a85 100644 --- a/src/core/BrowserManager.js +++ b/src/core/BrowserManager.js @@ -869,7 +869,7 @@ class BrowserManager { const maxIterations = 12; // Max polling iterations const pollInterval = 500; // Interval between polls (ms) const minIterations = 4; // Min iterations (2s), ensure slow popups have time to load - const idleThreshold = 2; // Exit after N consecutive iterations with no new popups + const idleThreshold = 3; // Exit after N consecutive iterations with no new popups const handledPopups = new Set(); let consecutiveIdleCount = 0; // Counter for consecutive idle iterations @@ -882,16 +882,33 @@ class BrowserManager { try { const element = this.page.locator(popup.selector).first(); // Quick visibility check with very short timeout - if (await element.isVisible({ timeout: 100 })) { + if (await element.isVisible({ timeout: 200 })) { this.logger.info(popup.logFound); await element.click({ force: true }); handledPopups.add(popup.name); foundAny = true; // Short pause after clicking to let next popup appear - await this.page.waitForTimeout(300); + await this.page.waitForTimeout(800); + } + } catch (error) { + // Element not visible or doesn't exist is expected here, + // but propagate clearly critical browser/page issues. + if (error && error.message) { + const msg = error.message; + if ( + msg.includes("Execution context was destroyed") || + msg.includes("Target page, context or browser has been closed") || + msg.includes("Protocol error") || + msg.includes("Navigation failed because page was closed") + ) { + throw error; + } + if (this.logger && typeof this.logger.debug === "function") { + this.logger.debug( + `[Browser] Ignored error while checking popup "${popup.name}": ${msg}` + ); + } } - } catch { - // Element not visible or doesn't exist, continue } }