From fe3071877257084ee414c7471e190e4d8365b853 Mon Sep 17 00:00:00 2001 From: Peter Hedenskog Date: Fri, 1 May 2026 08:05:20 +0200 Subject: [PATCH] Add Chrome settings to the result JSON Issue #1622. $ Co-authored-by: Claude Opus 4.7 (1M context) noreply@anthropic.com Change-Id: Icb65cfb9f6f4add225d2344d98f5ec39b3d13023 --- lib/chrome/webdriver/setupChromiumOptions.js | 91 ++++++++++++-------- lib/core/engine/index.js | 21 ++++- 2 files changed, 75 insertions(+), 37 deletions(-) diff --git a/lib/chrome/webdriver/setupChromiumOptions.js b/lib/chrome/webdriver/setupChromiumOptions.js index 617263955..1cc93c38c 100644 --- a/lib/chrome/webdriver/setupChromiumOptions.js +++ b/lib/chrome/webdriver/setupChromiumOptions.js @@ -45,10 +45,36 @@ export function setupChromiumOptions( options, baseDir ) { + // Record every argument / preference / capability we apply to the browser + // so it can be surfaced in the result JSON for debugging — issue #1622. + // Stored on `options` because both Chrome and Edge call this and both end + // up needing it later in the engine for `result.info.browser`. + const recorded = { + args: [], + preferences: {}, + mobileEmulation: undefined, + binaryPath: undefined, + extensions: 0 + }; + options.recordedBrowserSettings = recorded; + + const addArgs = arg => { + seleniumOptions.addArguments(arg); + if (Array.isArray(arg)) { + recorded.args.push(...arg); + } else { + recorded.args.push(arg); + } + }; + const setPrefs = prefs => { + seleniumOptions.setUserPreferences(prefs); + Object.assign(recorded.preferences, prefs); + }; + // Fixing save password popup, only on Desktop if (!isAndroidConfigured(options)) { - seleniumOptions.setUserPreferences({ + setPrefs({ 'profile.password_manager_enable': false, 'profile.default_content_setting_values.notifications': 2, credentials_enable_service: false @@ -56,32 +82,28 @@ export function setupChromiumOptions( } if (options.headless) { - seleniumOptions.addArguments('--headless=new'); + addArgs('--headless=new'); } // If we run in Docker we need to always use no-sandbox if (options.docker) { - seleniumOptions.addArguments('--no-sandbox'); - seleniumOptions.addArguments('--disable-setuid-sandbox'); + addArgs('--no-sandbox'); + addArgs('--disable-setuid-sandbox'); } if (options.xvfb && (options.xvfb === true || options.xvfb === 'true')) { - seleniumOptions.addArguments('--disable-gpu'); + addArgs('--disable-gpu'); } - seleniumOptions.addArguments( - '--disable-features=' + CHROME_FEATURES_THAT_WE_DISABLES.join(',') - ); + addArgs('--disable-features=' + CHROME_FEATURES_THAT_WE_DISABLES.join(',')); - seleniumOptions.addArguments( - '--enable-features=' + CHROME_FEATURES_THAT_WE_ENABLE.join(',') - ); + addArgs('--enable-features=' + CHROME_FEATURES_THAT_WE_ENABLE.join(',')); const viewPort = getViewPort(options); // If viewport is defined (only on desktop) then set start args if (viewPort) { - seleniumOptions.addArguments('--window-position=0,0'); - seleniumOptions.addArguments('--window-size=' + viewPort.replace('x', ',')); + addArgs('--window-position=0,0'); + addArgs('--window-size=' + viewPort.replace('x', ',')); // Desktop Chrome enforces a minimum window width (~500px) regardless of // --window-size, so a request like --viewPort 360x640 silently becomes @@ -120,10 +142,10 @@ export function setupChromiumOptions( } excludes += ' EXCLUDE localhost'; - seleniumOptions.addArguments('--host-resolver-rules=' + excludes); + addArgs('--host-resolver-rules=' + excludes); } // If we are replaying with WebPageReplay else if (browserOptions.webPageReplayHostResolver) { - seleniumOptions.addArguments( + addArgs( `--host-resolver-rules= "MAP *:80 127.0.0.1:${browserOptions.webPageReplayHTTPPort}, MAP *:443 127.0.0.1:${browserOptions.webPageReplayHTTPSPort}, EXCLUDE localhost"` ); } // If we do not use WebPageReplay but wanna block on domain @@ -133,7 +155,7 @@ export function setupChromiumOptions( for (let domain of excludesDomains) { excludes += 'MAP * 127.0.0.1, EXCLUDE ' + domain + ','; } - seleniumOptions.addArguments('--host-resolver-rules=' + excludes); + addArgs('--host-resolver-rules=' + excludes); } else { // Make sure we only set this if we do not have any other host resolver rules const chromeCommandLineArguments = toArray(browserOptions.args); @@ -141,7 +163,7 @@ export function setupChromiumOptions( argument => argument.includes('host-resolver-rules') ); if (argumentsWithHostResolverRules.length === 0) { - seleniumOptions.addArguments( + addArgs( `--host-resolver-rules="${CHROME_AMD_EDGE_INTERNAL_PHONE_HOME.join( ',' )}"` @@ -157,51 +179,48 @@ export function setupChromiumOptions( seleniumOptions.addExtensions( readFileSync(extension, { encoding: 'base64' }) ); + recorded.extensions += 1; } } if (options.debug) { - seleniumOptions.addArguments('--auto-open-devtools-for-tabs'); + addArgs('--auto-open-devtools-for-tabs'); } const perfLogConfig = { enableNetwork: true, enablePage: true }; seleniumOptions.setPerfLoggingPrefs(perfLogConfig); if (options.userAgent) { - seleniumOptions.addArguments('--user-agent=' + options.userAgent); + addArgs('--user-agent=' + options.userAgent); } if (browserOptions.ignoreCertificateErrors) { - seleniumOptions.addArguments('--ignore-certificate-errors'); + addArgs('--ignore-certificate-errors'); } if (browserOptions.collectNetLog) { const dir = isAndroidConfigured(browserOptions) ? '/data/local/tmp' : baseDir; - seleniumOptions.addArguments(`--log-net-log=${dir}/chromeNetlog.json`); + addArgs(`--log-net-log=${dir}/chromeNetlog.json`); const level = browserOptions.netLogCaptureMode || 'IncludeSensitive'; - seleniumOptions.addArguments(`--net-log-capture-mode=${level}`); + addArgs(`--net-log-capture-mode=${level}`); } if (browserOptions.android) { - seleniumOptions.addArguments(defaultAndroidChromeOptions); - seleniumOptions.addArguments( - '--remote-debugging-port=' + options.devToolsPort - ); + addArgs(defaultAndroidChromeOptions); + addArgs('--remote-debugging-port=' + options.devToolsPort); } else { if (browserOptions.noDefaultOptions) { log.info('Skip setting default options for Chrome'); } else { - seleniumOptions.addArguments(defaultChromeOptions); - seleniumOptions.addArguments( - '--remote-debugging-port=' + options.devToolsPort - ); + addArgs(defaultChromeOptions); + addArgs('--remote-debugging-port=' + options.devToolsPort); } } if (browserOptions.enableVideoAutoplay) { - seleniumOptions.addArguments('--autoplay-policy=no-user-gesture-required'); + addArgs('--autoplay-policy=no-user-gesture-required'); } // It's a new splash screen introduced in Chrome 98 @@ -214,29 +233,31 @@ export function setupChromiumOptions( argument.includes('disable-features') && !argument.includes('ChromeWhatsNewUI') ) { - seleniumOptions.addArguments(`${argument},ChromeWhatsNewUI`); + addArgs(`${argument},ChromeWhatsNewUI`); log.debug('Set Chrome args %j', `${argument},ChromeWhatsNewUI`); } else if ( argument.includes('enable-features') && !argument.includes('SoftNavigationHeuristics') ) { - seleniumOptions.addArguments(`${argument},SoftNavigationHeuristics`); + addArgs(`${argument},SoftNavigationHeuristics`); log.debug('Set Chrome args %j', `${argument},SoftNavigationHeuristics`); } else { - seleniumOptions.addArguments(argument); + addArgs(argument); log.debug('Set Chrome args %j', argument); } } } else { - seleniumOptions.addArguments('--disable-features=ChromeWhatsNewUI'); + addArgs('--disable-features=ChromeWhatsNewUI'); } if (browserOptions.binaryPath) { seleniumOptions.setChromeBinaryPath(browserOptions.binaryPath); + recorded.binaryPath = browserOptions.binaryPath; } if (browserOptions.mobileEmulation) { seleniumOptions.setMobileEmulation(browserOptions.mobileEmulation); + recorded.mobileEmulation = browserOptions.mobileEmulation; } // See https://bugs.chromium.org/p/chromium/issues/detail?id=818483 diff --git a/lib/core/engine/index.js b/lib/core/engine/index.js index cec75ba8c..2026bf5e0 100644 --- a/lib/core/engine/index.js +++ b/lib/core/engine/index.js @@ -414,8 +414,25 @@ export class Engine { result.info.browser.geckProfilerFeatures = options.firefox.geckoProfilerParams.features; } - } else if (options.browser === 'chrome') { - if (options.chrome) { + } else if (options.browser === 'chrome' || options.browser === 'edge') { + // Issue #1622 — surface the full set of args/preferences/etc that + // browsertime applied to the browser, not just what the user passed + // via --chrome.args. Captured by setupChromiumOptions; see + // lib/chrome/webdriver/setupChromiumOptions.js. + if (options.recordedBrowserSettings) { + const recorded = options.recordedBrowserSettings; + result.info.browser.args = recorded.args; + result.info.browser.preferences = recorded.preferences; + if (recorded.mobileEmulation) { + result.info.browser.mobileEmulation = recorded.mobileEmulation; + } + if (recorded.binaryPath) { + result.info.browser.binaryPath = recorded.binaryPath; + } + if (recorded.extensions > 0) { + result.info.browser.extensions = recorded.extensions; + } + } else if (options.chrome) { result.info.browser.args = options.chrome.args; } if (