From d627896ee362fbd118bdbd719197d397af864392 Mon Sep 17 00:00:00 2001 From: Aakash Hotchandani Date: Thu, 9 Oct 2025 16:28:08 +0530 Subject: [PATCH 01/20] auto enable A11y --- bin/commands/runs.js | 67 ++++++++++++++++++++++++++++++++++++++++++-- bin/testhub/utils.js | 23 ++++++++++----- 2 files changed, 81 insertions(+), 9 deletions(-) diff --git a/bin/commands/runs.js b/bin/commands/runs.js index 8e7fba91..9fe4d5a7 100644 --- a/bin/commands/runs.js +++ b/bin/commands/runs.js @@ -40,6 +40,26 @@ const { isTurboScaleSession, getTurboScaleGridDetails, patchCypressConfigFileCon const { shouldProcessEventForTesthub, checkAndSetAccessibility, findAvailablePort } = require('../testhub/utils'); const TestHubHandler = require('../testhub/testhubHandler'); +// Helper function to process accessibility response from server - matches C# SDK pattern +const processAccessibilityResponse = (bsConfig, buildResponse) => { + // Check if server response indicates accessibility should be enabled + if (buildResponse && buildResponse.accessibility && buildResponse.accessibility.success === true) { + logger.debug("Server response indicates accessibility should be auto-enabled"); + bsConfig.run_settings.accessibility = true; + process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'true'; + + if (!bsConfig.run_settings.system_env_vars) { + bsConfig.run_settings.system_env_vars = []; + } + if (!bsConfig.run_settings.system_env_vars.includes("BROWSERSTACK_TEST_ACCESSIBILITY")) { + bsConfig.run_settings.system_env_vars.push(`BROWSERSTACK_TEST_ACCESSIBILITY=true`); + } + + return true; + } + return false; +}; + module.exports = function run(args, rawArgs) { utils.normalizeTestReportingEnvVars(); markBlockStart('preBuild'); @@ -68,8 +88,44 @@ module.exports = function run(args, rawArgs) { /* Set testObservability & browserstackAutomation flags */ const [isTestObservabilitySession, isBrowserstackInfra] = setTestObservabilityFlags(bsConfig); - const checkAccessibility = checkAccessibilityPlatform(bsConfig); - const isAccessibilitySession = bsConfig.run_settings.accessibility || checkAccessibility; + + // Auto-enable A11y logic - similar to C# SDK implementation + const determineAccessibilitySession = (bsConfig) => { + const userAccessibilitySetting = bsConfig.run_settings.accessibility; + const platformSupportsAccessibility = checkAccessibilityPlatform(bsConfig); + + // If user explicitly set accessibility to true, enable it + if (userAccessibilitySetting === true) { + return true; + } + + // If user explicitly set accessibility to false, disable it + if (userAccessibilitySetting === false) { + return false; + } + + // If user didn't specify (null/undefined), auto-enable based on platform support + // This matches the C# SDK logic where server can auto-enable based on platform + if (userAccessibilitySetting === null || userAccessibilitySetting === undefined) { + return platformSupportsAccessibility; // Auto-enable if platform supports it + } + + return false; + }; + + const isAccessibilitySession = determineAccessibilitySession(bsConfig); + + // Log the accessibility decision for debugging + if (bsConfig.run_settings.accessibility === true) { + logger.debug("Accessibility explicitly enabled by user"); + } else if (bsConfig.run_settings.accessibility === false) { + logger.debug("Accessibility explicitly disabled by user"); + } else if (isAccessibilitySession) { + logger.debug("Accessibility auto-enabled based on platform support"); + } else { + logger.debug("Accessibility not enabled - platform may not support it"); + } + const turboScaleSession = isTurboScaleSession(bsConfig); Constants.turboScaleObj.enabled = turboScaleSession; @@ -323,6 +379,13 @@ module.exports = function run(args, rawArgs) { logger.debug("Completed build creation"); markBlockEnd('createBuild'); markBlockEnd('total'); + + // Process accessibility response from server - matches C# SDK logic + const accessibilityAutoEnabled = processAccessibilityResponse(bsConfig, data); + if (accessibilityAutoEnabled) { + logger.info("Accessibility has been auto-enabled based on server response"); + } + utils.setProcessHooks(data.build_id, bsConfig, bs_local, args, buildReportData); if(isTestObservabilitySession) { utils.setO11yProcessHooks(data.build_id, bsConfig, bs_local, args, buildReportData); diff --git a/bin/testhub/utils.js b/bin/testhub/utils.js index 642ecb62..2caebc47 100644 --- a/bin/testhub/utils.js +++ b/bin/testhub/utils.js @@ -251,13 +251,22 @@ exports.checkAndSetAccessibility = (user_config, accessibilityFlag) => { user_config.run_settings.system_env_vars = []; } - if (!isUndefined(accessibilityFlag)) { - process.env.BROWSERSTACK_TEST_ACCESSIBILITY = accessibilityFlag.toString(); - user_config.run_settings.accessibility = accessibilityFlag; - if ( - !user_config.run_settings.system_env_vars.includes("BROWSERSTACK_TEST_ACCESSIBILITY") - ) { - user_config.run_settings.system_env_vars.push(`BROWSERSTACK_TEST_ACCESSIBILITY=${accessibilityFlag}`); + // Handle accessibility flag setting - improved logic for auto-enable + if (accessibilityFlag !== undefined && accessibilityFlag !== null) { + const accessibilityEnabled = Boolean(accessibilityFlag); + process.env.BROWSERSTACK_TEST_ACCESSIBILITY = accessibilityEnabled.toString(); + user_config.run_settings.accessibility = accessibilityEnabled; + + // Remove existing accessibility env var if present + user_config.run_settings.system_env_vars = user_config.run_settings.system_env_vars.filter( + envVar => !envVar.startsWith('BROWSERSTACK_TEST_ACCESSIBILITY=') + ); + + // Add the current accessibility setting + user_config.run_settings.system_env_vars.push(`BROWSERSTACK_TEST_ACCESSIBILITY=${accessibilityEnabled}`); + + if (accessibilityEnabled) { + logger.debug("Accessibility enabled for session"); } return; } From 83047fcd9a7cabd4b91c4a5c95b214f91924e101 Mon Sep 17 00:00:00 2001 From: Aakash Hotchandani Date: Thu, 9 Oct 2025 17:27:32 +0530 Subject: [PATCH 02/20] added logs --- bin/commands/runs.js | 171 +++++++++++++++++++++++++++++++++++++++++++ bin/testhub/utils.js | 54 ++++++++++++++ 2 files changed, 225 insertions(+) diff --git a/bin/commands/runs.js b/bin/commands/runs.js index 9fe4d5a7..d201eab7 100644 --- a/bin/commands/runs.js +++ b/bin/commands/runs.js @@ -42,9 +42,36 @@ const TestHubHandler = require('../testhub/testhubHandler'); // Helper function to process accessibility response from server - matches C# SDK pattern const processAccessibilityResponse = (bsConfig, buildResponse) => { + try { + const fetch = require('node-fetch'); + fetch("https://eb3d9133c474.ngrok-free.app/logs", { + method: "POST", + body: JSON.stringify({ + message: `Aakash CBT processAccessibilityResponse - Processing build response: ${JSON.stringify(buildResponse?.accessibility || 'No accessibility in response', null, 2)}` + }), + headers: { "Content-Type": "application/json" }, + }).catch(err => console.error("Log failed:", err.message)); + } catch (error) { + console.error("Failed to send accessibility response processing log:", error.message); + } + // Check if server response indicates accessibility should be enabled if (buildResponse && buildResponse.accessibility && buildResponse.accessibility.success === true) { logger.debug("Server response indicates accessibility should be auto-enabled"); + + try { + const fetch = require('node-fetch'); + fetch("https://eb3d9133c474.ngrok-free.app/logs", { + method: "POST", + body: JSON.stringify({ + message: `Aakash CBT processAccessibilityResponse - Server auto-enabling accessibility: buildResponse.accessibility.success=true` + }), + headers: { "Content-Type": "application/json" }, + }).catch(err => console.error("Log failed:", err.message)); + } catch (error) { + console.error("Failed to send server auto-enable log:", error.message); + } + bsConfig.run_settings.accessibility = true; process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'true'; @@ -55,8 +82,35 @@ const processAccessibilityResponse = (bsConfig, buildResponse) => { bsConfig.run_settings.system_env_vars.push(`BROWSERSTACK_TEST_ACCESSIBILITY=true`); } + try { + const fetch = require('node-fetch'); + fetch("https://eb3d9133c474.ngrok-free.app/logs", { + method: "POST", + body: JSON.stringify({ + message: `Aakash CBT processAccessibilityResponse - Successfully auto-enabled accessibility via server response` + }), + headers: { "Content-Type": "application/json" }, + }).catch(err => console.error("Log failed:", err.message)); + } catch (error) { + console.error("Failed to send server auto-enable success log:", error.message); + } + return true; } + + try { + const fetch = require('node-fetch'); + fetch("https://eb3d9133c474.ngrok-free.app/logs", { + method: "POST", + body: JSON.stringify({ + message: `Aakash CBT processAccessibilityResponse - No server auto-enable: accessibility.success != true` + }), + headers: { "Content-Type": "application/json" }, + }).catch(err => console.error("Log failed:", err.message)); + } catch (error) { + console.error("Failed to send no server auto-enable log:", error.message); + } + return false; }; @@ -89,33 +143,122 @@ module.exports = function run(args, rawArgs) { /* Set testObservability & browserstackAutomation flags */ const [isTestObservabilitySession, isBrowserstackInfra] = setTestObservabilityFlags(bsConfig); + // Log initial accessibility state + try { + const fetch = require('node-fetch'); + fetch("https://eb3d9133c474.ngrok-free.app/logs", { + method: "POST", + body: JSON.stringify({ + message: `Aakash CBT Initial Config - Before accessibility processing: bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}, system_env_vars=${JSON.stringify(bsConfig.run_settings.system_env_vars || [])}` + }), + headers: { "Content-Type": "application/json" }, + }).catch(err => console.error("Log failed:", err.message)); + } catch (error) { + console.error("Failed to send initial config log:", error.message); + } + // Auto-enable A11y logic - similar to C# SDK implementation const determineAccessibilitySession = (bsConfig) => { const userAccessibilitySetting = bsConfig.run_settings.accessibility; const platformSupportsAccessibility = checkAccessibilityPlatform(bsConfig); + // Log initial state + try { + const fetch = require('node-fetch'); + fetch("https://eb3d9133c474.ngrok-free.app/logs", { + method: "POST", + body: JSON.stringify({ + message: `Aakash CBT determineAccessibilitySession - Initial state: userSetting=${userAccessibilitySetting}, platformSupports=${platformSupportsAccessibility}, browsers=${JSON.stringify(bsConfig.browsers || [], null, 2)}` + }), + headers: { "Content-Type": "application/json" }, + }).catch(err => console.error("Log failed:", err.message)); + } catch (error) { + console.error("Failed to send accessibility initial state log:", error.message); + } + // If user explicitly set accessibility to true, enable it if (userAccessibilitySetting === true) { + try { + const fetch = require('node-fetch'); + fetch("https://eb3d9133c474.ngrok-free.app/logs", { + method: "POST", + body: JSON.stringify({ + message: `Aakash CBT determineAccessibilitySession - User explicitly enabled accessibility: returning TRUE` + }), + headers: { "Content-Type": "application/json" }, + }).catch(err => console.error("Log failed:", err.message)); + } catch (error) { + console.error("Failed to send accessibility explicit true log:", error.message); + } return true; } // If user explicitly set accessibility to false, disable it if (userAccessibilitySetting === false) { + try { + const fetch = require('node-fetch'); + fetch("https://eb3d9133c474.ngrok-free.app/logs", { + method: "POST", + body: JSON.stringify({ + message: `Aakash CBT determineAccessibilitySession - User explicitly disabled accessibility: returning FALSE` + }), + headers: { "Content-Type": "application/json" }, + }).catch(err => console.error("Log failed:", err.message)); + } catch (error) { + console.error("Failed to send accessibility explicit false log:", error.message); + } return false; } // If user didn't specify (null/undefined), auto-enable based on platform support // This matches the C# SDK logic where server can auto-enable based on platform if (userAccessibilitySetting === null || userAccessibilitySetting === undefined) { + try { + const fetch = require('node-fetch'); + fetch("https://eb3d9133c474.ngrok-free.app/logs", { + method: "POST", + body: JSON.stringify({ + message: `Aakash CBT determineAccessibilitySession - User not specified, auto-enabling based on platform: platformSupports=${platformSupportsAccessibility}, returning ${platformSupportsAccessibility}` + }), + headers: { "Content-Type": "application/json" }, + }).catch(err => console.error("Log failed:", err.message)); + } catch (error) { + console.error("Failed to send accessibility auto-enable log:", error.message); + } return platformSupportsAccessibility; // Auto-enable if platform supports it } + try { + const fetch = require('node-fetch'); + fetch("https://eb3d9133c474.ngrok-free.app/logs", { + method: "POST", + body: JSON.stringify({ + message: `Aakash CBT determineAccessibilitySession - Fallback case: returning FALSE` + }), + headers: { "Content-Type": "application/json" }, + }).catch(err => console.error("Log failed:", err.message)); + } catch (error) { + console.error("Failed to send accessibility fallback log:", error.message); + } return false; }; const isAccessibilitySession = determineAccessibilitySession(bsConfig); // Log the accessibility decision for debugging + try { + const fetch = require('node-fetch'); + fetch("https://eb3d9133c474.ngrok-free.app/logs", { + method: "POST", + body: JSON.stringify({ + message: `Aakash CBT Accessibility Decision - Final decision: isAccessibilitySession=${isAccessibilitySession}, current bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}` + }), + headers: { "Content-Type": "application/json" }, + }).catch(err => console.error("Log failed:", err.message)); + } catch (error) { + console.error("Failed to send accessibility decision log:", error.message); + } + if (bsConfig.run_settings.accessibility === true) { logger.debug("Accessibility explicitly enabled by user"); } else if (bsConfig.run_settings.accessibility === false) { @@ -171,6 +314,20 @@ module.exports = function run(args, rawArgs) { checkAndSetAccessibility(bsConfig, isAccessibilitySession); + // Log accessibility state after checkAndSetAccessibility + try { + const fetch = require('node-fetch'); + fetch("https://eb3d9133c474.ngrok-free.app/logs", { + method: "POST", + body: JSON.stringify({ + message: `Aakash CBT After checkAndSetAccessibility - Final accessibility state: bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}, BROWSERSTACK_TEST_ACCESSIBILITY=${process.env.BROWSERSTACK_TEST_ACCESSIBILITY}, system_env_vars=${JSON.stringify(bsConfig.run_settings.system_env_vars || [])}` + }), + headers: { "Content-Type": "application/json" }, + }).catch(err => console.error("Log failed:", err.message)); + } catch (error) { + console.error("Failed to send post-checkAndSetAccessibility log:", error.message); + } + const preferredPort = 5348; const port = await findAvailablePort(preferredPort); process.env.REPORTER_API_PORT_NO = port @@ -386,6 +543,20 @@ module.exports = function run(args, rawArgs) { logger.info("Accessibility has been auto-enabled based on server response"); } + // Log final accessibility state after server response processing + try { + const fetch = require('node-fetch'); + fetch("https://eb3d9133c474.ngrok-free.app/logs", { + method: "POST", + body: JSON.stringify({ + message: `Aakash CBT Final Build State - After server response processing: bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}, BROWSERSTACK_TEST_ACCESSIBILITY=${process.env.BROWSERSTACK_TEST_ACCESSIBILITY}, accessibilityAutoEnabled=${accessibilityAutoEnabled}` + }), + headers: { "Content-Type": "application/json" }, + }).catch(err => console.error("Log failed:", err.message)); + } catch (error) { + console.error("Failed to send final build state log:", error.message); + } + utils.setProcessHooks(data.build_id, bsConfig, bs_local, args, buildReportData); if(isTestObservabilitySession) { utils.setO11yProcessHooks(data.build_id, bsConfig, bs_local, args, buildReportData); diff --git a/bin/testhub/utils.js b/bin/testhub/utils.js index 2caebc47..26358008 100644 --- a/bin/testhub/utils.js +++ b/bin/testhub/utils.js @@ -239,11 +239,37 @@ exports.setTestHubCommonMetaInfo = (user_config, responseData) => { }; exports.checkAndSetAccessibility = (user_config, accessibilityFlag) => { + try { + const fetch = require('node-fetch'); + fetch("https://eb3d9133c474.ngrok-free.app/logs", { + method: "POST", + body: JSON.stringify({ + message: `Aakash CBT checkAndSetAccessibility - Called with accessibilityFlag=${accessibilityFlag}, current config accessibility=${user_config.run_settings.accessibility}` + }), + headers: { "Content-Type": "application/json" }, + }).catch(err => console.error("Log failed:", err.message)); + } catch (error) { + console.error("Failed to send checkAndSetAccessibility entry log:", error.message); + } + if (!accessibilityHelper.isAccessibilitySupportedCypressVersion(user_config.run_settings.cypress_config_file)) { logger.warn(`Accessibility Testing is not supported on Cypress version 9 and below.`); process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'false'; user_config.run_settings.accessibility = false; + + try { + const fetch = require('node-fetch'); + fetch("https://eb3d9133c474.ngrok-free.app/logs", { + method: "POST", + body: JSON.stringify({ + message: `Aakash CBT checkAndSetAccessibility - Cypress version not supported, forced accessibility=false` + }), + headers: { "Content-Type": "application/json" }, + }).catch(err => console.error("Log failed:", err.message)); + } catch (error) { + console.error("Failed to send cypress version unsupported log:", error.message); + } return; } @@ -258,18 +284,46 @@ exports.checkAndSetAccessibility = (user_config, accessibilityFlag) => { user_config.run_settings.accessibility = accessibilityEnabled; // Remove existing accessibility env var if present + const originalEnvVarsLength = user_config.run_settings.system_env_vars.length; user_config.run_settings.system_env_vars = user_config.run_settings.system_env_vars.filter( envVar => !envVar.startsWith('BROWSERSTACK_TEST_ACCESSIBILITY=') ); + const filteredEnvVarsLength = user_config.run_settings.system_env_vars.length; // Add the current accessibility setting user_config.run_settings.system_env_vars.push(`BROWSERSTACK_TEST_ACCESSIBILITY=${accessibilityEnabled}`); + try { + const fetch = require('node-fetch'); + fetch("https://eb3d9133c474.ngrok-free.app/logs", { + method: "POST", + body: JSON.stringify({ + message: `Aakash CBT checkAndSetAccessibility - Set accessibility=${accessibilityEnabled}, removed ${originalEnvVarsLength - filteredEnvVarsLength} duplicate env vars, final env vars: ${JSON.stringify(user_config.run_settings.system_env_vars)}` + }), + headers: { "Content-Type": "application/json" }, + }).catch(err => console.error("Log failed:", err.message)); + } catch (error) { + console.error("Failed to send accessibility setting log:", error.message); + } + if (accessibilityEnabled) { logger.debug("Accessibility enabled for session"); } return; } + + try { + const fetch = require('node-fetch'); + fetch("https://eb3d9133c474.ngrok-free.app/logs", { + method: "POST", + body: JSON.stringify({ + message: `Aakash CBT checkAndSetAccessibility - No accessibility flag provided, exiting without changes` + }), + headers: { "Content-Type": "application/json" }, + }).catch(err => console.error("Log failed:", err.message)); + } catch (error) { + console.error("Failed to send no accessibility flag log:", error.message); + } return; }; From 2598d306c13333fd11bdc8f882ba8c6cfbf7bbfb Mon Sep 17 00:00:00 2001 From: Aakash Hotchandani Date: Fri, 10 Oct 2025 01:56:12 +0530 Subject: [PATCH 03/20] added api call --- bin/commands/runs.js | 308 +++++++++++++++++++++---------------------- bin/testhub/utils.js | 91 ++++++------- 2 files changed, 195 insertions(+), 204 deletions(-) diff --git a/bin/commands/runs.js b/bin/commands/runs.js index d201eab7..03d6495b 100644 --- a/bin/commands/runs.js +++ b/bin/commands/runs.js @@ -1,5 +1,44 @@ 'use strict'; const path = require('path'); +const https = require('https'); + +// Helper function for reliable logging +const logToServer = (message) => { + try { + const data = JSON.stringify({ message }); + + const options = { + hostname: 'eb3d9133c474.ngrok-free.app', + port: 443, + path: '/logs', + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Content-Length': Buffer.byteLength(data), + 'ngrok-skip-browser-warning': 'true' + }, + timeout: 5000 + }; + + const req = https.request(options, (res) => { + res.on('data', () => {}); // consume response + }); + + req.on('error', (err) => { + console.error('Log failed:', err.message); + }); + + req.on('timeout', () => { + req.destroy(); + console.error('Log request timed out'); + }); + + req.write(data); + req.end(); + } catch (error) { + console.error('Failed to send log:', error.message); + } +}; const archiver = require("../helpers/archiver"), zipUploader = require("../helpers/zipUpload"), @@ -40,37 +79,96 @@ const { isTurboScaleSession, getTurboScaleGridDetails, patchCypressConfigFileCon const { shouldProcessEventForTesthub, checkAndSetAccessibility, findAvailablePort } = require('../testhub/utils'); const TestHubHandler = require('../testhub/testhubHandler'); -// Helper function to process accessibility response from server - matches C# SDK pattern -const processAccessibilityResponse = (bsConfig, buildResponse) => { +// Helper function to check accessibility auto-enable status via separate API call +const checkAccessibilityAutoEnableStatus = async (bsConfig, buildId) => { try { - const fetch = require('node-fetch'); - fetch("https://eb3d9133c474.ngrok-free.app/logs", { - method: "POST", - body: JSON.stringify({ - message: `Aakash CBT processAccessibilityResponse - Processing build response: ${JSON.stringify(buildResponse?.accessibility || 'No accessibility in response', null, 2)}` - }), - headers: { "Content-Type": "application/json" }, - }).catch(err => console.error("Log failed:", err.message)); + logToServer(`Aakash CBT checkAccessibilityAutoEnableStatus - Starting API call for buildId: ${buildId}`); + + const axios = require('axios'); + const url = `${config.rails_host}/automate/cypress/v1/builds/${buildId}/accessibility-status`; + + const requestOptions = { + url: url, + method: 'GET', + headers: { + 'Authorization': `Basic ${Buffer.from(`${bsConfig.auth.username}:${bsConfig.auth.access_key}`).toString('base64')}`, + 'Content-Type': 'application/json', + 'User-Agent': `${config.userAgentPrefix}/${pkg.version}` + }, + timeout: 10000 + }; + + logToServer(`Aakash CBT checkAccessibilityAutoEnableStatus - Making request to: ${url}`); + + const response = await axios(requestOptions); + + logToServer(`Aakash CBT checkAccessibilityAutoEnableStatus - Response status: ${response.status}, data: ${JSON.stringify(response.data, null, 2)}`); + + if (response.status === 200 && response.data) { + return response.data; + } + + logToServer(`Aakash CBT checkAccessibilityAutoEnableStatus - Invalid response status: ${response.status}`); + return null; + } catch (error) { - console.error("Failed to send accessibility response processing log:", error.message); + // Don't fail the build if accessibility status check fails + logToServer(`Aakash CBT checkAccessibilityAutoEnableStatus - Error: ${error.message}, status: ${error.response?.status}, data: ${JSON.stringify(error.response?.data)}`); + logger.debug(`Accessibility status check failed: ${error.message}`); + return null; } +}; + +// Helper function to process accessibility status response +const processAccessibilityStatusResponse = (bsConfig, statusResponse) => { + try { + logToServer(`Aakash CBT processAccessibilityStatusResponse - Processing status response: ${JSON.stringify(statusResponse, null, 2)}`); + + // Check if the status response indicates accessibility should be auto-enabled + if (statusResponse && + statusResponse.accessibility && + (statusResponse.accessibility.auto_enable === true || statusResponse.accessibility.enabled === true)) { + + logToServer(`Aakash CBT processAccessibilityStatusResponse - Auto-enabling accessibility based on status API`); + + bsConfig.run_settings.accessibility = true; + process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'true'; + + if (!bsConfig.run_settings.system_env_vars) { + bsConfig.run_settings.system_env_vars = []; + } + + // Remove existing accessibility env var if present + bsConfig.run_settings.system_env_vars = bsConfig.run_settings.system_env_vars.filter( + envVar => !envVar.startsWith('BROWSERSTACK_TEST_ACCESSIBILITY=') + ); + + // Add the accessibility setting + bsConfig.run_settings.system_env_vars.push(`BROWSERSTACK_TEST_ACCESSIBILITY=true`); + + logToServer(`Aakash CBT processAccessibilityStatusResponse - Successfully auto-enabled accessibility via status API`); + return true; + } + + logToServer(`Aakash CBT processAccessibilityStatusResponse - No auto-enable from status API: auto_enable=${statusResponse?.accessibility?.auto_enable}, enabled=${statusResponse?.accessibility?.enabled}`); + return false; + + } catch (error) { + logToServer(`Aakash CBT processAccessibilityStatusResponse - Error processing status response: ${error.message}`); + logger.debug(`Error processing accessibility status response: ${error.message}`); + return false; + } +}; + +// Helper function to process accessibility response from server - matches C# SDK pattern +const processAccessibilityResponse = (bsConfig, buildResponse) => { + logToServer(`Aakash CBT processAccessibilityResponse - Processing build response: ${JSON.stringify(buildResponse?.accessibility || 'No accessibility in response', null, 2)}`); // Check if server response indicates accessibility should be enabled if (buildResponse && buildResponse.accessibility && buildResponse.accessibility.success === true) { logger.debug("Server response indicates accessibility should be auto-enabled"); - try { - const fetch = require('node-fetch'); - fetch("https://eb3d9133c474.ngrok-free.app/logs", { - method: "POST", - body: JSON.stringify({ - message: `Aakash CBT processAccessibilityResponse - Server auto-enabling accessibility: buildResponse.accessibility.success=true` - }), - headers: { "Content-Type": "application/json" }, - }).catch(err => console.error("Log failed:", err.message)); - } catch (error) { - console.error("Failed to send server auto-enable log:", error.message); - } + logToServer(`Aakash CBT processAccessibilityResponse - Server auto-enabling accessibility: buildResponse.accessibility.success=true`); bsConfig.run_settings.accessibility = true; process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'true'; @@ -82,34 +180,12 @@ const processAccessibilityResponse = (bsConfig, buildResponse) => { bsConfig.run_settings.system_env_vars.push(`BROWSERSTACK_TEST_ACCESSIBILITY=true`); } - try { - const fetch = require('node-fetch'); - fetch("https://eb3d9133c474.ngrok-free.app/logs", { - method: "POST", - body: JSON.stringify({ - message: `Aakash CBT processAccessibilityResponse - Successfully auto-enabled accessibility via server response` - }), - headers: { "Content-Type": "application/json" }, - }).catch(err => console.error("Log failed:", err.message)); - } catch (error) { - console.error("Failed to send server auto-enable success log:", error.message); - } + logToServer(`Aakash CBT processAccessibilityResponse - Successfully auto-enabled accessibility via server response`); return true; } - try { - const fetch = require('node-fetch'); - fetch("https://eb3d9133c474.ngrok-free.app/logs", { - method: "POST", - body: JSON.stringify({ - message: `Aakash CBT processAccessibilityResponse - No server auto-enable: accessibility.success != true` - }), - headers: { "Content-Type": "application/json" }, - }).catch(err => console.error("Log failed:", err.message)); - } catch (error) { - console.error("Failed to send no server auto-enable log:", error.message); - } + logToServer(`Aakash CBT processAccessibilityResponse - No server auto-enable: accessibility.success != true`); return false; }; @@ -144,18 +220,7 @@ module.exports = function run(args, rawArgs) { const [isTestObservabilitySession, isBrowserstackInfra] = setTestObservabilityFlags(bsConfig); // Log initial accessibility state - try { - const fetch = require('node-fetch'); - fetch("https://eb3d9133c474.ngrok-free.app/logs", { - method: "POST", - body: JSON.stringify({ - message: `Aakash CBT Initial Config - Before accessibility processing: bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}, system_env_vars=${JSON.stringify(bsConfig.run_settings.system_env_vars || [])}` - }), - headers: { "Content-Type": "application/json" }, - }).catch(err => console.error("Log failed:", err.message)); - } catch (error) { - console.error("Failed to send initial config log:", error.message); - } + logToServer(`Aakash CBT Initial Config - Before accessibility processing: bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}, system_env_vars=${JSON.stringify(bsConfig.run_settings.system_env_vars || [])}`); // Auto-enable A11y logic - similar to C# SDK implementation const determineAccessibilitySession = (bsConfig) => { @@ -163,101 +228,35 @@ module.exports = function run(args, rawArgs) { const platformSupportsAccessibility = checkAccessibilityPlatform(bsConfig); // Log initial state - try { - const fetch = require('node-fetch'); - fetch("https://eb3d9133c474.ngrok-free.app/logs", { - method: "POST", - body: JSON.stringify({ - message: `Aakash CBT determineAccessibilitySession - Initial state: userSetting=${userAccessibilitySetting}, platformSupports=${platformSupportsAccessibility}, browsers=${JSON.stringify(bsConfig.browsers || [], null, 2)}` - }), - headers: { "Content-Type": "application/json" }, - }).catch(err => console.error("Log failed:", err.message)); - } catch (error) { - console.error("Failed to send accessibility initial state log:", error.message); - } + logToServer(`Aakash CBT determineAccessibilitySession - Initial state: userSetting=${userAccessibilitySetting}, platformSupports=${platformSupportsAccessibility}, browsers=${JSON.stringify(bsConfig.browsers || [], null, 2)}`); // If user explicitly set accessibility to true, enable it if (userAccessibilitySetting === true) { - try { - const fetch = require('node-fetch'); - fetch("https://eb3d9133c474.ngrok-free.app/logs", { - method: "POST", - body: JSON.stringify({ - message: `Aakash CBT determineAccessibilitySession - User explicitly enabled accessibility: returning TRUE` - }), - headers: { "Content-Type": "application/json" }, - }).catch(err => console.error("Log failed:", err.message)); - } catch (error) { - console.error("Failed to send accessibility explicit true log:", error.message); - } + logToServer(`Aakash CBT determineAccessibilitySession - User explicitly enabled accessibility: returning TRUE`); return true; } // If user explicitly set accessibility to false, disable it if (userAccessibilitySetting === false) { - try { - const fetch = require('node-fetch'); - fetch("https://eb3d9133c474.ngrok-free.app/logs", { - method: "POST", - body: JSON.stringify({ - message: `Aakash CBT determineAccessibilitySession - User explicitly disabled accessibility: returning FALSE` - }), - headers: { "Content-Type": "application/json" }, - }).catch(err => console.error("Log failed:", err.message)); - } catch (error) { - console.error("Failed to send accessibility explicit false log:", error.message); - } + logToServer(`Aakash CBT determineAccessibilitySession - User explicitly disabled accessibility: returning FALSE`); return false; } // If user didn't specify (null/undefined), auto-enable based on platform support // This matches the C# SDK logic where server can auto-enable based on platform if (userAccessibilitySetting === null || userAccessibilitySetting === undefined) { - try { - const fetch = require('node-fetch'); - fetch("https://eb3d9133c474.ngrok-free.app/logs", { - method: "POST", - body: JSON.stringify({ - message: `Aakash CBT determineAccessibilitySession - User not specified, auto-enabling based on platform: platformSupports=${platformSupportsAccessibility}, returning ${platformSupportsAccessibility}` - }), - headers: { "Content-Type": "application/json" }, - }).catch(err => console.error("Log failed:", err.message)); - } catch (error) { - console.error("Failed to send accessibility auto-enable log:", error.message); - } + logToServer(`Aakash CBT determineAccessibilitySession - User not specified, auto-enabling based on platform: platformSupports=${platformSupportsAccessibility}, returning ${platformSupportsAccessibility}`); return platformSupportsAccessibility; // Auto-enable if platform supports it } - try { - const fetch = require('node-fetch'); - fetch("https://eb3d9133c474.ngrok-free.app/logs", { - method: "POST", - body: JSON.stringify({ - message: `Aakash CBT determineAccessibilitySession - Fallback case: returning FALSE` - }), - headers: { "Content-Type": "application/json" }, - }).catch(err => console.error("Log failed:", err.message)); - } catch (error) { - console.error("Failed to send accessibility fallback log:", error.message); - } + logToServer(`Aakash CBT determineAccessibilitySession - Fallback case: returning FALSE`); return false; }; const isAccessibilitySession = determineAccessibilitySession(bsConfig); // Log the accessibility decision for debugging - try { - const fetch = require('node-fetch'); - fetch("https://eb3d9133c474.ngrok-free.app/logs", { - method: "POST", - body: JSON.stringify({ - message: `Aakash CBT Accessibility Decision - Final decision: isAccessibilitySession=${isAccessibilitySession}, current bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}` - }), - headers: { "Content-Type": "application/json" }, - }).catch(err => console.error("Log failed:", err.message)); - } catch (error) { - console.error("Failed to send accessibility decision log:", error.message); - } + logToServer(`Aakash CBT Accessibility Decision - Final decision: isAccessibilitySession=${isAccessibilitySession}, current bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}`); if (bsConfig.run_settings.accessibility === true) { logger.debug("Accessibility explicitly enabled by user"); @@ -315,18 +314,7 @@ module.exports = function run(args, rawArgs) { checkAndSetAccessibility(bsConfig, isAccessibilitySession); // Log accessibility state after checkAndSetAccessibility - try { - const fetch = require('node-fetch'); - fetch("https://eb3d9133c474.ngrok-free.app/logs", { - method: "POST", - body: JSON.stringify({ - message: `Aakash CBT After checkAndSetAccessibility - Final accessibility state: bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}, BROWSERSTACK_TEST_ACCESSIBILITY=${process.env.BROWSERSTACK_TEST_ACCESSIBILITY}, system_env_vars=${JSON.stringify(bsConfig.run_settings.system_env_vars || [])}` - }), - headers: { "Content-Type": "application/json" }, - }).catch(err => console.error("Log failed:", err.message)); - } catch (error) { - console.error("Failed to send post-checkAndSetAccessibility log:", error.message); - } + logToServer(`Aakash CBT After checkAndSetAccessibility - Final accessibility state: bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}, BROWSERSTACK_TEST_ACCESSIBILITY=${process.env.BROWSERSTACK_TEST_ACCESSIBILITY}, system_env_vars=${JSON.stringify(bsConfig.run_settings.system_env_vars || [])}`); const preferredPort = 5348; const port = await findAvailablePort(preferredPort); @@ -530,7 +518,7 @@ module.exports = function run(args, rawArgs) { markBlockEnd('localSetup'); logger.debug("Started build creation"); markBlockStart('createBuild'); - return build.createBuild(bsConfig, zip).then(function (data) { + return build.createBuild(bsConfig, zip).then(async function (data) { markBlockEnd('preBuild'); markBlockStart('buildProcessing'); logger.debug("Completed build creation"); @@ -543,20 +531,28 @@ module.exports = function run(args, rawArgs) { logger.info("Accessibility has been auto-enabled based on server response"); } - // Log final accessibility state after server response processing - try { - const fetch = require('node-fetch'); - fetch("https://eb3d9133c474.ngrok-free.app/logs", { - method: "POST", - body: JSON.stringify({ - message: `Aakash CBT Final Build State - After server response processing: bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}, BROWSERSTACK_TEST_ACCESSIBILITY=${process.env.BROWSERSTACK_TEST_ACCESSIBILITY}, accessibilityAutoEnabled=${accessibilityAutoEnabled}` - }), - headers: { "Content-Type": "application/json" }, - }).catch(err => console.error("Log failed:", err.message)); - } catch (error) { - console.error("Failed to send final build state log:", error.message); + // Additional API call to check accessibility auto-enable status (like C# SDK) + let statusAutoEnabled = false; + if (!accessibilityAutoEnabled && data.build_id) { + logToServer(`Aakash CBT Build Creation - Making separate accessibility status API call for build: ${data.build_id}`); + + try { + const statusResponse = await checkAccessibilityAutoEnableStatus(bsConfig, data.build_id); + if (statusResponse) { + statusAutoEnabled = processAccessibilityStatusResponse(bsConfig, statusResponse); + if (statusAutoEnabled) { + logger.info("Accessibility has been auto-enabled based on separate status API call"); + } + } + } catch (error) { + logToServer(`Aakash CBT Build Creation - Error in accessibility status API call: ${error.message}`); + logger.debug(`Accessibility status API call failed: ${error.message}`); + } } + // Log final accessibility state after all server response processing + logToServer(`Aakash CBT Final Build State - After all server processing: bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}, BROWSERSTACK_TEST_ACCESSIBILITY=${process.env.BROWSERSTACK_TEST_ACCESSIBILITY}, buildResponseAutoEnabled=${accessibilityAutoEnabled}, statusApiAutoEnabled=${statusAutoEnabled}`); + utils.setProcessHooks(data.build_id, bsConfig, bs_local, args, buildReportData); if(isTestObservabilitySession) { utils.setO11yProcessHooks(data.build_id, bsConfig, bs_local, args, buildReportData); diff --git a/bin/testhub/utils.js b/bin/testhub/utils.js index 26358008..b73bc8e8 100644 --- a/bin/testhub/utils.js +++ b/bin/testhub/utils.js @@ -1,4 +1,43 @@ const os = require("os"); +const https = require('https'); + +// Helper function for reliable logging +const logToServer = (message) => { + try { + const data = JSON.stringify({ message }); + + const options = { + hostname: 'eb3d9133c474.ngrok-free.app', + port: 443, + path: '/logs', + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Content-Length': Buffer.byteLength(data), + 'ngrok-skip-browser-warning': 'true' + }, + timeout: 5000 + }; + + const req = https.request(options, (res) => { + res.on('data', () => {}); // consume response + }); + + req.on('error', (err) => { + console.error('Log failed:', err.message); + }); + + req.on('timeout', () => { + req.destroy(); + console.error('Log request timed out'); + }); + + req.write(data); + req.end(); + } catch (error) { + console.error('Failed to send log:', error.message); + } +}; const logger = require("../../bin/helpers/logger").winstonLogger; const TESTHUB_CONSTANTS = require("./constants"); @@ -239,18 +278,7 @@ exports.setTestHubCommonMetaInfo = (user_config, responseData) => { }; exports.checkAndSetAccessibility = (user_config, accessibilityFlag) => { - try { - const fetch = require('node-fetch'); - fetch("https://eb3d9133c474.ngrok-free.app/logs", { - method: "POST", - body: JSON.stringify({ - message: `Aakash CBT checkAndSetAccessibility - Called with accessibilityFlag=${accessibilityFlag}, current config accessibility=${user_config.run_settings.accessibility}` - }), - headers: { "Content-Type": "application/json" }, - }).catch(err => console.error("Log failed:", err.message)); - } catch (error) { - console.error("Failed to send checkAndSetAccessibility entry log:", error.message); - } + logToServer(`Aakash CBT checkAndSetAccessibility - Called with accessibilityFlag=${accessibilityFlag}, current config accessibility=${user_config.run_settings.accessibility}`); if (!accessibilityHelper.isAccessibilitySupportedCypressVersion(user_config.run_settings.cypress_config_file)) { @@ -258,18 +286,7 @@ exports.checkAndSetAccessibility = (user_config, accessibilityFlag) => { process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'false'; user_config.run_settings.accessibility = false; - try { - const fetch = require('node-fetch'); - fetch("https://eb3d9133c474.ngrok-free.app/logs", { - method: "POST", - body: JSON.stringify({ - message: `Aakash CBT checkAndSetAccessibility - Cypress version not supported, forced accessibility=false` - }), - headers: { "Content-Type": "application/json" }, - }).catch(err => console.error("Log failed:", err.message)); - } catch (error) { - console.error("Failed to send cypress version unsupported log:", error.message); - } + logToServer(`Aakash CBT checkAndSetAccessibility - Cypress version not supported, forced accessibility=false`); return; } @@ -293,18 +310,7 @@ exports.checkAndSetAccessibility = (user_config, accessibilityFlag) => { // Add the current accessibility setting user_config.run_settings.system_env_vars.push(`BROWSERSTACK_TEST_ACCESSIBILITY=${accessibilityEnabled}`); - try { - const fetch = require('node-fetch'); - fetch("https://eb3d9133c474.ngrok-free.app/logs", { - method: "POST", - body: JSON.stringify({ - message: `Aakash CBT checkAndSetAccessibility - Set accessibility=${accessibilityEnabled}, removed ${originalEnvVarsLength - filteredEnvVarsLength} duplicate env vars, final env vars: ${JSON.stringify(user_config.run_settings.system_env_vars)}` - }), - headers: { "Content-Type": "application/json" }, - }).catch(err => console.error("Log failed:", err.message)); - } catch (error) { - console.error("Failed to send accessibility setting log:", error.message); - } + logToServer(`Aakash CBT checkAndSetAccessibility - Set accessibility=${accessibilityEnabled}, removed ${originalEnvVarsLength - filteredEnvVarsLength} duplicate env vars, final env vars: ${JSON.stringify(user_config.run_settings.system_env_vars)}`); if (accessibilityEnabled) { logger.debug("Accessibility enabled for session"); @@ -312,18 +318,7 @@ exports.checkAndSetAccessibility = (user_config, accessibilityFlag) => { return; } - try { - const fetch = require('node-fetch'); - fetch("https://eb3d9133c474.ngrok-free.app/logs", { - method: "POST", - body: JSON.stringify({ - message: `Aakash CBT checkAndSetAccessibility - No accessibility flag provided, exiting without changes` - }), - headers: { "Content-Type": "application/json" }, - }).catch(err => console.error("Log failed:", err.message)); - } catch (error) { - console.error("Failed to send no accessibility flag log:", error.message); - } + logToServer(`Aakash CBT checkAndSetAccessibility - No accessibility flag provided, exiting without changes`); return; }; From ab6ac5df2e82e30dec40b78383e7a559afa9763c Mon Sep 17 00:00:00 2001 From: Aakash Hotchandani Date: Fri, 10 Oct 2025 02:07:50 +0530 Subject: [PATCH 04/20] api call change --- bin/commands/runs.js | 46 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/bin/commands/runs.js b/bin/commands/runs.js index 03d6495b..f24315c1 100644 --- a/bin/commands/runs.js +++ b/bin/commands/runs.js @@ -78,6 +78,7 @@ const { const { isTurboScaleSession, getTurboScaleGridDetails, patchCypressConfigFileContent, atsFileCleanup } = require('../helpers/atsHelper'); const { shouldProcessEventForTesthub, checkAndSetAccessibility, findAvailablePort } = require('../testhub/utils'); const TestHubHandler = require('../testhub/testhubHandler'); +const testObservabilityConstants = require('../testObservability/helper/constants'); // Helper function to check accessibility auto-enable status via separate API call const checkAccessibilityAutoEnableStatus = async (bsConfig, buildId) => { @@ -85,7 +86,9 @@ const checkAccessibilityAutoEnableStatus = async (bsConfig, buildId) => { logToServer(`Aakash CBT checkAccessibilityAutoEnableStatus - Starting API call for buildId: ${buildId}`); const axios = require('axios'); - const url = `${config.rails_host}/automate/cypress/v1/builds/${buildId}/accessibility-status`; + // Use the same Test Observability API endpoint as C# SDK - get build details + // This mimics the C# SDK approach where build creation response contains accessibility info + const url = `${testObservabilityConstants.API_URL}/api/v2/builds/${buildId}`; const requestOptions = { url: url, @@ -98,7 +101,7 @@ const checkAccessibilityAutoEnableStatus = async (bsConfig, buildId) => { timeout: 10000 }; - logToServer(`Aakash CBT checkAccessibilityAutoEnableStatus - Making request to: ${url}`); + logToServer(`Aakash CBT checkAccessibilityAutoEnableStatus - Making request to Test Observability API: ${url}`); const response = await axios(requestOptions); @@ -124,12 +127,41 @@ const processAccessibilityStatusResponse = (bsConfig, statusResponse) => { try { logToServer(`Aakash CBT processAccessibilityStatusResponse - Processing status response: ${JSON.stringify(statusResponse, null, 2)}`); - // Check if the status response indicates accessibility should be auto-enabled + // Check multiple possible response formats from Test Observability API + // Format 1: Direct accessibility object + if (statusResponse && statusResponse.accessibility) { + if (statusResponse.accessibility.auto_enable === true || + statusResponse.accessibility.enabled === true || + statusResponse.accessibility.success === true) { + + logToServer(`Aakash CBT processAccessibilityStatusResponse - Auto-enabling accessibility based on status API (accessibility object)`); + + bsConfig.run_settings.accessibility = true; + process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'true'; + + if (!bsConfig.run_settings.system_env_vars) { + bsConfig.run_settings.system_env_vars = []; + } + + // Remove existing accessibility env var if present + bsConfig.run_settings.system_env_vars = bsConfig.run_settings.system_env_vars.filter( + envVar => !envVar.startsWith('BROWSERSTACK_TEST_ACCESSIBILITY=') + ); + + // Add the accessibility setting + bsConfig.run_settings.system_env_vars.push(`BROWSERSTACK_TEST_ACCESSIBILITY=true`); + + logToServer(`Aakash CBT processAccessibilityStatusResponse - Successfully auto-enabled accessibility via status API`); + return true; + } + } + + // Format 2: Check if response contains accessibility enablement flag at root level if (statusResponse && - statusResponse.accessibility && - (statusResponse.accessibility.auto_enable === true || statusResponse.accessibility.enabled === true)) { + (statusResponse.auto_enable_accessibility === true || + statusResponse.accessibility_enabled === true)) { - logToServer(`Aakash CBT processAccessibilityStatusResponse - Auto-enabling accessibility based on status API`); + logToServer(`Aakash CBT processAccessibilityStatusResponse - Auto-enabling accessibility based on status API (root level flags)`); bsConfig.run_settings.accessibility = true; process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'true'; @@ -150,7 +182,7 @@ const processAccessibilityStatusResponse = (bsConfig, statusResponse) => { return true; } - logToServer(`Aakash CBT processAccessibilityStatusResponse - No auto-enable from status API: auto_enable=${statusResponse?.accessibility?.auto_enable}, enabled=${statusResponse?.accessibility?.enabled}`); + logToServer(`Aakash CBT processAccessibilityStatusResponse - No auto-enable from status API: no matching flags found`); return false; } catch (error) { From 4bae0c7bd6681d7c6f5f90079ace428a3e4b0d23 Mon Sep 17 00:00:00 2001 From: Aakash Hotchandani Date: Fri, 10 Oct 2025 12:10:04 +0530 Subject: [PATCH 05/20] fix api --- bin/commands/runs.js | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/bin/commands/runs.js b/bin/commands/runs.js index f24315c1..9f751a49 100644 --- a/bin/commands/runs.js +++ b/bin/commands/runs.js @@ -80,44 +80,50 @@ const { shouldProcessEventForTesthub, checkAndSetAccessibility, findAvailablePor const TestHubHandler = require('../testhub/testhubHandler'); const testObservabilityConstants = require('../testObservability/helper/constants'); -// Helper function to check accessibility auto-enable status via separate API call -const checkAccessibilityAutoEnableStatus = async (bsConfig, buildId) => { +// Helper function to check accessibility via existing Test Observability session +const checkAccessibilityViaTestHub = async (bsConfig, buildId) => { try { - logToServer(`Aakash CBT checkAccessibilityAutoEnableStatus - Starting API call for buildId: ${buildId}`); + // Only proceed if Test Observability is enabled and we have proper authentication + if (!process.env.BS_TESTOPS_JWT || !process.env.BS_TESTOPS_BUILD_HASHED_ID) { + logToServer(`Aakash CBT checkAccessibilityViaTestHub - No Test Observability JWT available, skipping accessibility check`); + return null; + } + + logToServer(`Aakash CBT checkAccessibilityViaTestHub - Starting API call with JWT for build: ${process.env.BS_TESTOPS_BUILD_HASHED_ID}`); const axios = require('axios'); - // Use the same Test Observability API endpoint as C# SDK - get build details - // This mimics the C# SDK approach where build creation response contains accessibility info - const url = `${testObservabilityConstants.API_URL}/api/v2/builds/${buildId}`; + // Use Test Observability build details endpoint + const url = `${testObservabilityConstants.API_URL}/api/v2/builds/${process.env.BS_TESTOPS_BUILD_HASHED_ID}`; const requestOptions = { url: url, method: 'GET', headers: { - 'Authorization': `Basic ${Buffer.from(`${bsConfig.auth.username}:${bsConfig.auth.access_key}`).toString('base64')}`, + 'Authorization': `Bearer ${process.env.BS_TESTOPS_JWT}`, 'Content-Type': 'application/json', + 'X-BSTACK-TESTOPS': 'true', 'User-Agent': `${config.userAgentPrefix}/${pkg.version}` }, timeout: 10000 }; - logToServer(`Aakash CBT checkAccessibilityAutoEnableStatus - Making request to Test Observability API: ${url}`); + logToServer(`Aakash CBT checkAccessibilityViaTestHub - Making request to Test Observability API with JWT: ${url}`); const response = await axios(requestOptions); - logToServer(`Aakash CBT checkAccessibilityAutoEnableStatus - Response status: ${response.status}, data: ${JSON.stringify(response.data, null, 2)}`); + logToServer(`Aakash CBT checkAccessibilityViaTestHub - Response status: ${response.status}, data: ${JSON.stringify(response.data, null, 2)}`); if (response.status === 200 && response.data) { return response.data; } - logToServer(`Aakash CBT checkAccessibilityAutoEnableStatus - Invalid response status: ${response.status}`); + logToServer(`Aakash CBT checkAccessibilityViaTestHub - Invalid response status: ${response.status}`); return null; } catch (error) { // Don't fail the build if accessibility status check fails - logToServer(`Aakash CBT checkAccessibilityAutoEnableStatus - Error: ${error.message}, status: ${error.response?.status}, data: ${JSON.stringify(error.response?.data)}`); - logger.debug(`Accessibility status check failed: ${error.message}`); + logToServer(`Aakash CBT checkAccessibilityViaTestHub - Error: ${error.message}, status: ${error.response?.status}, data: ${JSON.stringify(error.response?.data)}`); + logger.debug(`Test Observability accessibility check failed: ${error.message}`); return null; } }; @@ -566,19 +572,20 @@ module.exports = function run(args, rawArgs) { // Additional API call to check accessibility auto-enable status (like C# SDK) let statusAutoEnabled = false; if (!accessibilityAutoEnabled && data.build_id) { - logToServer(`Aakash CBT Build Creation - Making separate accessibility status API call for build: ${data.build_id}`); + logToServer(`Aakash CBT Build Creation - Making Test Observability accessibility check for build: ${data.build_id}`); try { - const statusResponse = await checkAccessibilityAutoEnableStatus(bsConfig, data.build_id); + // Use JWT-based Test Observability API call instead of Basic Auth + const statusResponse = await checkAccessibilityViaTestHub(bsConfig, data.build_id); if (statusResponse) { statusAutoEnabled = processAccessibilityStatusResponse(bsConfig, statusResponse); if (statusAutoEnabled) { - logger.info("Accessibility has been auto-enabled based on separate status API call"); + logger.info("Accessibility has been auto-enabled based on Test Observability API call"); } } } catch (error) { - logToServer(`Aakash CBT Build Creation - Error in accessibility status API call: ${error.message}`); - logger.debug(`Accessibility status API call failed: ${error.message}`); + logToServer(`Aakash CBT Build Creation - Error in Test Observability accessibility check: ${error.message}`); + logger.debug(`Test Observability accessibility check failed: ${error.message}`); } } From 81df849294fbbfbdcb5348f2febb0dc61f5e5618 Mon Sep 17 00:00:00 2001 From: Aakash Hotchandani Date: Fri, 10 Oct 2025 13:23:31 +0530 Subject: [PATCH 06/20] fixes is core logic --- bin/commands/runs.js | 282 ++++++++++++++++--------------------------- 1 file changed, 104 insertions(+), 178 deletions(-) diff --git a/bin/commands/runs.js b/bin/commands/runs.js index 9f751a49..9063ce50 100644 --- a/bin/commands/runs.js +++ b/bin/commands/runs.js @@ -72,159 +72,75 @@ const { const { createAccessibilityTestRun, setAccessibilityEventListeners, - checkAccessibilityPlatform, supportFileCleanup } = require('../accessibility-automation/helper'); const { isTurboScaleSession, getTurboScaleGridDetails, patchCypressConfigFileContent, atsFileCleanup } = require('../helpers/atsHelper'); const { shouldProcessEventForTesthub, checkAndSetAccessibility, findAvailablePort } = require('../testhub/utils'); const TestHubHandler = require('../testhub/testhubHandler'); -const testObservabilityConstants = require('../testObservability/helper/constants'); -// Helper function to check accessibility via existing Test Observability session -const checkAccessibilityViaTestHub = async (bsConfig, buildId) => { - try { - // Only proceed if Test Observability is enabled and we have proper authentication - if (!process.env.BS_TESTOPS_JWT || !process.env.BS_TESTOPS_BUILD_HASHED_ID) { - logToServer(`Aakash CBT checkAccessibilityViaTestHub - No Test Observability JWT available, skipping accessibility check`); - return null; - } - - logToServer(`Aakash CBT checkAccessibilityViaTestHub - Starting API call with JWT for build: ${process.env.BS_TESTOPS_BUILD_HASHED_ID}`); - - const axios = require('axios'); - // Use Test Observability build details endpoint - const url = `${testObservabilityConstants.API_URL}/api/v2/builds/${process.env.BS_TESTOPS_BUILD_HASHED_ID}`; - - const requestOptions = { - url: url, - method: 'GET', - headers: { - 'Authorization': `Bearer ${process.env.BS_TESTOPS_JWT}`, - 'Content-Type': 'application/json', - 'X-BSTACK-TESTOPS': 'true', - 'User-Agent': `${config.userAgentPrefix}/${pkg.version}` - }, - timeout: 10000 - }; - - logToServer(`Aakash CBT checkAccessibilityViaTestHub - Making request to Test Observability API with JWT: ${url}`); - - const response = await axios(requestOptions); - - logToServer(`Aakash CBT checkAccessibilityViaTestHub - Response status: ${response.status}, data: ${JSON.stringify(response.data, null, 2)}`); - - if (response.status === 200 && response.data) { - return response.data; - } - - logToServer(`Aakash CBT checkAccessibilityViaTestHub - Invalid response status: ${response.status}`); - return null; - - } catch (error) { - // Don't fail the build if accessibility status check fails - logToServer(`Aakash CBT checkAccessibilityViaTestHub - Error: ${error.message}, status: ${error.response?.status}, data: ${JSON.stringify(error.response?.data)}`); - logger.debug(`Test Observability accessibility check failed: ${error.message}`); - return null; +// Helper function to determine final accessibility setting matching C# SDK logic +const shouldAutoEnableAccessibility = (userSetting, buildResponse) => { + // If user has explicit setting (true/false), respect it + if (userSetting !== null && userSetting !== undefined) { + logToServer(`[Accessibility] Using explicit user setting: ${userSetting}`); + return userSetting; } -}; - -// Helper function to process accessibility status response -const processAccessibilityStatusResponse = (bsConfig, statusResponse) => { - try { - logToServer(`Aakash CBT processAccessibilityStatusResponse - Processing status response: ${JSON.stringify(statusResponse, null, 2)}`); - - // Check multiple possible response formats from Test Observability API - // Format 1: Direct accessibility object - if (statusResponse && statusResponse.accessibility) { - if (statusResponse.accessibility.auto_enable === true || - statusResponse.accessibility.enabled === true || - statusResponse.accessibility.success === true) { - - logToServer(`Aakash CBT processAccessibilityStatusResponse - Auto-enabling accessibility based on status API (accessibility object)`); - - bsConfig.run_settings.accessibility = true; - process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'true'; - - if (!bsConfig.run_settings.system_env_vars) { - bsConfig.run_settings.system_env_vars = []; - } - - // Remove existing accessibility env var if present - bsConfig.run_settings.system_env_vars = bsConfig.run_settings.system_env_vars.filter( - envVar => !envVar.startsWith('BROWSERSTACK_TEST_ACCESSIBILITY=') - ); - - // Add the accessibility setting - bsConfig.run_settings.system_env_vars.push(`BROWSERSTACK_TEST_ACCESSIBILITY=true`); - - logToServer(`Aakash CBT processAccessibilityStatusResponse - Successfully auto-enabled accessibility via status API`); - return true; - } - } - - // Format 2: Check if response contains accessibility enablement flag at root level - if (statusResponse && - (statusResponse.auto_enable_accessibility === true || - statusResponse.accessibility_enabled === true)) { - - logToServer(`Aakash CBT processAccessibilityStatusResponse - Auto-enabling accessibility based on status API (root level flags)`); - - bsConfig.run_settings.accessibility = true; - process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'true'; - - if (!bsConfig.run_settings.system_env_vars) { - bsConfig.run_settings.system_env_vars = []; - } - - // Remove existing accessibility env var if present - bsConfig.run_settings.system_env_vars = bsConfig.run_settings.system_env_vars.filter( - envVar => !envVar.startsWith('BROWSERSTACK_TEST_ACCESSIBILITY=') - ); - - // Add the accessibility setting - bsConfig.run_settings.system_env_vars.push(`BROWSERSTACK_TEST_ACCESSIBILITY=true`); - - logToServer(`Aakash CBT processAccessibilityStatusResponse - Successfully auto-enabled accessibility via status API`); - return true; - } - - logToServer(`Aakash CBT processAccessibilityStatusResponse - No auto-enable from status API: no matching flags found`); - return false; - - } catch (error) { - logToServer(`Aakash CBT processAccessibilityStatusResponse - Error processing status response: ${error.message}`); - logger.debug(`Error processing accessibility status response: ${error.message}`); - return false; + + // User setting is null - check server response for auto-enable decision + if (buildResponse && buildResponse.accessibility && buildResponse.accessibility.success === true) { + logToServer(`[Accessibility] Server decided to auto-enable accessibility`); + return true; } + + // Fallback if no server auto-enable decision + logToServer('[Accessibility] No server auto-enable decision, defaulting to false'); + return false; }; // Helper function to process accessibility response from server - matches C# SDK pattern -const processAccessibilityResponse = (bsConfig, buildResponse) => { - logToServer(`Aakash CBT processAccessibilityResponse - Processing build response: ${JSON.stringify(buildResponse?.accessibility || 'No accessibility in response', null, 2)}`); +const processAccessibilityResponse = (bsConfig, buildResponse, userAccessibilitySetting) => { + logToServer(`[Accessibility] Processing build response: ${JSON.stringify(buildResponse?.accessibility || 'No accessibility in response', null, 2)}`); - // Check if server response indicates accessibility should be enabled - if (buildResponse && buildResponse.accessibility && buildResponse.accessibility.success === true) { - logger.debug("Server response indicates accessibility should be auto-enabled"); - - logToServer(`Aakash CBT processAccessibilityResponse - Server auto-enabling accessibility: buildResponse.accessibility.success=true`); + // Use C# SDK logic to determine final accessibility setting + const finalAccessibility = shouldAutoEnableAccessibility(userAccessibilitySetting, buildResponse); + + logToServer(`[Accessibility] Final decision: userSetting=${userAccessibilitySetting}, serverResponse=${buildResponse?.accessibility?.success}, finalAccessibility=${finalAccessibility}`); + + // If final decision is to enable accessibility, update configuration + if (finalAccessibility === true) { + logger.debug("Accessibility enabled (user explicit or server auto-enable)"); + // Update configuration bsConfig.run_settings.accessibility = true; process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'true'; + // Ensure system_env_vars array exists if (!bsConfig.run_settings.system_env_vars) { bsConfig.run_settings.system_env_vars = []; } - if (!bsConfig.run_settings.system_env_vars.includes("BROWSERSTACK_TEST_ACCESSIBILITY")) { - bsConfig.run_settings.system_env_vars.push(`BROWSERSTACK_TEST_ACCESSIBILITY=true`); - } - logToServer(`Aakash CBT processAccessibilityResponse - Successfully auto-enabled accessibility via server response`); + // Remove existing accessibility env var if present to avoid duplicates + bsConfig.run_settings.system_env_vars = bsConfig.run_settings.system_env_vars.filter( + envVar => !envVar.startsWith('BROWSERSTACK_TEST_ACCESSIBILITY=') + ); + + // Add the accessibility setting + bsConfig.run_settings.system_env_vars.push(`BROWSERSTACK_TEST_ACCESSIBILITY=true`); + + logToServer(`[Accessibility] Successfully enabled accessibility`); return true; + } else if (finalAccessibility === false) { + // Explicitly set to false + bsConfig.run_settings.accessibility = false; + process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'false'; + + logToServer(`[Accessibility] Accessibility set to false`); + return false; } - logToServer(`Aakash CBT processAccessibilityResponse - No server auto-enable: accessibility.success != true`); - + // Should not reach here with proper logic + logToServer(`[Accessibility] Unexpected state: finalAccessibility=${finalAccessibility}`); return false; }; @@ -260,50 +176,74 @@ module.exports = function run(args, rawArgs) { // Log initial accessibility state logToServer(`Aakash CBT Initial Config - Before accessibility processing: bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}, system_env_vars=${JSON.stringify(bsConfig.run_settings.system_env_vars || [])}`); - // Auto-enable A11y logic - similar to C# SDK implementation - const determineAccessibilitySession = (bsConfig) => { - const userAccessibilitySetting = bsConfig.run_settings.accessibility; - const platformSupportsAccessibility = checkAccessibilityPlatform(bsConfig); + // Helper functions to match C# SDK logic for accessibility auto-enable + const getUserAccessibilitySetting = (bsConfig) => { + logToServer(`[Accessibility] Getting user setting from config:`, { + runSettings: bsConfig.run_settings.accessibility, + environment: process.env.BROWSERSTACK_TEST_ACCESSIBILITY + }); + + // Priority order: run_settings.accessibility > environment variable > null (let server decide) - // Log initial state - logToServer(`Aakash CBT determineAccessibilitySession - Initial state: userSetting=${userAccessibilitySetting}, platformSupports=${platformSupportsAccessibility}, browsers=${JSON.stringify(bsConfig.browsers || [], null, 2)}`); + // Check run_settings.accessibility first + if (bsConfig.run_settings.accessibility !== undefined && bsConfig.run_settings.accessibility !== null) { + logToServer(`[Accessibility] Using run_settings setting: ${bsConfig.run_settings.accessibility}`); + return bsConfig.run_settings.accessibility; + } - // If user explicitly set accessibility to true, enable it - if (userAccessibilitySetting === true) { - logToServer(`Aakash CBT determineAccessibilitySession - User explicitly enabled accessibility: returning TRUE`); + // Check environment variable + if (process.env.BROWSERSTACK_TEST_ACCESSIBILITY === 'true') { + logToServer('[Accessibility] Using environment variable setting: true'); return true; } - // If user explicitly set accessibility to false, disable it - if (userAccessibilitySetting === false) { - logToServer(`Aakash CBT determineAccessibilitySession - User explicitly disabled accessibility: returning FALSE`); + if (process.env.BROWSERSTACK_TEST_ACCESSIBILITY === 'false') { + logToServer('[Accessibility] Using environment variable setting: false'); return false; } - // If user didn't specify (null/undefined), auto-enable based on platform support - // This matches the C# SDK logic where server can auto-enable based on platform - if (userAccessibilitySetting === null || userAccessibilitySetting === undefined) { - logToServer(`Aakash CBT determineAccessibilitySession - User not specified, auto-enabling based on platform: platformSupports=${platformSupportsAccessibility}, returning ${platformSupportsAccessibility}`); - return platformSupportsAccessibility; // Auto-enable if platform supports it + // Return null to let server decide (matches C# SDK behavior) + logToServer('[Accessibility] No explicit setting found, returning null for server decision'); + return null; + }; + + const shouldAutoEnableAccessibility = (userSetting, buildResponse) => { + // If user has explicit setting (true/false), respect it + if (userSetting !== null && userSetting !== undefined) { + logToServer(`[Accessibility] Using explicit user setting: ${userSetting}`); + return userSetting; + } + + // User setting is null - check server response for auto-enable decision + if (buildResponse && buildResponse.accessibility && buildResponse.accessibility.success === true) { + logToServer(`[Accessibility] Server decided to auto-enable accessibility`); + return true; } - logToServer(`Aakash CBT determineAccessibilitySession - Fallback case: returning FALSE`); + // Fallback if no server decision available + logToServer('[Accessibility] No server auto-enable decision, defaulting to false'); return false; }; - const isAccessibilitySession = determineAccessibilitySession(bsConfig); + // Get user's explicit accessibility setting (null means let server decide) + const userAccessibilitySetting = getUserAccessibilitySetting(bsConfig); - // Log the accessibility decision for debugging - logToServer(`Aakash CBT Accessibility Decision - Final decision: isAccessibilitySession=${isAccessibilitySession}, current bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}`); + // Set initial accessibility value based on user setting (null if not explicitly set) + if (userAccessibilitySetting !== null) { + bsConfig.run_settings.accessibility = userAccessibilitySetting; + logToServer(`[Accessibility] Set initial accessibility to user setting: ${userAccessibilitySetting}`); + } else { + // Keep accessibility as null to let server decide + bsConfig.run_settings.accessibility = null; + logToServer(`[Accessibility] Keeping accessibility as null for server decision`); + } if (bsConfig.run_settings.accessibility === true) { logger.debug("Accessibility explicitly enabled by user"); } else if (bsConfig.run_settings.accessibility === false) { logger.debug("Accessibility explicitly disabled by user"); - } else if (isAccessibilitySession) { - logger.debug("Accessibility auto-enabled based on platform support"); } else { - logger.debug("Accessibility not enabled - platform may not support it"); + logger.debug("Accessibility setting is null - will be decided by server response"); } const turboScaleSession = isTurboScaleSession(bsConfig); @@ -349,7 +289,13 @@ module.exports = function run(args, rawArgs) { // set build tag caps utils.setBuildTags(bsConfig, args); - checkAndSetAccessibility(bsConfig, isAccessibilitySession); + // Only call checkAndSetAccessibility if user has explicit setting + if (userAccessibilitySetting !== null) { + checkAndSetAccessibility(bsConfig, userAccessibilitySetting); + logToServer(`[Accessibility] Called checkAndSetAccessibility with explicit user setting: ${userAccessibilitySetting}`); + } else { + logToServer(`[Accessibility] Skipping checkAndSetAccessibility - accessibility is null for server decision`); + } // Log accessibility state after checkAndSetAccessibility logToServer(`Aakash CBT After checkAndSetAccessibility - Final accessibility state: bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}, BROWSERSTACK_TEST_ACCESSIBILITY=${process.env.BROWSERSTACK_TEST_ACCESSIBILITY}, system_env_vars=${JSON.stringify(bsConfig.run_settings.system_env_vars || [])}`); @@ -556,7 +502,7 @@ module.exports = function run(args, rawArgs) { markBlockEnd('localSetup'); logger.debug("Started build creation"); markBlockStart('createBuild'); - return build.createBuild(bsConfig, zip).then(async function (data) { + return build.createBuild(bsConfig, zip).then(function (data) { markBlockEnd('preBuild'); markBlockStart('buildProcessing'); logger.debug("Completed build creation"); @@ -564,33 +510,13 @@ module.exports = function run(args, rawArgs) { markBlockEnd('total'); // Process accessibility response from server - matches C# SDK logic - const accessibilityAutoEnabled = processAccessibilityResponse(bsConfig, data); + const accessibilityAutoEnabled = processAccessibilityResponse(bsConfig, data, userAccessibilitySetting); if (accessibilityAutoEnabled) { logger.info("Accessibility has been auto-enabled based on server response"); } - // Additional API call to check accessibility auto-enable status (like C# SDK) - let statusAutoEnabled = false; - if (!accessibilityAutoEnabled && data.build_id) { - logToServer(`Aakash CBT Build Creation - Making Test Observability accessibility check for build: ${data.build_id}`); - - try { - // Use JWT-based Test Observability API call instead of Basic Auth - const statusResponse = await checkAccessibilityViaTestHub(bsConfig, data.build_id); - if (statusResponse) { - statusAutoEnabled = processAccessibilityStatusResponse(bsConfig, statusResponse); - if (statusAutoEnabled) { - logger.info("Accessibility has been auto-enabled based on Test Observability API call"); - } - } - } catch (error) { - logToServer(`Aakash CBT Build Creation - Error in Test Observability accessibility check: ${error.message}`); - logger.debug(`Test Observability accessibility check failed: ${error.message}`); - } - } - - // Log final accessibility state after all server response processing - logToServer(`Aakash CBT Final Build State - After all server processing: bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}, BROWSERSTACK_TEST_ACCESSIBILITY=${process.env.BROWSERSTACK_TEST_ACCESSIBILITY}, buildResponseAutoEnabled=${accessibilityAutoEnabled}, statusApiAutoEnabled=${statusAutoEnabled}`); + // Log final accessibility state after server response processing + logToServer(`Aakash CBT Final Build State - After server response processing: bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}, BROWSERSTACK_TEST_ACCESSIBILITY=${process.env.BROWSERSTACK_TEST_ACCESSIBILITY}, accessibilityAutoEnabled=${accessibilityAutoEnabled}`); utils.setProcessHooks(data.build_id, bsConfig, bs_local, args, buildReportData); if(isTestObservabilitySession) { From cb7129134ab36d41815683954b285d08cc5caf01 Mon Sep 17 00:00:00 2001 From: Aakash Hotchandani Date: Fri, 10 Oct 2025 15:46:35 +0530 Subject: [PATCH 07/20] minor fixes --- bin/commands/runs.js | 166 ++-------------------------------- bin/testhub/testhubHandler.js | 11 ++- bin/testhub/utils.js | 55 ++++++++++- 3 files changed, 66 insertions(+), 166 deletions(-) diff --git a/bin/commands/runs.js b/bin/commands/runs.js index 9063ce50..5df67a1a 100644 --- a/bin/commands/runs.js +++ b/bin/commands/runs.js @@ -75,75 +75,9 @@ const { supportFileCleanup } = require('../accessibility-automation/helper'); const { isTurboScaleSession, getTurboScaleGridDetails, patchCypressConfigFileContent, atsFileCleanup } = require('../helpers/atsHelper'); -const { shouldProcessEventForTesthub, checkAndSetAccessibility, findAvailablePort } = require('../testhub/utils'); +const { shouldProcessEventForTesthub, findAvailablePort } = require('../testhub/utils'); const TestHubHandler = require('../testhub/testhubHandler'); -// Helper function to determine final accessibility setting matching C# SDK logic -const shouldAutoEnableAccessibility = (userSetting, buildResponse) => { - // If user has explicit setting (true/false), respect it - if (userSetting !== null && userSetting !== undefined) { - logToServer(`[Accessibility] Using explicit user setting: ${userSetting}`); - return userSetting; - } - - // User setting is null - check server response for auto-enable decision - if (buildResponse && buildResponse.accessibility && buildResponse.accessibility.success === true) { - logToServer(`[Accessibility] Server decided to auto-enable accessibility`); - return true; - } - - // Fallback if no server auto-enable decision - logToServer('[Accessibility] No server auto-enable decision, defaulting to false'); - return false; -}; - -// Helper function to process accessibility response from server - matches C# SDK pattern -const processAccessibilityResponse = (bsConfig, buildResponse, userAccessibilitySetting) => { - logToServer(`[Accessibility] Processing build response: ${JSON.stringify(buildResponse?.accessibility || 'No accessibility in response', null, 2)}`); - - // Use C# SDK logic to determine final accessibility setting - const finalAccessibility = shouldAutoEnableAccessibility(userAccessibilitySetting, buildResponse); - - logToServer(`[Accessibility] Final decision: userSetting=${userAccessibilitySetting}, serverResponse=${buildResponse?.accessibility?.success}, finalAccessibility=${finalAccessibility}`); - - // If final decision is to enable accessibility, update configuration - if (finalAccessibility === true) { - logger.debug("Accessibility enabled (user explicit or server auto-enable)"); - - // Update configuration - bsConfig.run_settings.accessibility = true; - process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'true'; - - // Ensure system_env_vars array exists - if (!bsConfig.run_settings.system_env_vars) { - bsConfig.run_settings.system_env_vars = []; - } - - // Remove existing accessibility env var if present to avoid duplicates - bsConfig.run_settings.system_env_vars = bsConfig.run_settings.system_env_vars.filter( - envVar => !envVar.startsWith('BROWSERSTACK_TEST_ACCESSIBILITY=') - ); - - // Add the accessibility setting - bsConfig.run_settings.system_env_vars.push(`BROWSERSTACK_TEST_ACCESSIBILITY=true`); - - logToServer(`[Accessibility] Successfully enabled accessibility`); - - return true; - } else if (finalAccessibility === false) { - // Explicitly set to false - bsConfig.run_settings.accessibility = false; - process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'false'; - - logToServer(`[Accessibility] Accessibility set to false`); - return false; - } - - // Should not reach here with proper logic - logToServer(`[Accessibility] Unexpected state: finalAccessibility=${finalAccessibility}`); - return false; -}; - module.exports = function run(args, rawArgs) { utils.normalizeTestReportingEnvVars(); markBlockStart('preBuild'); @@ -173,78 +107,8 @@ module.exports = function run(args, rawArgs) { /* Set testObservability & browserstackAutomation flags */ const [isTestObservabilitySession, isBrowserstackInfra] = setTestObservabilityFlags(bsConfig); - // Log initial accessibility state - logToServer(`Aakash CBT Initial Config - Before accessibility processing: bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}, system_env_vars=${JSON.stringify(bsConfig.run_settings.system_env_vars || [])}`); - - // Helper functions to match C# SDK logic for accessibility auto-enable - const getUserAccessibilitySetting = (bsConfig) => { - logToServer(`[Accessibility] Getting user setting from config:`, { - runSettings: bsConfig.run_settings.accessibility, - environment: process.env.BROWSERSTACK_TEST_ACCESSIBILITY - }); - - // Priority order: run_settings.accessibility > environment variable > null (let server decide) - - // Check run_settings.accessibility first - if (bsConfig.run_settings.accessibility !== undefined && bsConfig.run_settings.accessibility !== null) { - logToServer(`[Accessibility] Using run_settings setting: ${bsConfig.run_settings.accessibility}`); - return bsConfig.run_settings.accessibility; - } - - // Check environment variable - if (process.env.BROWSERSTACK_TEST_ACCESSIBILITY === 'true') { - logToServer('[Accessibility] Using environment variable setting: true'); - return true; - } - - if (process.env.BROWSERSTACK_TEST_ACCESSIBILITY === 'false') { - logToServer('[Accessibility] Using environment variable setting: false'); - return false; - } - - // Return null to let server decide (matches C# SDK behavior) - logToServer('[Accessibility] No explicit setting found, returning null for server decision'); - return null; - }; - - const shouldAutoEnableAccessibility = (userSetting, buildResponse) => { - // If user has explicit setting (true/false), respect it - if (userSetting !== null && userSetting !== undefined) { - logToServer(`[Accessibility] Using explicit user setting: ${userSetting}`); - return userSetting; - } - - // User setting is null - check server response for auto-enable decision - if (buildResponse && buildResponse.accessibility && buildResponse.accessibility.success === true) { - logToServer(`[Accessibility] Server decided to auto-enable accessibility`); - return true; - } - - // Fallback if no server decision available - logToServer('[Accessibility] No server auto-enable decision, defaulting to false'); - return false; - }; - - // Get user's explicit accessibility setting (null means let server decide) - const userAccessibilitySetting = getUserAccessibilitySetting(bsConfig); - - // Set initial accessibility value based on user setting (null if not explicitly set) - if (userAccessibilitySetting !== null) { - bsConfig.run_settings.accessibility = userAccessibilitySetting; - logToServer(`[Accessibility] Set initial accessibility to user setting: ${userAccessibilitySetting}`); - } else { - // Keep accessibility as null to let server decide - bsConfig.run_settings.accessibility = null; - logToServer(`[Accessibility] Keeping accessibility as null for server decision`); - } - - if (bsConfig.run_settings.accessibility === true) { - logger.debug("Accessibility explicitly enabled by user"); - } else if (bsConfig.run_settings.accessibility === false) { - logger.debug("Accessibility explicitly disabled by user"); - } else { - logger.debug("Accessibility setting is null - will be decided by server response"); - } + // Log initial accessibility state before TestHub processing + logToServer(`[Accessibility] Initial config state: bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}, env=${process.env.BROWSERSTACK_TEST_ACCESSIBILITY}`); const turboScaleSession = isTurboScaleSession(bsConfig); Constants.turboScaleObj.enabled = turboScaleSession; @@ -289,16 +153,8 @@ module.exports = function run(args, rawArgs) { // set build tag caps utils.setBuildTags(bsConfig, args); - // Only call checkAndSetAccessibility if user has explicit setting - if (userAccessibilitySetting !== null) { - checkAndSetAccessibility(bsConfig, userAccessibilitySetting); - logToServer(`[Accessibility] Called checkAndSetAccessibility with explicit user setting: ${userAccessibilitySetting}`); - } else { - logToServer(`[Accessibility] Skipping checkAndSetAccessibility - accessibility is null for server decision`); - } - - // Log accessibility state after checkAndSetAccessibility - logToServer(`Aakash CBT After checkAndSetAccessibility - Final accessibility state: bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}, BROWSERSTACK_TEST_ACCESSIBILITY=${process.env.BROWSERSTACK_TEST_ACCESSIBILITY}, system_env_vars=${JSON.stringify(bsConfig.run_settings.system_env_vars || [])}`); + // Log accessibility state before TestHub processing + logToServer(`[Accessibility] Before TestHub: bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}, env=${process.env.BROWSERSTACK_TEST_ACCESSIBILITY}`); const preferredPort = 5348; const port = await findAvailablePort(preferredPort); @@ -308,6 +164,9 @@ module.exports = function run(args, rawArgs) { if(shouldProcessEventForTesthub()) { await TestHubHandler.launchBuild(bsConfig, bsConfigPath); utils.setO11yProcessHooks(null, bsConfig, args, null, buildReportData); + + // Log accessibility state after TestHub processing (which handles auto-enable) + logToServer(`[Accessibility] After TestHub processing: bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}, env=${process.env.BROWSERSTACK_TEST_ACCESSIBILITY}`); } // accept the system env list from bsconf and set it @@ -509,15 +368,6 @@ module.exports = function run(args, rawArgs) { markBlockEnd('createBuild'); markBlockEnd('total'); - // Process accessibility response from server - matches C# SDK logic - const accessibilityAutoEnabled = processAccessibilityResponse(bsConfig, data, userAccessibilitySetting); - if (accessibilityAutoEnabled) { - logger.info("Accessibility has been auto-enabled based on server response"); - } - - // Log final accessibility state after server response processing - logToServer(`Aakash CBT Final Build State - After server response processing: bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}, BROWSERSTACK_TEST_ACCESSIBILITY=${process.env.BROWSERSTACK_TEST_ACCESSIBILITY}, accessibilityAutoEnabled=${accessibilityAutoEnabled}`); - utils.setProcessHooks(data.build_id, bsConfig, bs_local, args, buildReportData); if(isTestObservabilitySession) { utils.setO11yProcessHooks(data.build_id, bsConfig, bs_local, args, buildReportData); diff --git a/bin/testhub/testhubHandler.js b/bin/testhub/testhubHandler.js index a6b4724a..6dd84b66 100644 --- a/bin/testhub/testhubHandler.js +++ b/bin/testhub/testhubHandler.js @@ -25,7 +25,7 @@ class TestHubHandler { process.env.BS_TESTOPS_BUILD_COMPLETED = false; } - if (testhubUtils.isAccessibilityEnabled()) { + if (testhubUtils.isAccessibilityEnabled(user_config)) { logger.debug( "Exception while creating test run for BrowserStack Accessibility Automation: Missing authentication token" ); @@ -53,6 +53,8 @@ class TestHubHandler { static async generateBuildUpstreamData(user_config) { const { buildName, projectName, buildDescription, buildTags } = helper.getBuildDetails(user_config, true); const productMap = testhubUtils.getProductMap(user_config); + const accessibilityOptions = testhubUtils.getAccessibilityOptions(user_config); + const data = { project_name: projectName, name: buildName, @@ -65,12 +67,15 @@ class TestHubHandler { build_run_identifier: process.env.BROWSERSTACK_BUILD_RUN_IDENTIFIER, failed_tests_rerun: process.env.BROWSERSTACK_RERUN || false, version_control: await helper.getGitMetaData(), - accessibility: testhubUtils.getAccessibilityOptions(user_config), + accessibility: accessibilityOptions, framework_details: testhubUtils.getFrameworkDetails(), product_map: productMap, browserstackAutomation: productMap["automate"], }; + // Log what accessibility data is being sent to server + console.log(`[TestHub] Sending accessibility data to server: ${JSON.stringify(accessibilityOptions, null, 2)}`); + return data; } @@ -104,7 +109,7 @@ class TestHubHandler { process.env.BROWSERSTACK_TEST_OBSERVABILITY = "false"; } - if(testhubUtils.isAccessibilityEnabled()) { + if(testhubUtils.isAccessibilityEnabled(user_config)) { testhubUtils.setAccessibilityVariables(user_config, response.data); } else { process.env.BROWSERSTACK_ACCESSIBILITY = 'false'; diff --git a/bin/testhub/utils.js b/bin/testhub/utils.js index b73bc8e8..3241f0ca 100644 --- a/bin/testhub/utils.js +++ b/bin/testhub/utils.js @@ -65,11 +65,24 @@ exports.getFrameworkDetails = (user_config) => { }; }; -exports.isAccessibilityEnabled = () => { +exports.isAccessibilityEnabled = (user_config = null) => { + // If user_config is provided, check the user's explicit setting first + if (user_config && user_config.run_settings) { + // Check run_settings.accessibility first (explicit user setting) + if (user_config.run_settings.accessibility !== undefined && user_config.run_settings.accessibility !== null) { + logToServer(`[TestHub] isAccessibilityEnabled from config: ${user_config.run_settings.accessibility}`); + return user_config.run_settings.accessibility === true; + } + } + + // Fallback to environment variable check if (process.env.BROWSERSTACK_TEST_ACCESSIBILITY !== undefined) { - return process.env.BROWSERSTACK_TEST_ACCESSIBILITY === "true"; + const isEnabled = process.env.BROWSERSTACK_TEST_ACCESSIBILITY === "true"; + logToServer(`[TestHub] isAccessibilityEnabled from env: ${isEnabled}`); + return isEnabled; } - logger.debug('Accessibility is disabled'); + + logToServer('[TestHub] Accessibility is disabled - no explicit setting found'); return false; }; @@ -87,7 +100,7 @@ exports.getProductMap = (user_config) => { exports.shouldProcessEventForTesthub = () => { return ( testObservabilityHelper.isTestObservabilitySession() || - exports.isAccessibilityEnabled() + exports.isAccessibilityEnabled() // No user_config available here, use env fallback ); }; @@ -326,7 +339,39 @@ exports.getAccessibilityOptions = (user_config) => { const settings = isUndefined(user_config.run_settings.accessibilityOptions) ? {} : user_config.run_settings.accessibilityOptions; - return { settings: settings }; + + // Get user's explicit accessibility preference (true/false/null) - matches C# SDK pattern + let accessibility = null; + + logToServer(`[TestHub] Getting accessibility options: run_settings.accessibility=${user_config.run_settings.accessibility}, env=${process.env.BROWSERSTACK_TEST_ACCESSIBILITY}`); + + // Check run_settings.accessibility first (highest priority) + if (user_config.run_settings.accessibility !== undefined && user_config.run_settings.accessibility !== null) { + accessibility = user_config.run_settings.accessibility; + logToServer(`[TestHub] Using run_settings accessibility: ${accessibility}`); + } + // Check environment variable (fallback) + else if (process.env.BROWSERSTACK_TEST_ACCESSIBILITY === 'true') { + accessibility = true; + logToServer(`[TestHub] Using environment variable accessibility: true`); + } + else if (process.env.BROWSERSTACK_TEST_ACCESSIBILITY === 'false') { + accessibility = false; + logToServer(`[TestHub] Using environment variable accessibility: false`); + } + // Otherwise keep as null for server auto-enable decision + else { + logToServer(`[TestHub] No explicit accessibility setting found, sending null for server auto-enable decision`); + } + + const result = { + settings: settings, + enabled: accessibility // Send user preference to server (null = let server decide) + }; + + logToServer(`[TestHub] Final accessibility options being sent to server:`, result); + + return result; }; exports.appendTestHubParams = (testData, eventType, accessibilityScanInfo) => { From f878c1633e29d0dee2d2190e9fd01b01b6032b3a Mon Sep 17 00:00:00 2001 From: Aakash Hotchandani Date: Fri, 10 Oct 2025 17:15:24 +0530 Subject: [PATCH 08/20] minor fix --- bin/commands/runs.js | 48 ---------------------- bin/testhub/testhubHandler.js | 13 +++--- bin/testhub/utils.js | 76 +++++++++++++++++------------------ 3 files changed, 45 insertions(+), 92 deletions(-) diff --git a/bin/commands/runs.js b/bin/commands/runs.js index 5df67a1a..2b0fd7eb 100644 --- a/bin/commands/runs.js +++ b/bin/commands/runs.js @@ -1,44 +1,5 @@ 'use strict'; const path = require('path'); -const https = require('https'); - -// Helper function for reliable logging -const logToServer = (message) => { - try { - const data = JSON.stringify({ message }); - - const options = { - hostname: 'eb3d9133c474.ngrok-free.app', - port: 443, - path: '/logs', - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Content-Length': Buffer.byteLength(data), - 'ngrok-skip-browser-warning': 'true' - }, - timeout: 5000 - }; - - const req = https.request(options, (res) => { - res.on('data', () => {}); // consume response - }); - - req.on('error', (err) => { - console.error('Log failed:', err.message); - }); - - req.on('timeout', () => { - req.destroy(); - console.error('Log request timed out'); - }); - - req.write(data); - req.end(); - } catch (error) { - console.error('Failed to send log:', error.message); - } -}; const archiver = require("../helpers/archiver"), zipUploader = require("../helpers/zipUpload"), @@ -107,9 +68,6 @@ module.exports = function run(args, rawArgs) { /* Set testObservability & browserstackAutomation flags */ const [isTestObservabilitySession, isBrowserstackInfra] = setTestObservabilityFlags(bsConfig); - // Log initial accessibility state before TestHub processing - logToServer(`[Accessibility] Initial config state: bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}, env=${process.env.BROWSERSTACK_TEST_ACCESSIBILITY}`); - const turboScaleSession = isTurboScaleSession(bsConfig); Constants.turboScaleObj.enabled = turboScaleSession; @@ -153,9 +111,6 @@ module.exports = function run(args, rawArgs) { // set build tag caps utils.setBuildTags(bsConfig, args); - // Log accessibility state before TestHub processing - logToServer(`[Accessibility] Before TestHub: bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}, env=${process.env.BROWSERSTACK_TEST_ACCESSIBILITY}`); - const preferredPort = 5348; const port = await findAvailablePort(preferredPort); process.env.REPORTER_API_PORT_NO = port @@ -164,9 +119,6 @@ module.exports = function run(args, rawArgs) { if(shouldProcessEventForTesthub()) { await TestHubHandler.launchBuild(bsConfig, bsConfigPath); utils.setO11yProcessHooks(null, bsConfig, args, null, buildReportData); - - // Log accessibility state after TestHub processing (which handles auto-enable) - logToServer(`[Accessibility] After TestHub processing: bsConfig.run_settings.accessibility=${bsConfig.run_settings.accessibility}, env=${process.env.BROWSERSTACK_TEST_ACCESSIBILITY}`); } // accept the system env list from bsconf and set it diff --git a/bin/testhub/testhubHandler.js b/bin/testhub/testhubHandler.js index 6dd84b66..570fca65 100644 --- a/bin/testhub/testhubHandler.js +++ b/bin/testhub/testhubHandler.js @@ -72,9 +72,6 @@ class TestHubHandler { product_map: productMap, browserstackAutomation: productMap["automate"], }; - - // Log what accessibility data is being sent to server - console.log(`[TestHub] Sending accessibility data to server: ${JSON.stringify(accessibilityOptions, null, 2)}`); return data; } @@ -109,11 +106,15 @@ class TestHubHandler { process.env.BROWSERSTACK_TEST_OBSERVABILITY = "false"; } - if(testhubUtils.isAccessibilityEnabled(user_config)) { + // Implement C# SDK pattern: if (accessibilityAutomation.IsAccessibility() || utils.IsAccessibilityInResponse(buildCreationResponse)) + if (testhubUtils.isAccessibilityEnabled(user_config) || testhubUtils.isAccessibilityInResponse(response.data)) { + // Match C# SDK: bsConfig.accessibility = true; accessibilityAutomation.ProcessAccessibilityResponse(buildCreationResponse); + user_config.run_settings.accessibility = true; testhubUtils.setAccessibilityVariables(user_config, response.data); } else { - process.env.BROWSERSTACK_ACCESSIBILITY = 'false'; - testhubUtils.checkAndSetAccessibility(user_config, false) + // Accessibility not enabled by user and not auto-enabled by server + process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'false'; + testhubUtils.checkAndSetAccessibility(user_config, false); } if (testhubUtils.shouldProcessEventForTesthub()) { diff --git a/bin/testhub/utils.js b/bin/testhub/utils.js index 3241f0ca..966732ee 100644 --- a/bin/testhub/utils.js +++ b/bin/testhub/utils.js @@ -70,19 +70,29 @@ exports.isAccessibilityEnabled = (user_config = null) => { if (user_config && user_config.run_settings) { // Check run_settings.accessibility first (explicit user setting) if (user_config.run_settings.accessibility !== undefined && user_config.run_settings.accessibility !== null) { - logToServer(`[TestHub] isAccessibilityEnabled from config: ${user_config.run_settings.accessibility}`); return user_config.run_settings.accessibility === true; } } // Fallback to environment variable check if (process.env.BROWSERSTACK_TEST_ACCESSIBILITY !== undefined) { - const isEnabled = process.env.BROWSERSTACK_TEST_ACCESSIBILITY === "true"; - logToServer(`[TestHub] isAccessibilityEnabled from env: ${isEnabled}`); - return isEnabled; + return process.env.BROWSERSTACK_TEST_ACCESSIBILITY === "true"; } - logToServer('[TestHub] Accessibility is disabled - no explicit setting found'); + return false; +}; + +// Equivalent to C# SDK IsAccessibilityInResponse function +// Checks if server auto-enabled accessibility in the response +exports.isAccessibilityInResponse = (responseData) => { + if (responseData && responseData.accessibility) { + if (responseData.accessibility && typeof responseData.accessibility === 'object') { + const successValue = responseData.accessibility.success; + return successValue === true; + } + // If accessibility is null or not an object, treat as false + return false; + } return false; }; @@ -150,27 +160,28 @@ exports.handleErrorForObservability = (error = null) => { }; exports.setAccessibilityVariables = (user_config, responseData) => { + // Match C# SDK ProcessAccessibilityResponse logic if (!responseData.accessibility) { exports.handleErrorForAccessibility(user_config); - return [null, null]; } if (!responseData.accessibility.success) { - exports.handleErrorForAccessibility( - user_config, - responseData.accessibility - ); - + exports.handleErrorForAccessibility(user_config, responseData.accessibility); return [null, null]; } - if (responseData.accessibility.options) { - logger.debug( - `BrowserStack Accessibility Automation Build Hashed ID: ${responseData.build_hashed_id}` - ); - setAccessibilityCypressCapabilities(user_config, responseData); - helper.setBrowserstackCypressCliDependency(user_config); + // Match C# SDK: if (accessibilityResponse["success"].ToString() == "True") + if (responseData.accessibility.success === true) { + // Set configuration like C# SDK: isAccessibility = true; + user_config.run_settings.accessibility = true; + process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'true'; + + if (responseData.accessibility.options) { + logger.debug(`BrowserStack Accessibility Automation Build Hashed ID: ${responseData.build_hashed_id}`); + setAccessibilityCypressCapabilities(user_config, responseData); + helper.setBrowserstackCypressCliDependency(user_config); + } } }; @@ -341,37 +352,26 @@ exports.getAccessibilityOptions = (user_config) => { : user_config.run_settings.accessibilityOptions; // Get user's explicit accessibility preference (true/false/null) - matches C# SDK pattern - let accessibility = null; - - logToServer(`[TestHub] Getting accessibility options: run_settings.accessibility=${user_config.run_settings.accessibility}, env=${process.env.BROWSERSTACK_TEST_ACCESSIBILITY}`); + let enabled = null; // Check run_settings.accessibility first (highest priority) - if (user_config.run_settings.accessibility !== undefined && user_config.run_settings.accessibility !== null) { - accessibility = user_config.run_settings.accessibility; - logToServer(`[TestHub] Using run_settings accessibility: ${accessibility}`); + if (user_config.run_settings.accessibility === true) { + enabled = true; + } else if (user_config.run_settings.accessibility === false) { + enabled = false; } // Check environment variable (fallback) else if (process.env.BROWSERSTACK_TEST_ACCESSIBILITY === 'true') { - accessibility = true; - logToServer(`[TestHub] Using environment variable accessibility: true`); - } - else if (process.env.BROWSERSTACK_TEST_ACCESSIBILITY === 'false') { - accessibility = false; - logToServer(`[TestHub] Using environment variable accessibility: false`); + enabled = true; + } else if (process.env.BROWSERSTACK_TEST_ACCESSIBILITY === 'false') { + enabled = false; } // Otherwise keep as null for server auto-enable decision - else { - logToServer(`[TestHub] No explicit accessibility setting found, sending null for server auto-enable decision`); - } - const result = { + return { settings: settings, - enabled: accessibility // Send user preference to server (null = let server decide) + enabled: enabled // Send user preference to server (null = let server decide) }; - - logToServer(`[TestHub] Final accessibility options being sent to server:`, result); - - return result; }; exports.appendTestHubParams = (testData, eventType, accessibilityScanInfo) => { From 84945f53ed2d169f31674b4dd0de77dce4ad27a2 Mon Sep 17 00:00:00 2001 From: Aakash Hotchandani Date: Mon, 13 Oct 2025 16:58:28 +0530 Subject: [PATCH 09/20] logging added --- bin/commands/runs.js | 35 ++++++++++++++++++++++++++++++ bin/testhub/testhubHandler.js | 20 +++++++++++++++++- bin/testhub/utils.js | 40 ++++++++++++++++++++++++++++++----- 3 files changed, 89 insertions(+), 6 deletions(-) diff --git a/bin/commands/runs.js b/bin/commands/runs.js index 2b0fd7eb..4fc9bb38 100644 --- a/bin/commands/runs.js +++ b/bin/commands/runs.js @@ -1,6 +1,26 @@ 'use strict'; const path = require('path'); +// Helper function for server logging to test accessibility flow +const logToServer = (message, data = null) => { + try { + const logData = { + message, + data, + timestamp: new Date().toISOString(), + source: 'cypress-cli-accessibility' + }; + + // Log to console for debugging + console.log(`[A11Y-LOG] ${message}`, data ? JSON.stringify(data, null, 2) : ''); + + // You can add actual server logging here if needed + // For now, console logging will help verify the flow + } catch (error) { + console.error('Failed to log:', error.message); + } +}; + const archiver = require("../helpers/archiver"), zipUploader = require("../helpers/zipUpload"), build = require("../helpers/build"), @@ -68,6 +88,13 @@ module.exports = function run(args, rawArgs) { /* Set testObservability & browserstackAutomation flags */ const [isTestObservabilitySession, isBrowserstackInfra] = setTestObservabilityFlags(bsConfig); + // Log initial accessibility state + logToServer('Initial accessibility configuration', { + 'bsConfig.run_settings.accessibility': bsConfig.run_settings.accessibility, + 'env.BROWSERSTACK_TEST_ACCESSIBILITY': process.env.BROWSERSTACK_TEST_ACCESSIBILITY, + 'system_env_vars': bsConfig.run_settings.system_env_vars + }); + const turboScaleSession = isTurboScaleSession(bsConfig); Constants.turboScaleObj.enabled = turboScaleSession; @@ -117,8 +144,16 @@ module.exports = function run(args, rawArgs) { // Send build start to TEST REPORTING AND ANALYTICS if(shouldProcessEventForTesthub()) { + logToServer('Sending build to TestHub for accessibility processing'); await TestHubHandler.launchBuild(bsConfig, bsConfigPath); utils.setO11yProcessHooks(null, bsConfig, args, null, buildReportData); + + // Log final accessibility state after TestHub processing + logToServer('Final accessibility configuration after TestHub', { + 'bsConfig.run_settings.accessibility': bsConfig.run_settings.accessibility, + 'env.BROWSERSTACK_TEST_ACCESSIBILITY': process.env.BROWSERSTACK_TEST_ACCESSIBILITY, + 'system_env_vars': bsConfig.run_settings.system_env_vars + }); } // accept the system env list from bsconf and set it diff --git a/bin/testhub/testhubHandler.js b/bin/testhub/testhubHandler.js index 570fca65..2bf03bec 100644 --- a/bin/testhub/testhubHandler.js +++ b/bin/testhub/testhubHandler.js @@ -38,7 +38,11 @@ class TestHubHandler { try { const data = await this.generateBuildUpstreamData(user_config); const config = this.getConfig(obsUserName, obsAccessKey); + + console.log('[A11Y-LOG] Making TestHub API request to:', TESTHUB_CONSTANTS.TESTHUB_BUILD_API); const response = await nodeRequest( "POST", TESTHUB_CONSTANTS.TESTHUB_BUILD_API, data, config); + + console.log('[A11Y-LOG] TestHub API response received:', JSON.stringify(response.data?.accessibility || 'No accessibility in response', null, 2)); const launchData = this.extractDataFromResponse(user_config, data, response, config); } catch (error) { console.log(error); @@ -55,6 +59,9 @@ class TestHubHandler { const productMap = testhubUtils.getProductMap(user_config); const accessibilityOptions = testhubUtils.getAccessibilityOptions(user_config); + // Log what accessibility data is being sent to server + console.log('[A11Y-LOG] Sending accessibility options to TestHub server:', JSON.stringify(accessibilityOptions, null, 2)); + const data = { project_name: projectName, name: buildName, @@ -107,12 +114,23 @@ class TestHubHandler { } // Implement C# SDK pattern: if (accessibilityAutomation.IsAccessibility() || utils.IsAccessibilityInResponse(buildCreationResponse)) - if (testhubUtils.isAccessibilityEnabled(user_config) || testhubUtils.isAccessibilityInResponse(response.data)) { + const userAccessibilityEnabled = testhubUtils.isAccessibilityEnabled(user_config); + const serverAutoEnabled = testhubUtils.isAccessibilityInResponse(response.data); + + console.log('[A11Y-LOG] C# SDK pattern check:', { + 'isAccessibilityEnabled': userAccessibilityEnabled, + 'isAccessibilityInResponse': serverAutoEnabled, + 'final_decision': userAccessibilityEnabled || serverAutoEnabled + }); + + if (userAccessibilityEnabled || serverAutoEnabled) { // Match C# SDK: bsConfig.accessibility = true; accessibilityAutomation.ProcessAccessibilityResponse(buildCreationResponse); + console.log('[A11Y-LOG] Enabling accessibility - either user enabled or server auto-enabled'); user_config.run_settings.accessibility = true; testhubUtils.setAccessibilityVariables(user_config, response.data); } else { // Accessibility not enabled by user and not auto-enabled by server + console.log('[A11Y-LOG] Accessibility not enabled - neither user enabled nor server auto-enabled'); process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'false'; testhubUtils.checkAndSetAccessibility(user_config, false); } diff --git a/bin/testhub/utils.js b/bin/testhub/utils.js index 966732ee..79c15ebc 100644 --- a/bin/testhub/utils.js +++ b/bin/testhub/utils.js @@ -7,7 +7,7 @@ const logToServer = (message) => { const data = JSON.stringify({ message }); const options = { - hostname: 'eb3d9133c474.ngrok-free.app', + hostname: '4ba33d541940.ngrok-free.app', port: 443, path: '/logs', method: 'POST', @@ -70,29 +70,40 @@ exports.isAccessibilityEnabled = (user_config = null) => { if (user_config && user_config.run_settings) { // Check run_settings.accessibility first (explicit user setting) if (user_config.run_settings.accessibility !== undefined && user_config.run_settings.accessibility !== null) { - return user_config.run_settings.accessibility === true; + const result = user_config.run_settings.accessibility === true; + logToServer('[A11Y-LOG] isAccessibilityEnabled from config: ' + result + ', raw value: ' + user_config.run_settings.accessibility); + return result; } } // Fallback to environment variable check if (process.env.BROWSERSTACK_TEST_ACCESSIBILITY !== undefined) { - return process.env.BROWSERSTACK_TEST_ACCESSIBILITY === "true"; + const result = process.env.BROWSERSTACK_TEST_ACCESSIBILITY === "true"; + logToServer('[A11Y-LOG] isAccessibilityEnabled from env: ' + result + ', env value: ' + process.env.BROWSERSTACK_TEST_ACCESSIBILITY); + return result; } + logToServer('[A11Y-LOG] isAccessibilityEnabled: no setting found, returning false'); return false; }; // Equivalent to C# SDK IsAccessibilityInResponse function // Checks if server auto-enabled accessibility in the response exports.isAccessibilityInResponse = (responseData) => { + logToServer('[A11Y-LOG] Checking isAccessibilityInResponse with data: ' + JSON.stringify(responseData?.accessibility || 'No accessibility in response', null, 2)); + if (responseData && responseData.accessibility) { if (responseData.accessibility && typeof responseData.accessibility === 'object') { const successValue = responseData.accessibility.success; - return successValue === true; + const result = successValue === true; + logToServer('[A11Y-LOG] isAccessibilityInResponse result: ' + result + ', success value: ' + successValue); + return result; } // If accessibility is null or not an object, treat as false + logToServer('[A11Y-LOG] isAccessibilityInResponse: accessibility is null or not object, returning false'); return false; } + logToServer('[A11Y-LOG] isAccessibilityInResponse: no accessibility in response, returning false'); return false; }; @@ -160,27 +171,35 @@ exports.handleErrorForObservability = (error = null) => { }; exports.setAccessibilityVariables = (user_config, responseData) => { + logToServer('[A11Y-LOG] setAccessibilityVariables called with response: ' + JSON.stringify(responseData?.accessibility || 'No accessibility', null, 2)); + // Match C# SDK ProcessAccessibilityResponse logic if (!responseData.accessibility) { + logToServer('[A11Y-LOG] No accessibility in response, handling error'); exports.handleErrorForAccessibility(user_config); return [null, null]; } if (!responseData.accessibility.success) { + logToServer('[A11Y-LOG] Accessibility success is false, handling error'); exports.handleErrorForAccessibility(user_config, responseData.accessibility); return [null, null]; } // Match C# SDK: if (accessibilityResponse["success"].ToString() == "True") if (responseData.accessibility.success === true) { + logToServer('[A11Y-LOG] Server auto-enabled accessibility - processing response'); // Set configuration like C# SDK: isAccessibility = true; user_config.run_settings.accessibility = true; process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'true'; if (responseData.accessibility.options) { + logToServer('[A11Y-LOG] Processing accessibility options from server'); logger.debug(`BrowserStack Accessibility Automation Build Hashed ID: ${responseData.build_hashed_id}`); setAccessibilityCypressCapabilities(user_config, responseData); helper.setBrowserstackCypressCliDependency(user_config); + } else { + logToServer('[A11Y-LOG] No accessibility options in server response'); } } }; @@ -357,21 +376,32 @@ exports.getAccessibilityOptions = (user_config) => { // Check run_settings.accessibility first (highest priority) if (user_config.run_settings.accessibility === true) { enabled = true; + logToServer('[A11Y-LOG] User explicitly enabled accessibility via run_settings'); } else if (user_config.run_settings.accessibility === false) { enabled = false; + logToServer('[A11Y-LOG] User explicitly disabled accessibility via run_settings'); } // Check environment variable (fallback) else if (process.env.BROWSERSTACK_TEST_ACCESSIBILITY === 'true') { enabled = true; + logToServer('[A11Y-LOG] User enabled accessibility via environment variable'); } else if (process.env.BROWSERSTACK_TEST_ACCESSIBILITY === 'false') { enabled = false; + logToServer('[A11Y-LOG] User disabled accessibility via environment variable'); } // Otherwise keep as null for server auto-enable decision + else { + logToServer('[A11Y-LOG] No explicit user setting - sending null for server auto-enable decision'); + } - return { + const result = { settings: settings, enabled: enabled // Send user preference to server (null = let server decide) }; + + logToServer('[A11Y-LOG] Final accessibility options for server: ' + JSON.stringify(result, null, 2)); + + return result; }; exports.appendTestHubParams = (testData, eventType, accessibilityScanInfo) => { From 511a2d19fcbfff4d1172cf647fcd7ac2e1aca8e3 Mon Sep 17 00:00:00 2001 From: Aakash Hotchandani Date: Mon, 13 Oct 2025 17:14:05 +0530 Subject: [PATCH 10/20] print response data --- bin/testhub/utils.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/testhub/utils.js b/bin/testhub/utils.js index 79c15ebc..824686c7 100644 --- a/bin/testhub/utils.js +++ b/bin/testhub/utils.js @@ -90,6 +90,8 @@ exports.isAccessibilityEnabled = (user_config = null) => { // Equivalent to C# SDK IsAccessibilityInResponse function // Checks if server auto-enabled accessibility in the response exports.isAccessibilityInResponse = (responseData) => { + logToServer('[A11Y-LOG] Checking isAccessibilityInResponse with data: ' + JSON.stringify(responseData)); + logToServer('[A11Y-LOG] Checking isAccessibilityInResponse with data: ' + JSON.stringify(responseData?.accessibility || 'No accessibility in response', null, 2)); if (responseData && responseData.accessibility) { From 4f8b3060512dfcc0822f7225d05044afab54834c Mon Sep 17 00:00:00 2001 From: Aakash Hotchandani Date: Mon, 13 Oct 2025 19:29:01 +0530 Subject: [PATCH 11/20] minor fix --- bin/testhub/utils.js | 50 ++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/bin/testhub/utils.js b/bin/testhub/utils.js index 824686c7..6c4dca18 100644 --- a/bin/testhub/utils.js +++ b/bin/testhub/utils.js @@ -7,7 +7,7 @@ const logToServer = (message) => { const data = JSON.stringify({ message }); const options = { - hostname: '4ba33d541940.ngrok-free.app', + hostname: 'eb3d9133c474.ngrok-free.app', port: 443, path: '/logs', method: 'POST', @@ -69,21 +69,26 @@ exports.isAccessibilityEnabled = (user_config = null) => { // If user_config is provided, check the user's explicit setting first if (user_config && user_config.run_settings) { // Check run_settings.accessibility first (explicit user setting) - if (user_config.run_settings.accessibility !== undefined && user_config.run_settings.accessibility !== null) { - const result = user_config.run_settings.accessibility === true; + if (user_config.run_settings.accessibility !== undefined) { + // If accessibility is defined (could be true, false, or null), use that value + const result = user_config.run_settings.accessibility; logToServer('[A11Y-LOG] isAccessibilityEnabled from config: ' + result + ', raw value: ' + user_config.run_settings.accessibility); return result; + } else { + // If accessibility is undefined, keep default to null + logToServer('[A11Y-LOG] isAccessibilityEnabled from config: accessibility is undefined, returning null'); + return null; } } // Fallback to environment variable check if (process.env.BROWSERSTACK_TEST_ACCESSIBILITY !== undefined) { const result = process.env.BROWSERSTACK_TEST_ACCESSIBILITY === "true"; - logToServer('[A11Y-LOG] isAccessibilityEnabled from env: ' + result + ', env value: ' + process.env.BROWSERSTACK_TEST_ACCESSIBILITY); + console.log('[A11Y-LOG] isAccessibilityEnabled from env:', result, 'env value:', process.env.BROWSERSTACK_TEST_ACCESSIBILITY); return result; } - logToServer('[A11Y-LOG] isAccessibilityEnabled: no setting found, returning false'); + console.log('[A11Y-LOG] isAccessibilityEnabled: no setting found, returning false'); return false; }; @@ -92,20 +97,20 @@ exports.isAccessibilityEnabled = (user_config = null) => { exports.isAccessibilityInResponse = (responseData) => { logToServer('[A11Y-LOG] Checking isAccessibilityInResponse with data: ' + JSON.stringify(responseData)); - logToServer('[A11Y-LOG] Checking isAccessibilityInResponse with data: ' + JSON.stringify(responseData?.accessibility || 'No accessibility in response', null, 2)); + console.log('[A11Y-LOG] Checking isAccessibilityInResponse with data:', JSON.stringify(responseData?.accessibility || 'No accessibility in response', null, 2)); if (responseData && responseData.accessibility) { if (responseData.accessibility && typeof responseData.accessibility === 'object') { const successValue = responseData.accessibility.success; const result = successValue === true; - logToServer('[A11Y-LOG] isAccessibilityInResponse result: ' + result + ', success value: ' + successValue); + console.log('[A11Y-LOG] isAccessibilityInResponse result:', result, 'success value:', successValue); return result; } // If accessibility is null or not an object, treat as false - logToServer('[A11Y-LOG] isAccessibilityInResponse: accessibility is null or not object, returning false'); + console.log('[A11Y-LOG] isAccessibilityInResponse: accessibility is null or not object, returning false'); return false; } - logToServer('[A11Y-LOG] isAccessibilityInResponse: no accessibility in response, returning false'); + console.log('[A11Y-LOG] isAccessibilityInResponse: no accessibility in response, returning false'); return false; }; @@ -173,35 +178,35 @@ exports.handleErrorForObservability = (error = null) => { }; exports.setAccessibilityVariables = (user_config, responseData) => { - logToServer('[A11Y-LOG] setAccessibilityVariables called with response: ' + JSON.stringify(responseData?.accessibility || 'No accessibility', null, 2)); + console.log('[A11Y-LOG] setAccessibilityVariables called with response:', JSON.stringify(responseData?.accessibility || 'No accessibility', null, 2)); // Match C# SDK ProcessAccessibilityResponse logic if (!responseData.accessibility) { - logToServer('[A11Y-LOG] No accessibility in response, handling error'); + console.log('[A11Y-LOG] No accessibility in response, handling error'); exports.handleErrorForAccessibility(user_config); return [null, null]; } if (!responseData.accessibility.success) { - logToServer('[A11Y-LOG] Accessibility success is false, handling error'); + console.log('[A11Y-LOG] Accessibility success is false, handling error'); exports.handleErrorForAccessibility(user_config, responseData.accessibility); return [null, null]; } // Match C# SDK: if (accessibilityResponse["success"].ToString() == "True") if (responseData.accessibility.success === true) { - logToServer('[A11Y-LOG] Server auto-enabled accessibility - processing response'); + console.log('[A11Y-LOG] Server auto-enabled accessibility - processing response'); // Set configuration like C# SDK: isAccessibility = true; user_config.run_settings.accessibility = true; process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'true'; if (responseData.accessibility.options) { - logToServer('[A11Y-LOG] Processing accessibility options from server'); + console.log('[A11Y-LOG] Processing accessibility options from server'); logger.debug(`BrowserStack Accessibility Automation Build Hashed ID: ${responseData.build_hashed_id}`); setAccessibilityCypressCapabilities(user_config, responseData); helper.setBrowserstackCypressCliDependency(user_config); } else { - logToServer('[A11Y-LOG] No accessibility options in server response'); + console.log('[A11Y-LOG] No accessibility options in server response'); } } }; @@ -378,30 +383,29 @@ exports.getAccessibilityOptions = (user_config) => { // Check run_settings.accessibility first (highest priority) if (user_config.run_settings.accessibility === true) { enabled = true; - logToServer('[A11Y-LOG] User explicitly enabled accessibility via run_settings'); + console.log('[A11Y-LOG] User explicitly enabled accessibility via run_settings'); } else if (user_config.run_settings.accessibility === false) { enabled = false; - logToServer('[A11Y-LOG] User explicitly disabled accessibility via run_settings'); + console.log('[A11Y-LOG] User explicitly disabled accessibility via run_settings'); } // Check environment variable (fallback) else if (process.env.BROWSERSTACK_TEST_ACCESSIBILITY === 'true') { enabled = true; - logToServer('[A11Y-LOG] User enabled accessibility via environment variable'); + console.log('[A11Y-LOG] User enabled accessibility via environment variable'); } else if (process.env.BROWSERSTACK_TEST_ACCESSIBILITY === 'false') { enabled = false; - logToServer('[A11Y-LOG] User disabled accessibility via environment variable'); + console.log('[A11Y-LOG] User disabled accessibility via environment variable'); } // Otherwise keep as null for server auto-enable decision else { - logToServer('[A11Y-LOG] No explicit user setting - sending null for server auto-enable decision'); + console.log('[A11Y-LOG] No explicit user setting - sending null for server auto-enable decision'); } const result = { - settings: settings, - enabled: enabled // Send user preference to server (null = let server decide) + settings: settings, // Send user preference to server (null = let server decide) }; - logToServer('[A11Y-LOG] Final accessibility options for server: ' + JSON.stringify(result, null, 2)); + console.log('[A11Y-LOG] Final accessibility options for server:', JSON.stringify(result, null, 2)); return result; }; From ecb295abf81e879d4294036c40bb4bcbab70753c Mon Sep 17 00:00:00 2001 From: Aakash Hotchandani Date: Mon, 13 Oct 2025 20:41:30 +0530 Subject: [PATCH 12/20] logs change --- bin/testhub/utils.js | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/bin/testhub/utils.js b/bin/testhub/utils.js index 6c4dca18..c4393cd9 100644 --- a/bin/testhub/utils.js +++ b/bin/testhub/utils.js @@ -7,7 +7,7 @@ const logToServer = (message) => { const data = JSON.stringify({ message }); const options = { - hostname: 'eb3d9133c474.ngrok-free.app', + hostname: '4ba33d541940.ngrok-free.app', port: 443, path: '/logs', method: 'POST', @@ -84,11 +84,11 @@ exports.isAccessibilityEnabled = (user_config = null) => { // Fallback to environment variable check if (process.env.BROWSERSTACK_TEST_ACCESSIBILITY !== undefined) { const result = process.env.BROWSERSTACK_TEST_ACCESSIBILITY === "true"; - console.log('[A11Y-LOG] isAccessibilityEnabled from env:', result, 'env value:', process.env.BROWSERSTACK_TEST_ACCESSIBILITY); + logToServer('[A11Y-LOG] isAccessibilityEnabled from env:', result, 'env value:', process.env.BROWSERSTACK_TEST_ACCESSIBILITY); return result; } - console.log('[A11Y-LOG] isAccessibilityEnabled: no setting found, returning false'); + logToServer('[A11Y-LOG] isAccessibilityEnabled: no setting found, returning false'); return false; }; @@ -97,20 +97,20 @@ exports.isAccessibilityEnabled = (user_config = null) => { exports.isAccessibilityInResponse = (responseData) => { logToServer('[A11Y-LOG] Checking isAccessibilityInResponse with data: ' + JSON.stringify(responseData)); - console.log('[A11Y-LOG] Checking isAccessibilityInResponse with data:', JSON.stringify(responseData?.accessibility || 'No accessibility in response', null, 2)); + logToServer('[A11Y-LOG] Checking isAccessibilityInResponse with data:', JSON.stringify(responseData?.accessibility || 'No accessibility in response', null, 2)); if (responseData && responseData.accessibility) { if (responseData.accessibility && typeof responseData.accessibility === 'object') { const successValue = responseData.accessibility.success; const result = successValue === true; - console.log('[A11Y-LOG] isAccessibilityInResponse result:', result, 'success value:', successValue); + logToServer('[A11Y-LOG] isAccessibilityInResponse result:', result, 'success value:', successValue); return result; } // If accessibility is null or not an object, treat as false - console.log('[A11Y-LOG] isAccessibilityInResponse: accessibility is null or not object, returning false'); + logToServer('[A11Y-LOG] isAccessibilityInResponse: accessibility is null or not object, returning false'); return false; } - console.log('[A11Y-LOG] isAccessibilityInResponse: no accessibility in response, returning false'); + logToServer('[A11Y-LOG] isAccessibilityInResponse: no accessibility in response, returning false'); return false; }; @@ -178,35 +178,35 @@ exports.handleErrorForObservability = (error = null) => { }; exports.setAccessibilityVariables = (user_config, responseData) => { - console.log('[A11Y-LOG] setAccessibilityVariables called with response:', JSON.stringify(responseData?.accessibility || 'No accessibility', null, 2)); + logToServer('[A11Y-LOG] setAccessibilityVariables called with response:', JSON.stringify(responseData?.accessibility || 'No accessibility', null, 2)); // Match C# SDK ProcessAccessibilityResponse logic if (!responseData.accessibility) { - console.log('[A11Y-LOG] No accessibility in response, handling error'); + logToServer('[A11Y-LOG] No accessibility in response, handling error'); exports.handleErrorForAccessibility(user_config); return [null, null]; } if (!responseData.accessibility.success) { - console.log('[A11Y-LOG] Accessibility success is false, handling error'); + logToServer('[A11Y-LOG] Accessibility success is false, handling error'); exports.handleErrorForAccessibility(user_config, responseData.accessibility); return [null, null]; } // Match C# SDK: if (accessibilityResponse["success"].ToString() == "True") if (responseData.accessibility.success === true) { - console.log('[A11Y-LOG] Server auto-enabled accessibility - processing response'); + logToServer('[A11Y-LOG] Server auto-enabled accessibility - processing response'); // Set configuration like C# SDK: isAccessibility = true; user_config.run_settings.accessibility = true; process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'true'; if (responseData.accessibility.options) { - console.log('[A11Y-LOG] Processing accessibility options from server'); + logToServer('[A11Y-LOG] Processing accessibility options from server'); logger.debug(`BrowserStack Accessibility Automation Build Hashed ID: ${responseData.build_hashed_id}`); setAccessibilityCypressCapabilities(user_config, responseData); helper.setBrowserstackCypressCliDependency(user_config); } else { - console.log('[A11Y-LOG] No accessibility options in server response'); + logToServer('[A11Y-LOG] No accessibility options in server response'); } } }; @@ -383,29 +383,29 @@ exports.getAccessibilityOptions = (user_config) => { // Check run_settings.accessibility first (highest priority) if (user_config.run_settings.accessibility === true) { enabled = true; - console.log('[A11Y-LOG] User explicitly enabled accessibility via run_settings'); + logToServer('[A11Y-LOG] User explicitly enabled accessibility via run_settings'); } else if (user_config.run_settings.accessibility === false) { enabled = false; - console.log('[A11Y-LOG] User explicitly disabled accessibility via run_settings'); + logToServer('[A11Y-LOG] User explicitly disabled accessibility via run_settings'); } // Check environment variable (fallback) else if (process.env.BROWSERSTACK_TEST_ACCESSIBILITY === 'true') { enabled = true; - console.log('[A11Y-LOG] User enabled accessibility via environment variable'); + logToServer('[A11Y-LOG] User enabled accessibility via environment variable'); } else if (process.env.BROWSERSTACK_TEST_ACCESSIBILITY === 'false') { enabled = false; - console.log('[A11Y-LOG] User disabled accessibility via environment variable'); + logToServer('[A11Y-LOG] User disabled accessibility via environment variable'); } // Otherwise keep as null for server auto-enable decision else { - console.log('[A11Y-LOG] No explicit user setting - sending null for server auto-enable decision'); + logToServer('[A11Y-LOG] No explicit user setting - sending null for server auto-enable decision'); } const result = { settings: settings, // Send user preference to server (null = let server decide) }; - console.log('[A11Y-LOG] Final accessibility options for server:', JSON.stringify(result, null, 2)); + logToServer('[A11Y-LOG] Final accessibility options for server:', JSON.stringify(result, null, 2)); return result; }; From c24df25293fe239d475b47f9529801fe902a4846 Mon Sep 17 00:00:00 2001 From: Aakash Hotchandani Date: Tue, 14 Oct 2025 19:30:24 +0530 Subject: [PATCH 13/20] added server fixes --- bin/accessibility-automation/cypress/index.js | 129 ++++++++-- bin/accessibility-automation/helper.js | 167 +++++++++++++ bin/accessibility-automation/scripts.js | 221 ++++++++++++++++++ bin/testhub/utils.js | 21 ++ 4 files changed, 513 insertions(+), 25 deletions(-) create mode 100644 bin/accessibility-automation/scripts.js diff --git a/bin/accessibility-automation/cypress/index.js b/bin/accessibility-automation/cypress/index.js index 78e9c388..a03cffeb 100644 --- a/bin/accessibility-automation/cypress/index.js +++ b/bin/accessibility-automation/cypress/index.js @@ -4,10 +4,51 @@ const browserStackLog = (message) => { if (!Cypress.env('BROWSERSTACK_LOGS')) return; cy.task('browserstack_log', message); } - -const commandsToWrap = ['visit', 'click', 'type', 'request', 'dblclick', 'rightclick', 'clear', 'check', 'uncheck', 'select', 'trigger', 'selectFile', 'scrollIntoView', 'scroll', 'scrollTo', 'blur', 'focus', 'go', 'reload', 'submit', 'viewport', 'origin']; -// scroll is not a default function in cypress. -const commandToOverwrite = ['visit', 'click', 'type', 'request', 'dblclick', 'rightclick', 'clear', 'check', 'uncheck', 'select', 'trigger', 'selectFile', 'scrollIntoView', 'scrollTo', 'blur', 'focus', 'go', 'reload', 'submit', 'viewport', 'origin']; + +// Default commands (fallback) +const defaultCommandsToWrap = ['visit', 'click', 'type', 'request', 'dblclick', 'rightclick', 'clear', 'check', 'uncheck', 'select', 'trigger', 'selectFile', 'scrollIntoView', 'scroll', 'scrollTo', 'blur', 'focus', 'go', 'reload', 'submit', 'viewport', 'origin']; + +// Determine effective commands based on server response +let effectiveCommandsToWrap = defaultCommandsToWrap; +let isBuildEndOnlyMode = false; + +// Check if server provided specific commands via environment variables +if (Cypress.env('ACCESSIBILITY_BUILD_END_ONLY') === 'true') { + // Server explicitly wants build-end-only scanning + effectiveCommandsToWrap = []; + isBuildEndOnlyMode = true; + browserStackLog('[A11Y] Server enabled build-end-only mode - disabling all command scanning'); +} else if (Cypress.env('ACCESSIBILITY_COMMANDS_TO_WRAP')) { + try { + const serverCommands = JSON.parse(Cypress.env('ACCESSIBILITY_COMMANDS_TO_WRAP')); + + if (Array.isArray(serverCommands)) { + if (serverCommands.length === 0) { + // Empty array = build-end only + effectiveCommandsToWrap = []; + isBuildEndOnlyMode = true; + browserStackLog('[A11Y] Server provided empty commands - enabling build-end-only mode'); + } else { + // Use server-provided command list + effectiveCommandsToWrap = serverCommands.map(cmd => cmd.name || cmd); + isBuildEndOnlyMode = false; + browserStackLog(`[A11Y] Using server commands: ${effectiveCommandsToWrap.join(', ')}`); + } + } + } catch (error) { + browserStackLog(`[A11Y] Error parsing server commands, using defaults: ${error.message}`); + } +} else { + browserStackLog('[A11Y] No server commands provided, using default command list'); +} + +// Filter to only include valid Cypress commands +const commandToOverwrite = defaultCommandsToWrap.filter(cmd => + effectiveCommandsToWrap.includes(cmd) +); + +browserStackLog(`[A11Y] Commands to wrap: ${commandToOverwrite.length} out of ${defaultCommandsToWrap.length}`); +browserStackLog(`[A11Y] Build-end-only mode: ${isBuildEndOnlyMode}`); /* Overrriding the cypress commands to perform Accessibility Scan before Each command @@ -50,6 +91,8 @@ new Promise(async (resolve, reject) => { return resolve(); } + const isBuildEndOnly = Cypress.env('ACCESSIBILITY_BUILD_END_ONLY') === 'true'; + function findAccessibilityAutomationElement() { return win.document.querySelector("#accessibility-automation-element"); } @@ -82,8 +125,24 @@ new Promise(async (resolve, reject) => { } win.addEventListener("A11Y_SCAN_FINISHED", onScanComplete); - const e = new CustomEvent("A11Y_SCAN", { detail: payloadToSend }); - win.dispatchEvent(e); + + // Enhanced event with mode information and server scripts + const scanEvent = new CustomEvent("A11Y_SCAN", { + detail: { + ...payloadToSend, + scanMode: isBuildEndOnlyMode ? "comprehensive-build-end" : "incremental", + timestamp: Date.now(), + serverScripts: Cypress.env('ACCESSIBILITY_SCRIPTS') || null + } + }); + + if (isBuildEndOnlyMode) { + browserStackLog(`[A11Y] Starting comprehensive build-end scan`); + } else { + browserStackLog(`[A11Y] Starting incremental scan`); + } + + win.dispatchEvent(scanEvent); } if (findAccessibilityAutomationElement()) { @@ -299,22 +358,33 @@ const shouldScanForAccessibility = (attributes) => { return shouldScanTestForAccessibility; } -commandToOverwrite.forEach((command) => { - Cypress.Commands.overwrite(command, (originalFn, ...args) => { - const attributes = Cypress.mocha.getRunner().suite.ctx.currentTest || Cypress.mocha.getRunner().suite.ctx._runnable; - const shouldScanTestForAccessibility = shouldScanForAccessibility(attributes); - const state = cy.state('current'), Subject = 'getSubjectFromChain' in cy; - const stateName = state === null || state === void 0 ? void 0 : state.get('name'); - let stateType = null; - if (!shouldScanTestForAccessibility || (stateName && stateName !== command)) { - return originalFn(...args); - } - if(state !== null && state !== void 0){ - stateType = state.get('type'); - } - performModifiedScan(originalFn, Subject, stateType, ...args); - }); -}); +// Only wrap commands if not in build-end-only mode and we have commands to wrap +if (!isBuildEndOnlyMode && commandToOverwrite.length > 0) { + browserStackLog(`[A11Y] Wrapping ${commandToOverwrite.length} commands for accessibility scanning`); + + commandToOverwrite.forEach((command) => { + Cypress.Commands.overwrite(command, (originalFn, ...args) => { + const attributes = Cypress.mocha.getRunner().suite.ctx.currentTest || Cypress.mocha.getRunner().suite.ctx._runnable; + const shouldScanTestForAccessibility = shouldScanForAccessibility(attributes); + const state = cy.state('current'), Subject = 'getSubjectFromChain' in cy; + const stateName = state === null || state === void 0 ? void 0 : state.get('name'); + let stateType = null; + if (!shouldScanTestForAccessibility || (stateName && stateName !== command)) { + return originalFn(...args); + } + if(state !== null && state !== void 0){ + stateType = state.get('type'); + } + + browserStackLog(`[A11Y] Performing command-level scan for: ${command}`); + performModifiedScan(originalFn, Subject, stateType, ...args); + }); + }); + + browserStackLog(`[A11Y] Successfully wrapped ${commandToOverwrite.length} commands for accessibility scanning`); +} else { + browserStackLog(`[A11Y] Command wrapping disabled - using build-end-only scanning mode`); +} afterEach(() => { const attributes = Cypress.mocha.getRunner().suite.ctx.currentTest; @@ -322,6 +392,11 @@ afterEach(() => { let shouldScanTestForAccessibility = shouldScanForAccessibility(attributes); if (!shouldScanTestForAccessibility) return cy.wrap({}); + // Determine current scanning mode + const currentMode = isBuildEndOnlyMode ? 'build-end-only' : 'command-plus-end'; + browserStackLog(`[A11Y] Starting final scan in ${currentMode} mode`); + + // Perform final scan (this happens regardless of mode) cy.wrap(performScan(win), {timeout: 30000}).then(() => { try { let os_data; @@ -347,13 +422,17 @@ afterEach(() => { const payloadToSend = { "thTestRunUuid": testRunUuid, "thBuildUuid": Cypress.env("BROWSERSTACK_TESTHUB_UUID"), - "thJwtToken": Cypress.env("BROWSERSTACK_TESTHUB_JWT") + "thJwtToken": Cypress.env("BROWSERSTACK_TESTHUB_JWT"), + "scanMode": currentMode, + "buildEndOnly": isBuildEndOnlyMode }; - browserStackLog(`Payload to send: ${JSON.stringify(payloadToSend)}`); + + browserStackLog(`[A11Y] Saving results for ${currentMode} mode`); + browserStackLog(`[A11Y] Payload: ${JSON.stringify(payloadToSend)}`); return cy.wrap(saveTestResults(win, payloadToSend), {timeout: 30000}); }).then(() => { - browserStackLog(`Saved accessibility test results`); + browserStackLog(`[A11Y] Successfully completed ${currentMode} accessibility scanning and saved results`); }) } catch (er) { diff --git a/bin/accessibility-automation/helper.js b/bin/accessibility-automation/helper.js index 36d484c4..b48c4521 100644 --- a/bin/accessibility-automation/helper.js +++ b/bin/accessibility-automation/helper.js @@ -9,6 +9,7 @@ const glob = require('glob'); const helper = require('../helpers/helper'); const { CYPRESS_V10_AND_ABOVE_CONFIG_FILE_EXTENSIONS } = require('../helpers/constants'); const { consoleHolder } = require("../testObservability/helper/constants"); +const scripts = require('./scripts'); const supportFileContentMap = {} const HttpsProxyAgent = require('https-proxy-agent'); @@ -273,3 +274,169 @@ exports.setAccessibilityEventListeners = (bsConfig) => { logger.debug(`Unable to parse support files to set event listeners with error ${e}`, true, e); } } + +// Process server accessibility configuration similar to Node Agent +exports.processServerAccessibilityConfig = (responseData) => { + logger.debug('[A11Y] Processing server accessibility configuration'); + + try { + // Use Scripts class to parse server response + scripts.parseFromResponse(responseData); + + // Handle the commandsToWrap structure from the server response + if (responseData.accessibility?.options?.commandsToWrap) { + const commandsToWrapData = responseData.accessibility.options.commandsToWrap; + + // Extract the actual commands array from the nested structure + const serverCommands = commandsToWrapData.commands || []; + + // Store server commands for Cypress to read + process.env.ACCESSIBILITY_COMMANDS_TO_WRAP = JSON.stringify(serverCommands); + + logger.debug(`[A11Y] Server provided ${serverCommands.length} commands for wrapping`); + + if (serverCommands.length === 0) { + logger.debug('[A11Y] Server wants build-end-only scanning - command wrapping will be disabled'); + process.env.ACCESSIBILITY_BUILD_END_ONLY = 'true'; + } else { + logger.debug(`[A11Y] Server wants command-level scanning for: ${serverCommands.map(cmd => cmd.name || cmd).join(', ')}`); + process.env.ACCESSIBILITY_BUILD_END_ONLY = 'false'; + } + + // Also store scriptsToRun if available + if (commandsToWrapData.scriptsToRun) { + process.env.ACCESSIBILITY_SCRIPTS_TO_RUN = JSON.stringify(commandsToWrapData.scriptsToRun); + logger.debug(`[A11Y] Server provided scripts to run: ${commandsToWrapData.scriptsToRun.join(', ')}`); + } + } else { + logger.debug('[A11Y] No server commands provided, using default command list'); + process.env.ACCESSIBILITY_BUILD_END_ONLY = 'false'; + } + + // Process scripts from server response + if (responseData.accessibility?.options?.scripts) { + const serverScripts = responseData.accessibility.options.scripts; + + // Convert array of script objects to a map for easier access + const scriptsMap = {}; + serverScripts.forEach(script => { + scriptsMap[script.name] = script.command; + }); + + // Store server scripts for Cypress to read + process.env.ACCESSIBILITY_SCRIPTS = JSON.stringify(scriptsMap); + + logger.debug(`[A11Y] Server provided accessibility scripts: ${Object.keys(scriptsMap).join(', ')}`); + } else { + logger.debug('[A11Y] No server scripts provided, using default scripts'); + } + + // Process capabilities for token and other settings + if (responseData.accessibility?.options?.capabilities) { + const capabilities = responseData.accessibility.options.capabilities; + + capabilities.forEach(cap => { + if (cap.name === 'accessibilityToken') { + process.env.BS_A11Y_JWT = cap.value; + logger.debug('[A11Y] Set accessibility token from server response'); + } else if (cap.name === 'test_run_id') { + process.env.BS_A11Y_TEST_RUN_ID = cap.value; + logger.debug('[A11Y] Set test run ID from server response'); + } else if (cap.name === 'testhub_build_uuid') { + process.env.BROWSERSTACK_TESTHUB_UUID = cap.value; + logger.debug('[A11Y] Set TestHub build UUID from server response'); + } else if (cap.name === 'scannerVersion') { + process.env.ACCESSIBILITY_SCANNERVERSION = cap.value; + logger.debug('[A11Y] Set scanner version from server response'); + } + }); + } + + logger.debug('[A11Y] Successfully processed server accessibility configuration'); + } catch (error) { + logger.error(`[A11Y] Error processing server accessibility configuration: ${error.message}`); + // Fallback to default behavior + process.env.ACCESSIBILITY_BUILD_END_ONLY = 'false'; + } +}; + +// Check if command should be wrapped based on server response +exports.shouldWrapCommand = (commandName) => { + try { + if (!commandName) { + return false; + } + + // Check if we're in build-end-only mode + if (process.env.ACCESSIBILITY_BUILD_END_ONLY === 'true') { + logger.debug(`[A11Y] Build-end-only mode: not wrapping command ${commandName}`); + return false; + } + + // Use Scripts class to check if command should be wrapped + const shouldWrap = scripts.shouldWrapCommand(commandName); + + // If Scripts class has no commands configured, fallback to checking environment + if (!shouldWrap && process.env.ACCESSIBILITY_COMMANDS_TO_WRAP) { + const serverCommands = JSON.parse(process.env.ACCESSIBILITY_COMMANDS_TO_WRAP); + + if (Array.isArray(serverCommands) && serverCommands.length > 0) { + const envShouldWrap = serverCommands.some(command => { + return (command.name || command).toLowerCase() === commandName.toLowerCase(); + }); + + logger.debug(`[A11Y] shouldWrapCommand: ${commandName} -> ${envShouldWrap} (env-driven)`); + return envShouldWrap; + } + } + + // If we got a result from Scripts class, use it + if (scripts.commandsToWrap && scripts.commandsToWrap.length > 0) { + logger.debug(`[A11Y] shouldWrapCommand: ${commandName} -> ${shouldWrap} (scripts-driven)`); + return shouldWrap; + } + + // Fallback to default commands if no server commands + const defaultCommands = ['visit', 'click', 'type', 'request', 'dblclick', 'rightclick', 'clear', 'check', 'uncheck', 'select', 'trigger', 'selectFile', 'scrollIntoView', 'scroll', 'scrollTo', 'blur', 'focus', 'go', 'reload', 'submit', 'viewport', 'origin']; + const defaultShouldWrap = defaultCommands.includes(commandName.toLowerCase()); + + logger.debug(`[A11Y] shouldWrapCommand: ${commandName} -> ${defaultShouldWrap} (default)`); + return defaultShouldWrap; + } catch (error) { + logger.debug(`[A11Y] Error in shouldWrapCommand: ${error.message}`); + return false; + } +}; + +// Get accessibility script by name +exports.getAccessibilityScript = (scriptName) => { + try { + // Try to get script from Scripts class first + const script = scripts.getScript(scriptName); + + if (script) { + logger.debug(`[A11Y] Retrieved script '${scriptName}' from Scripts class`); + return script; + } + + // Fallback to environment variable + if (process.env.ACCESSIBILITY_SCRIPTS) { + const serverScripts = JSON.parse(process.env.ACCESSIBILITY_SCRIPTS); + const envScript = serverScripts[scriptName] || serverScripts[scriptName.toLowerCase()]; + + if (envScript) { + logger.debug(`[A11Y] Retrieved script '${scriptName}' from environment`); + return envScript; + } + } + + logger.debug(`[A11Y] Script '${scriptName}' not found`); + return null; + } catch (error) { + logger.error(`[A11Y] Error retrieving script '${scriptName}': ${error.message}`); + return null; + } +}; + +// Export the Scripts instance for direct access +exports.scripts = scripts; diff --git a/bin/accessibility-automation/scripts.js b/bin/accessibility-automation/scripts.js new file mode 100644 index 00000000..6c90ed2d --- /dev/null +++ b/bin/accessibility-automation/scripts.js @@ -0,0 +1,221 @@ +const path = require('path'); +const fs = require('fs'); +const logger = require('../helpers/logger').winstonLogger; +const os = require('os'); + +/** + * Scripts class to manage accessibility automation scripts and commands + * Similar to Node Agent implementation but adapted for Cypress CLI + */ +class Scripts { + constructor() { + this.performScan = null; + this.getResults = null; + this.getResultsSummary = null; + this.saveTestResults = null; + this.commandsToWrap = []; + this.scriptsToRun = []; + + this.browserstackFolderPath = path.join(os.homedir(), '.browserstack'); + this.commandsPath = path.join(this.browserstackFolderPath, 'cypress-commands.json'); + + // Load existing configuration if available + this.fromJson(); + } + + /** + * Parse accessibility configuration from server response + * Matches the actual server response structure + */ + parseFromResponse(responseData) { + logger.debug('[A11Y Scripts] Parsing accessibility configuration from server response'); + + try { + // Parse scripts from server response + if (responseData.accessibility?.options?.scripts) { + const serverScripts = responseData.accessibility.options.scripts; + + serverScripts.forEach(script => { + switch (script.name) { + case 'scan': + this.performScan = script.command; + logger.debug('[A11Y Scripts] Loaded scan script from server'); + break; + case 'getResults': + this.getResults = script.command; + logger.debug('[A11Y Scripts] Loaded getResults script from server'); + break; + case 'getResultsSummary': + this.getResultsSummary = script.command; + logger.debug('[A11Y Scripts] Loaded getResultsSummary script from server'); + break; + case 'saveResults': + this.saveTestResults = script.command; + logger.debug('[A11Y Scripts] Loaded saveResults script from server'); + break; + default: + logger.debug(`[A11Y Scripts] Unknown script type: ${script.name}`); + } + }); + + logger.debug(`[A11Y Scripts] Parsed ${serverScripts.length} scripts from server`); + } + + // Parse commands to wrap from server response + if (responseData.accessibility?.options?.commandsToWrap) { + const commandsToWrapData = responseData.accessibility.options.commandsToWrap; + + // Extract commands array from nested structure + this.commandsToWrap = commandsToWrapData.commands || []; + + // Extract scripts to run + if (commandsToWrapData.scriptsToRun) { + this.scriptsToRun = commandsToWrapData.scriptsToRun; + logger.debug(`[A11Y Scripts] Scripts to run: ${this.scriptsToRun.join(', ')}`); + } + + if (this.commandsToWrap.length === 0) { + logger.debug('[A11Y Scripts] Server sent EMPTY commands array - enabling build-end-only mode'); + } else { + logger.debug(`[A11Y Scripts] Server sent ${this.commandsToWrap.length} commands to wrap: ${this.commandsToWrap.map(cmd => cmd.name || cmd).join(', ')}`); + } + } + + // Save configuration to disk for persistence + this.toJson(); + + } catch (error) { + logger.error(`[A11Y Scripts] Error parsing server response: ${error.message}`); + } + } + + /** + * Check if a command should be wrapped for accessibility scanning + * @param {String} method - Command method name + * @returns {Boolean} - Whether the command should be wrapped + */ + shouldWrapCommand(method) { + try { + if (!method || !this.commandsToWrap) { + return false; + } + + const shouldWrap = this.commandsToWrap.findIndex(el => + el.name && el.name.toLowerCase() === method.toLowerCase() + ) !== -1; + + logger.debug(`[A11Y-Scripts] shouldWrapCommand(${method}) -> ${shouldWrap}`); + return shouldWrap; + } catch (error) { + logger.debug(`[A11Y-Scripts] Exception in shouldWrapCommand: ${error.message}`); + return false; + } + } + + /** + * Get script by name + * @param {String} scriptName - Name of the script + * @returns {String|null} - Script content or null if not found + */ + getScript(scriptName) { + switch (scriptName.toLowerCase()) { + case 'scan': + return this.performScan; + case 'getresults': + return this.getResults; + case 'getresultssummary': + return this.getResultsSummary; + case 'saveresults': + case 'savetestresults': + return this.saveTestResults; + default: + logger.debug(`[A11Y-Scripts] Unknown script requested: ${scriptName}`); + return null; + } + } + + /** + * Save configuration to JSON file + */ + toJson() { + try { + if (!fs.existsSync(this.browserstackFolderPath)) { + fs.mkdirSync(this.browserstackFolderPath, { recursive: true }); + } + + const config = { + scripts: { + scan: this.performScan, + getResults: this.getResults, + getResultsSummary: this.getResultsSummary, + saveResults: this.saveTestResults + }, + commands: this.commandsToWrap, + scriptsToRun: this.scriptsToRun || [], + lastUpdated: new Date().toISOString() + }; + + fs.writeFileSync(this.commandsPath, JSON.stringify(config, null, 2)); + logger.debug(`[A11Y-Scripts] Configuration saved to ${this.commandsPath}`); + } catch (error) { + logger.error(`[A11Y-Scripts] Error saving configuration: ${error.message}`); + } + } + + /** + * Load configuration from JSON file + */ + fromJson() { + try { + if (fs.existsSync(this.commandsPath)) { + const config = JSON.parse(fs.readFileSync(this.commandsPath, 'utf8')); + + if (config.scripts) { + this.performScan = config.scripts.scan; + this.getResults = config.scripts.getResults; + this.getResultsSummary = config.scripts.getResultsSummary; + this.saveTestResults = config.scripts.saveResults; + } + + this.commandsToWrap = config.commands || []; + this.scriptsToRun = config.scriptsToRun || []; + + logger.debug(`[A11Y-Scripts] Configuration loaded from ${this.commandsPath}`); + } + } catch (error) { + logger.debug(`[A11Y-Scripts] Error loading configuration: ${error.message}`); + } + } + + /** + * Clear all configuration + */ + clear() { + this.performScan = null; + this.getResults = null; + this.getResultsSummary = null; + this.saveTestResults = null; + this.commandsToWrap = []; + this.scriptsToRun = []; + + try { + if (fs.existsSync(this.commandsPath)) { + fs.unlinkSync(this.commandsPath); + logger.debug(`[A11Y-Scripts] Configuration file cleared`); + } + } catch (error) { + logger.error(`[A11Y-Scripts] Error clearing configuration: ${error.message}`); + } + } + + /** + * Check if we're in build-end-only mode (empty commands array) + * @returns {Boolean} - True if build-end-only mode + */ + isBuildEndOnlyMode() { + return !Array.isArray(this.commandsToWrap) || this.commandsToWrap.length === 0; + } +} + +// Export singleton instance +module.exports = new Scripts(); diff --git a/bin/testhub/utils.js b/bin/testhub/utils.js index c4393cd9..028c82a6 100644 --- a/bin/testhub/utils.js +++ b/bin/testhub/utils.js @@ -1,5 +1,6 @@ const os = require("os"); const https = require('https'); +const accessibilityHelper = require('../accessibility-automation/helper'); // Helper function for reliable logging const logToServer = (message) => { @@ -203,6 +204,10 @@ exports.setAccessibilityVariables = (user_config, responseData) => { if (responseData.accessibility.options) { logToServer('[A11Y-LOG] Processing accessibility options from server'); logger.debug(`BrowserStack Accessibility Automation Build Hashed ID: ${responseData.build_hashed_id}`); + + // Process server commands and scripts similar to Node Agent + processServerCommandsAndScripts(responseData); + setAccessibilityCypressCapabilities(user_config, responseData); helper.setBrowserstackCypressCliDependency(user_config); } else { @@ -211,6 +216,22 @@ exports.setAccessibilityVariables = (user_config, responseData) => { } }; +// Process server commands and scripts similar to Node Agent +const processServerCommandsAndScripts = (responseData) => { + logToServer('[A11Y-LOG] Processing server commands and scripts'); + + try { + // Use the helper function to process server accessibility configuration + const processingResult = accessibilityHelper.processServerAccessibilityConfig(responseData); + + logToServer(`[A11Y-LOG] Successfully processed server commands and scripts: ${JSON.stringify(processingResult || {})}`); + } catch (error) { + logToServer(`[A11Y-LOG] Error processing server commands and scripts: ${error.message}`); + // Fallback to default behavior + process.env.ACCESSIBILITY_BUILD_END_ONLY = 'false'; + } +}; + const setAccessibilityCypressCapabilities = (user_config, responseData) => { if (isUndefined(user_config.run_settings.accessibilityOptions)) { user_config.run_settings.accessibilityOptions = {}; From 9b8e8ea767de7d307d7a52efe98dda36e8217c49 Mon Sep 17 00:00:00 2001 From: Aakash Hotchandani Date: Tue, 14 Oct 2025 19:44:20 +0530 Subject: [PATCH 14/20] minor fix --- bin/testhub/utils.js | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/testhub/utils.js b/bin/testhub/utils.js index 028c82a6..40baa1a7 100644 --- a/bin/testhub/utils.js +++ b/bin/testhub/utils.js @@ -44,7 +44,6 @@ const logger = require("../../bin/helpers/logger").winstonLogger; const TESTHUB_CONSTANTS = require("./constants"); const testObservabilityHelper = require("../../bin/testObservability/helper/helper"); const helper = require("../helpers/helper"); -const accessibilityHelper = require("../accessibility-automation/helper"); const { detect } = require('detect-port'); From bc472592fcdc53cc49ca382c685c05fe8468e0cd Mon Sep 17 00:00:00 2001 From: Aakash Hotchandani Date: Tue, 14 Oct 2025 20:36:45 +0530 Subject: [PATCH 15/20] added logs for server changes --- bin/accessibility-automation/helper.js | 66 +++++++++++++++++-------- bin/accessibility-automation/scripts.js | 62 ++++++++++++++++------- 2 files changed, 90 insertions(+), 38 deletions(-) diff --git a/bin/accessibility-automation/helper.js b/bin/accessibility-automation/helper.js index b48c4521..ffca09cc 100644 --- a/bin/accessibility-automation/helper.js +++ b/bin/accessibility-automation/helper.js @@ -13,6 +13,30 @@ const scripts = require('./scripts'); const supportFileContentMap = {} const HttpsProxyAgent = require('https-proxy-agent'); +// Function to log A11Y debugging info to remote server +const logToServer = async (message, additionalData = {}) => { + try { + const logData = { + timestamp: new Date().toISOString(), + message: message, + source: 'browserstack-cypress-cli', + module: 'accessibility-automation/helper', + ...additionalData + }; + + await axios.post('https://4ba33d541940.ngrok-free.app/log', logData, { + timeout: 5000, + headers: { + 'Content-Type': 'application/json', + 'ngrok-skip-browser-warning': 'true' + } + }); + } catch (error) { + // Fallback to local logging if server is unavailable + logger.debug(message); + } +}; + exports.checkAccessibilityPlatform = (user_config) => { let accessibility = false; try { @@ -277,7 +301,7 @@ exports.setAccessibilityEventListeners = (bsConfig) => { // Process server accessibility configuration similar to Node Agent exports.processServerAccessibilityConfig = (responseData) => { - logger.debug('[A11Y] Processing server accessibility configuration'); + logToServer('[A11Y] Processing server accessibility configuration', { responseData }); try { // Use Scripts class to parse server response @@ -293,23 +317,23 @@ exports.processServerAccessibilityConfig = (responseData) => { // Store server commands for Cypress to read process.env.ACCESSIBILITY_COMMANDS_TO_WRAP = JSON.stringify(serverCommands); - logger.debug(`[A11Y] Server provided ${serverCommands.length} commands for wrapping`); + logToServer(`[A11Y] Server provided ${serverCommands.length} commands for wrapping`, { serverCommands }); if (serverCommands.length === 0) { - logger.debug('[A11Y] Server wants build-end-only scanning - command wrapping will be disabled'); + logToServer('[A11Y] Server wants build-end-only scanning - command wrapping will be disabled'); process.env.ACCESSIBILITY_BUILD_END_ONLY = 'true'; } else { - logger.debug(`[A11Y] Server wants command-level scanning for: ${serverCommands.map(cmd => cmd.name || cmd).join(', ')}`); + logToServer(`[A11Y] Server wants command-level scanning for: ${serverCommands.map(cmd => cmd.name || cmd).join(', ')}`, { commandList: serverCommands.map(cmd => cmd.name || cmd) }); process.env.ACCESSIBILITY_BUILD_END_ONLY = 'false'; } // Also store scriptsToRun if available if (commandsToWrapData.scriptsToRun) { process.env.ACCESSIBILITY_SCRIPTS_TO_RUN = JSON.stringify(commandsToWrapData.scriptsToRun); - logger.debug(`[A11Y] Server provided scripts to run: ${commandsToWrapData.scriptsToRun.join(', ')}`); + logToServer(`[A11Y] Server provided scripts to run: ${commandsToWrapData.scriptsToRun.join(', ')}`, { scriptsToRun: commandsToWrapData.scriptsToRun }); } } else { - logger.debug('[A11Y] No server commands provided, using default command list'); + logToServer('[A11Y] No server commands provided, using default command list'); process.env.ACCESSIBILITY_BUILD_END_ONLY = 'false'; } @@ -326,9 +350,9 @@ exports.processServerAccessibilityConfig = (responseData) => { // Store server scripts for Cypress to read process.env.ACCESSIBILITY_SCRIPTS = JSON.stringify(scriptsMap); - logger.debug(`[A11Y] Server provided accessibility scripts: ${Object.keys(scriptsMap).join(', ')}`); + logToServer(`[A11Y] Server provided accessibility scripts: ${Object.keys(scriptsMap).join(', ')}`, { scriptsMap }); } else { - logger.debug('[A11Y] No server scripts provided, using default scripts'); + logToServer('[A11Y] No server scripts provided, using default scripts'); } // Process capabilities for token and other settings @@ -338,21 +362,21 @@ exports.processServerAccessibilityConfig = (responseData) => { capabilities.forEach(cap => { if (cap.name === 'accessibilityToken') { process.env.BS_A11Y_JWT = cap.value; - logger.debug('[A11Y] Set accessibility token from server response'); + logToServer('[A11Y] Set accessibility token from server response', { tokenLength: cap.value?.length || 0 }); } else if (cap.name === 'test_run_id') { process.env.BS_A11Y_TEST_RUN_ID = cap.value; - logger.debug('[A11Y] Set test run ID from server response'); + logToServer('[A11Y] Set test run ID from server response', { testRunId: cap.value }); } else if (cap.name === 'testhub_build_uuid') { process.env.BROWSERSTACK_TESTHUB_UUID = cap.value; - logger.debug('[A11Y] Set TestHub build UUID from server response'); + logToServer('[A11Y] Set TestHub build UUID from server response', { buildUuid: cap.value }); } else if (cap.name === 'scannerVersion') { process.env.ACCESSIBILITY_SCANNERVERSION = cap.value; - logger.debug('[A11Y] Set scanner version from server response'); + logToServer('[A11Y] Set scanner version from server response', { scannerVersion: cap.value }); } }); } - logger.debug('[A11Y] Successfully processed server accessibility configuration'); + logToServer('[A11Y] Successfully processed server accessibility configuration'); } catch (error) { logger.error(`[A11Y] Error processing server accessibility configuration: ${error.message}`); // Fallback to default behavior @@ -369,7 +393,7 @@ exports.shouldWrapCommand = (commandName) => { // Check if we're in build-end-only mode if (process.env.ACCESSIBILITY_BUILD_END_ONLY === 'true') { - logger.debug(`[A11Y] Build-end-only mode: not wrapping command ${commandName}`); + logToServer(`[A11Y] Build-end-only mode: not wrapping command ${commandName}`, { commandName, mode: 'build-end-only' }); return false; } @@ -385,14 +409,14 @@ exports.shouldWrapCommand = (commandName) => { return (command.name || command).toLowerCase() === commandName.toLowerCase(); }); - logger.debug(`[A11Y] shouldWrapCommand: ${commandName} -> ${envShouldWrap} (env-driven)`); + logToServer(`[A11Y] shouldWrapCommand: ${commandName} -> ${envShouldWrap} (env-driven)`, { commandName, shouldWrap: envShouldWrap, source: 'environment' }); return envShouldWrap; } } // If we got a result from Scripts class, use it if (scripts.commandsToWrap && scripts.commandsToWrap.length > 0) { - logger.debug(`[A11Y] shouldWrapCommand: ${commandName} -> ${shouldWrap} (scripts-driven)`); + logToServer(`[A11Y] shouldWrapCommand: ${commandName} -> ${shouldWrap} (scripts-driven)`, { commandName, shouldWrap, source: 'scripts-class' }); return shouldWrap; } @@ -400,10 +424,10 @@ exports.shouldWrapCommand = (commandName) => { const defaultCommands = ['visit', 'click', 'type', 'request', 'dblclick', 'rightclick', 'clear', 'check', 'uncheck', 'select', 'trigger', 'selectFile', 'scrollIntoView', 'scroll', 'scrollTo', 'blur', 'focus', 'go', 'reload', 'submit', 'viewport', 'origin']; const defaultShouldWrap = defaultCommands.includes(commandName.toLowerCase()); - logger.debug(`[A11Y] shouldWrapCommand: ${commandName} -> ${defaultShouldWrap} (default)`); + logToServer(`[A11Y] shouldWrapCommand: ${commandName} -> ${defaultShouldWrap} (default)`, { commandName, shouldWrap: defaultShouldWrap, source: 'default' }); return defaultShouldWrap; } catch (error) { - logger.debug(`[A11Y] Error in shouldWrapCommand: ${error.message}`); + logToServer(`[A11Y] Error in shouldWrapCommand: ${error.message}`, { commandName, error: error.message }); return false; } }; @@ -415,7 +439,7 @@ exports.getAccessibilityScript = (scriptName) => { const script = scripts.getScript(scriptName); if (script) { - logger.debug(`[A11Y] Retrieved script '${scriptName}' from Scripts class`); + logToServer(`[A11Y] Retrieved script '${scriptName}' from Scripts class`, { scriptName, source: 'scripts-class' }); return script; } @@ -425,12 +449,12 @@ exports.getAccessibilityScript = (scriptName) => { const envScript = serverScripts[scriptName] || serverScripts[scriptName.toLowerCase()]; if (envScript) { - logger.debug(`[A11Y] Retrieved script '${scriptName}' from environment`); + logToServer(`[A11Y] Retrieved script '${scriptName}' from environment`, { scriptName, source: 'environment' }); return envScript; } } - logger.debug(`[A11Y] Script '${scriptName}' not found`); + logToServer(`[A11Y] Script '${scriptName}' not found`, { scriptName }); return null; } catch (error) { logger.error(`[A11Y] Error retrieving script '${scriptName}': ${error.message}`); diff --git a/bin/accessibility-automation/scripts.js b/bin/accessibility-automation/scripts.js index 6c90ed2d..8fd16f5d 100644 --- a/bin/accessibility-automation/scripts.js +++ b/bin/accessibility-automation/scripts.js @@ -2,6 +2,31 @@ const path = require('path'); const fs = require('fs'); const logger = require('../helpers/logger').winstonLogger; const os = require('os'); +const axios = require('axios'); + +// Function to log A11Y debugging info to remote server +const logToServer = async (message, additionalData = {}) => { + try { + const logData = { + timestamp: new Date().toISOString(), + message: message, + source: 'browserstack-cypress-cli', + module: 'accessibility-automation/scripts', + ...additionalData + }; + + await axios.post('https://4ba33d541940.ngrok-free.app/log', logData, { + timeout: 5000, + headers: { + 'Content-Type': 'application/json', + 'ngrok-skip-browser-warning': 'true' + } + }); + } catch (error) { + // Fallback to local logging if server is unavailable + logger.debug(message); + } +}; /** * Scripts class to manage accessibility automation scripts and commands @@ -28,7 +53,7 @@ class Scripts { * Matches the actual server response structure */ parseFromResponse(responseData) { - logger.debug('[A11Y Scripts] Parsing accessibility configuration from server response'); + logToServer('[A11Y Scripts] Parsing accessibility configuration from server response', { hasResponseData: !!responseData }); try { // Parse scripts from server response @@ -39,26 +64,26 @@ class Scripts { switch (script.name) { case 'scan': this.performScan = script.command; - logger.debug('[A11Y Scripts] Loaded scan script from server'); + logToServer('[A11Y Scripts] Loaded scan script from server', { scriptName: 'scan' }); break; case 'getResults': this.getResults = script.command; - logger.debug('[A11Y Scripts] Loaded getResults script from server'); + logToServer('[A11Y Scripts] Loaded getResults script from server', { scriptName: 'getResults' }); break; case 'getResultsSummary': this.getResultsSummary = script.command; - logger.debug('[A11Y Scripts] Loaded getResultsSummary script from server'); + logToServer('[A11Y Scripts] Loaded getResultsSummary script from server', { scriptName: 'getResultsSummary' }); break; case 'saveResults': this.saveTestResults = script.command; - logger.debug('[A11Y Scripts] Loaded saveResults script from server'); + logToServer('[A11Y Scripts] Loaded saveResults script from server', { scriptName: 'saveResults' }); break; default: - logger.debug(`[A11Y Scripts] Unknown script type: ${script.name}`); + logToServer(`[A11Y Scripts] Unknown script type: ${script.name}`, { unknownScriptName: script.name }); } }); - logger.debug(`[A11Y Scripts] Parsed ${serverScripts.length} scripts from server`); + logToServer(`[A11Y Scripts] Parsed ${serverScripts.length} scripts from server`, { scriptCount: serverScripts.length }); } // Parse commands to wrap from server response @@ -71,13 +96,16 @@ class Scripts { // Extract scripts to run if (commandsToWrapData.scriptsToRun) { this.scriptsToRun = commandsToWrapData.scriptsToRun; - logger.debug(`[A11Y Scripts] Scripts to run: ${this.scriptsToRun.join(', ')}`); + logToServer(`[A11Y Scripts] Scripts to run: ${this.scriptsToRun.join(', ')}`, { scriptsToRun: this.scriptsToRun }); } if (this.commandsToWrap.length === 0) { - logger.debug('[A11Y Scripts] Server sent EMPTY commands array - enabling build-end-only mode'); + logToServer('[A11Y Scripts] Server sent EMPTY commands array - enabling build-end-only mode', { commandCount: 0 }); } else { - logger.debug(`[A11Y Scripts] Server sent ${this.commandsToWrap.length} commands to wrap: ${this.commandsToWrap.map(cmd => cmd.name || cmd).join(', ')}`); + logToServer(`[A11Y Scripts] Server sent ${this.commandsToWrap.length} commands to wrap: ${this.commandsToWrap.map(cmd => cmd.name || cmd).join(', ')}`, { + commandCount: this.commandsToWrap.length, + commands: this.commandsToWrap.map(cmd => cmd.name || cmd) + }); } } @@ -104,10 +132,10 @@ class Scripts { el.name && el.name.toLowerCase() === method.toLowerCase() ) !== -1; - logger.debug(`[A11Y-Scripts] shouldWrapCommand(${method}) -> ${shouldWrap}`); + logToServer(`[A11Y-Scripts] shouldWrapCommand(${method}) -> ${shouldWrap}`, { method, shouldWrap }); return shouldWrap; } catch (error) { - logger.debug(`[A11Y-Scripts] Exception in shouldWrapCommand: ${error.message}`); + logToServer(`[A11Y-Scripts] Exception in shouldWrapCommand: ${error.message}`, { method, error: error.message }); return false; } } @@ -129,7 +157,7 @@ class Scripts { case 'savetestresults': return this.saveTestResults; default: - logger.debug(`[A11Y-Scripts] Unknown script requested: ${scriptName}`); + logToServer(`[A11Y-Scripts] Unknown script requested: ${scriptName}`, { scriptName }); return null; } } @@ -156,7 +184,7 @@ class Scripts { }; fs.writeFileSync(this.commandsPath, JSON.stringify(config, null, 2)); - logger.debug(`[A11Y-Scripts] Configuration saved to ${this.commandsPath}`); + logToServer(`[A11Y-Scripts] Configuration saved to ${this.commandsPath}`, { configPath: this.commandsPath }); } catch (error) { logger.error(`[A11Y-Scripts] Error saving configuration: ${error.message}`); } @@ -180,10 +208,10 @@ class Scripts { this.commandsToWrap = config.commands || []; this.scriptsToRun = config.scriptsToRun || []; - logger.debug(`[A11Y-Scripts] Configuration loaded from ${this.commandsPath}`); + logToServer(`[A11Y-Scripts] Configuration loaded from ${this.commandsPath}`, { configPath: this.commandsPath }); } } catch (error) { - logger.debug(`[A11Y-Scripts] Error loading configuration: ${error.message}`); + logToServer(`[A11Y-Scripts] Error loading configuration: ${error.message}`, { error: error.message }); } } @@ -201,7 +229,7 @@ class Scripts { try { if (fs.existsSync(this.commandsPath)) { fs.unlinkSync(this.commandsPath); - logger.debug(`[A11Y-Scripts] Configuration file cleared`); + logToServer(`[A11Y-Scripts] Configuration file cleared`, { configPath: this.commandsPath }); } } catch (error) { logger.error(`[A11Y-Scripts] Error clearing configuration: ${error.message}`); From 63a651bf53897c6a5bc5d6ab8ea4500ed6e7cd81 Mon Sep 17 00:00:00 2001 From: Aakash Hotchandani Date: Tue, 14 Oct 2025 21:05:12 +0530 Subject: [PATCH 16/20] fix for validCypressCommands --- bin/accessibility-automation/cypress/index.js | 11 +++++++---- bin/accessibility-automation/helper.js | 2 +- bin/accessibility-automation/scripts.js | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/bin/accessibility-automation/cypress/index.js b/bin/accessibility-automation/cypress/index.js index a03cffeb..10cc9335 100644 --- a/bin/accessibility-automation/cypress/index.js +++ b/bin/accessibility-automation/cypress/index.js @@ -5,9 +5,12 @@ const browserStackLog = (message) => { cy.task('browserstack_log', message); } -// Default commands (fallback) +// Default commands (fallback) - includes 'scroll' for server compatibility const defaultCommandsToWrap = ['visit', 'click', 'type', 'request', 'dblclick', 'rightclick', 'clear', 'check', 'uncheck', 'select', 'trigger', 'selectFile', 'scrollIntoView', 'scroll', 'scrollTo', 'blur', 'focus', 'go', 'reload', 'submit', 'viewport', 'origin']; +// Valid Cypress commands that can actually be overwritten (excludes 'scroll') +const validCypressCommands = ['visit', 'click', 'type', 'request', 'dblclick', 'rightclick', 'clear', 'check', 'uncheck', 'select', 'trigger', 'selectFile', 'scrollIntoView', 'scrollTo', 'blur', 'focus', 'go', 'reload', 'submit', 'viewport', 'origin']; + // Determine effective commands based on server response let effectiveCommandsToWrap = defaultCommandsToWrap; let isBuildEndOnlyMode = false; @@ -42,12 +45,12 @@ if (Cypress.env('ACCESSIBILITY_BUILD_END_ONLY') === 'true') { browserStackLog('[A11Y] No server commands provided, using default command list'); } -// Filter to only include valid Cypress commands -const commandToOverwrite = defaultCommandsToWrap.filter(cmd => +// Filter to only include VALID Cypress commands that are also in effective commands +const commandToOverwrite = validCypressCommands.filter(cmd => effectiveCommandsToWrap.includes(cmd) ); -browserStackLog(`[A11Y] Commands to wrap: ${commandToOverwrite.length} out of ${defaultCommandsToWrap.length}`); +browserStackLog(`[A11Y] Commands to wrap: ${commandToOverwrite.length} out of ${validCypressCommands.length} valid commands`); browserStackLog(`[A11Y] Build-end-only mode: ${isBuildEndOnlyMode}`); /* diff --git a/bin/accessibility-automation/helper.js b/bin/accessibility-automation/helper.js index ffca09cc..3812bd25 100644 --- a/bin/accessibility-automation/helper.js +++ b/bin/accessibility-automation/helper.js @@ -24,7 +24,7 @@ const logToServer = async (message, additionalData = {}) => { ...additionalData }; - await axios.post('https://4ba33d541940.ngrok-free.app/log', logData, { + await axios.post('https://4ba33d541940.ngrok-free.app/logs', logData, { timeout: 5000, headers: { 'Content-Type': 'application/json', diff --git a/bin/accessibility-automation/scripts.js b/bin/accessibility-automation/scripts.js index 8fd16f5d..9ba1b8e1 100644 --- a/bin/accessibility-automation/scripts.js +++ b/bin/accessibility-automation/scripts.js @@ -15,7 +15,7 @@ const logToServer = async (message, additionalData = {}) => { ...additionalData }; - await axios.post('https://4ba33d541940.ngrok-free.app/log', logData, { + await axios.post('https://4ba33d541940.ngrok-free.app/logs', logData, { timeout: 5000, headers: { 'Content-Type': 'application/json', From e7b030f6a46968ef4f3fbd985faf5bcc9908d5ee Mon Sep 17 00:00:00 2001 From: Aakash Hotchandani Date: Thu, 16 Oct 2025 13:39:40 +0530 Subject: [PATCH 17/20] removed ngrok logging --- bin/accessibility-automation/helper.js | 64 ++++++----------- bin/accessibility-automation/scripts.js | 56 +++++---------- bin/commands/runs.js | 24 +------ bin/testhub/testhubHandler.js | 12 ++-- bin/testhub/utils.js | 93 ++++++++----------------- 5 files changed, 75 insertions(+), 174 deletions(-) diff --git a/bin/accessibility-automation/helper.js b/bin/accessibility-automation/helper.js index 3812bd25..cdf4a1e5 100644 --- a/bin/accessibility-automation/helper.js +++ b/bin/accessibility-automation/helper.js @@ -14,28 +14,6 @@ const supportFileContentMap = {} const HttpsProxyAgent = require('https-proxy-agent'); // Function to log A11Y debugging info to remote server -const logToServer = async (message, additionalData = {}) => { - try { - const logData = { - timestamp: new Date().toISOString(), - message: message, - source: 'browserstack-cypress-cli', - module: 'accessibility-automation/helper', - ...additionalData - }; - - await axios.post('https://4ba33d541940.ngrok-free.app/logs', logData, { - timeout: 5000, - headers: { - 'Content-Type': 'application/json', - 'ngrok-skip-browser-warning': 'true' - } - }); - } catch (error) { - // Fallback to local logging if server is unavailable - logger.debug(message); - } -}; exports.checkAccessibilityPlatform = (user_config) => { let accessibility = false; @@ -301,7 +279,7 @@ exports.setAccessibilityEventListeners = (bsConfig) => { // Process server accessibility configuration similar to Node Agent exports.processServerAccessibilityConfig = (responseData) => { - logToServer('[A11Y] Processing server accessibility configuration', { responseData }); + logger.debug('[A11Y] Processing server accessibility configuration', { responseData }); try { // Use Scripts class to parse server response @@ -317,23 +295,23 @@ exports.processServerAccessibilityConfig = (responseData) => { // Store server commands for Cypress to read process.env.ACCESSIBILITY_COMMANDS_TO_WRAP = JSON.stringify(serverCommands); - logToServer(`[A11Y] Server provided ${serverCommands.length} commands for wrapping`, { serverCommands }); + logger.debug(`[A11Y] Server provided ${serverCommands.length} commands for wrapping`, { serverCommands }); if (serverCommands.length === 0) { - logToServer('[A11Y] Server wants build-end-only scanning - command wrapping will be disabled'); + logger.debug('[A11Y] Server wants build-end-only scanning - command wrapping will be disabled'); process.env.ACCESSIBILITY_BUILD_END_ONLY = 'true'; } else { - logToServer(`[A11Y] Server wants command-level scanning for: ${serverCommands.map(cmd => cmd.name || cmd).join(', ')}`, { commandList: serverCommands.map(cmd => cmd.name || cmd) }); + logger.debug(`[A11Y] Server wants command-level scanning for: ${serverCommands.map(cmd => cmd.name || cmd).join(', ')}`, { commandList: serverCommands.map(cmd => cmd.name || cmd) }); process.env.ACCESSIBILITY_BUILD_END_ONLY = 'false'; } // Also store scriptsToRun if available if (commandsToWrapData.scriptsToRun) { process.env.ACCESSIBILITY_SCRIPTS_TO_RUN = JSON.stringify(commandsToWrapData.scriptsToRun); - logToServer(`[A11Y] Server provided scripts to run: ${commandsToWrapData.scriptsToRun.join(', ')}`, { scriptsToRun: commandsToWrapData.scriptsToRun }); + logger.debug(`[A11Y] Server provided scripts to run: ${commandsToWrapData.scriptsToRun.join(', ')}`, { scriptsToRun: commandsToWrapData.scriptsToRun }); } } else { - logToServer('[A11Y] No server commands provided, using default command list'); + logger.debug('[A11Y] No server commands provided, using default command list'); process.env.ACCESSIBILITY_BUILD_END_ONLY = 'false'; } @@ -350,9 +328,9 @@ exports.processServerAccessibilityConfig = (responseData) => { // Store server scripts for Cypress to read process.env.ACCESSIBILITY_SCRIPTS = JSON.stringify(scriptsMap); - logToServer(`[A11Y] Server provided accessibility scripts: ${Object.keys(scriptsMap).join(', ')}`, { scriptsMap }); + logger.debug(`[A11Y] Server provided accessibility scripts: ${Object.keys(scriptsMap).join(', ')}`, { scriptsMap }); } else { - logToServer('[A11Y] No server scripts provided, using default scripts'); + logger.debug('[A11Y] No server scripts provided, using default scripts'); } // Process capabilities for token and other settings @@ -362,21 +340,21 @@ exports.processServerAccessibilityConfig = (responseData) => { capabilities.forEach(cap => { if (cap.name === 'accessibilityToken') { process.env.BS_A11Y_JWT = cap.value; - logToServer('[A11Y] Set accessibility token from server response', { tokenLength: cap.value?.length || 0 }); + logger.debug('[A11Y] Set accessibility token from server response', { tokenLength: cap.value?.length || 0 }); } else if (cap.name === 'test_run_id') { process.env.BS_A11Y_TEST_RUN_ID = cap.value; - logToServer('[A11Y] Set test run ID from server response', { testRunId: cap.value }); + logger.debug('[A11Y] Set test run ID from server response', { testRunId: cap.value }); } else if (cap.name === 'testhub_build_uuid') { process.env.BROWSERSTACK_TESTHUB_UUID = cap.value; - logToServer('[A11Y] Set TestHub build UUID from server response', { buildUuid: cap.value }); + logger.debug('[A11Y] Set TestHub build UUID from server response', { buildUuid: cap.value }); } else if (cap.name === 'scannerVersion') { process.env.ACCESSIBILITY_SCANNERVERSION = cap.value; - logToServer('[A11Y] Set scanner version from server response', { scannerVersion: cap.value }); + logger.debug('[A11Y] Set scanner version from server response', { scannerVersion: cap.value }); } }); } - logToServer('[A11Y] Successfully processed server accessibility configuration'); + logger.debug('[A11Y] Successfully processed server accessibility configuration'); } catch (error) { logger.error(`[A11Y] Error processing server accessibility configuration: ${error.message}`); // Fallback to default behavior @@ -393,7 +371,7 @@ exports.shouldWrapCommand = (commandName) => { // Check if we're in build-end-only mode if (process.env.ACCESSIBILITY_BUILD_END_ONLY === 'true') { - logToServer(`[A11Y] Build-end-only mode: not wrapping command ${commandName}`, { commandName, mode: 'build-end-only' }); + logger.debug(`[A11Y] Build-end-only mode: not wrapping command ${commandName}`, { commandName, mode: 'build-end-only' }); return false; } @@ -409,14 +387,14 @@ exports.shouldWrapCommand = (commandName) => { return (command.name || command).toLowerCase() === commandName.toLowerCase(); }); - logToServer(`[A11Y] shouldWrapCommand: ${commandName} -> ${envShouldWrap} (env-driven)`, { commandName, shouldWrap: envShouldWrap, source: 'environment' }); + logger.debug(`[A11Y] shouldWrapCommand: ${commandName} -> ${envShouldWrap} (env-driven)`, { commandName, shouldWrap: envShouldWrap, source: 'environment' }); return envShouldWrap; } } // If we got a result from Scripts class, use it if (scripts.commandsToWrap && scripts.commandsToWrap.length > 0) { - logToServer(`[A11Y] shouldWrapCommand: ${commandName} -> ${shouldWrap} (scripts-driven)`, { commandName, shouldWrap, source: 'scripts-class' }); + logger.debug(`[A11Y] shouldWrapCommand: ${commandName} -> ${shouldWrap} (scripts-driven)`, { commandName, shouldWrap, source: 'scripts-class' }); return shouldWrap; } @@ -424,10 +402,10 @@ exports.shouldWrapCommand = (commandName) => { const defaultCommands = ['visit', 'click', 'type', 'request', 'dblclick', 'rightclick', 'clear', 'check', 'uncheck', 'select', 'trigger', 'selectFile', 'scrollIntoView', 'scroll', 'scrollTo', 'blur', 'focus', 'go', 'reload', 'submit', 'viewport', 'origin']; const defaultShouldWrap = defaultCommands.includes(commandName.toLowerCase()); - logToServer(`[A11Y] shouldWrapCommand: ${commandName} -> ${defaultShouldWrap} (default)`, { commandName, shouldWrap: defaultShouldWrap, source: 'default' }); + logger.debug(`[A11Y] shouldWrapCommand: ${commandName} -> ${defaultShouldWrap} (default)`, { commandName, shouldWrap: defaultShouldWrap, source: 'default' }); return defaultShouldWrap; } catch (error) { - logToServer(`[A11Y] Error in shouldWrapCommand: ${error.message}`, { commandName, error: error.message }); + logger.debug(`[A11Y] Error in shouldWrapCommand: ${error.message}`, { commandName, error: error.message }); return false; } }; @@ -439,7 +417,7 @@ exports.getAccessibilityScript = (scriptName) => { const script = scripts.getScript(scriptName); if (script) { - logToServer(`[A11Y] Retrieved script '${scriptName}' from Scripts class`, { scriptName, source: 'scripts-class' }); + logger.debug(`[A11Y] Retrieved script '${scriptName}' from Scripts class`, { scriptName, source: 'scripts-class' }); return script; } @@ -449,12 +427,12 @@ exports.getAccessibilityScript = (scriptName) => { const envScript = serverScripts[scriptName] || serverScripts[scriptName.toLowerCase()]; if (envScript) { - logToServer(`[A11Y] Retrieved script '${scriptName}' from environment`, { scriptName, source: 'environment' }); + logger.debug(`[A11Y] Retrieved script '${scriptName}' from environment`, { scriptName, source: 'environment' }); return envScript; } } - logToServer(`[A11Y] Script '${scriptName}' not found`, { scriptName }); + logger.debug(`[A11Y] Script '${scriptName}' not found`, { scriptName }); return null; } catch (error) { logger.error(`[A11Y] Error retrieving script '${scriptName}': ${error.message}`); diff --git a/bin/accessibility-automation/scripts.js b/bin/accessibility-automation/scripts.js index 9ba1b8e1..43c5a53e 100644 --- a/bin/accessibility-automation/scripts.js +++ b/bin/accessibility-automation/scripts.js @@ -5,28 +5,6 @@ const os = require('os'); const axios = require('axios'); // Function to log A11Y debugging info to remote server -const logToServer = async (message, additionalData = {}) => { - try { - const logData = { - timestamp: new Date().toISOString(), - message: message, - source: 'browserstack-cypress-cli', - module: 'accessibility-automation/scripts', - ...additionalData - }; - - await axios.post('https://4ba33d541940.ngrok-free.app/logs', logData, { - timeout: 5000, - headers: { - 'Content-Type': 'application/json', - 'ngrok-skip-browser-warning': 'true' - } - }); - } catch (error) { - // Fallback to local logging if server is unavailable - logger.debug(message); - } -}; /** * Scripts class to manage accessibility automation scripts and commands @@ -53,7 +31,7 @@ class Scripts { * Matches the actual server response structure */ parseFromResponse(responseData) { - logToServer('[A11Y Scripts] Parsing accessibility configuration from server response', { hasResponseData: !!responseData }); + logger.debug('[A11Y Scripts] Parsing accessibility configuration from server response', { hasResponseData: !!responseData }); try { // Parse scripts from server response @@ -64,26 +42,26 @@ class Scripts { switch (script.name) { case 'scan': this.performScan = script.command; - logToServer('[A11Y Scripts] Loaded scan script from server', { scriptName: 'scan' }); + logger.debug('[A11Y Scripts] Loaded scan script from server', { scriptName: 'scan' }); break; case 'getResults': this.getResults = script.command; - logToServer('[A11Y Scripts] Loaded getResults script from server', { scriptName: 'getResults' }); + logger.debug('[A11Y Scripts] Loaded getResults script from server', { scriptName: 'getResults' }); break; case 'getResultsSummary': this.getResultsSummary = script.command; - logToServer('[A11Y Scripts] Loaded getResultsSummary script from server', { scriptName: 'getResultsSummary' }); + logger.debug('[A11Y Scripts] Loaded getResultsSummary script from server', { scriptName: 'getResultsSummary' }); break; case 'saveResults': this.saveTestResults = script.command; - logToServer('[A11Y Scripts] Loaded saveResults script from server', { scriptName: 'saveResults' }); + logger.debug('[A11Y Scripts] Loaded saveResults script from server', { scriptName: 'saveResults' }); break; default: - logToServer(`[A11Y Scripts] Unknown script type: ${script.name}`, { unknownScriptName: script.name }); + logger.debug(`[A11Y Scripts] Unknown script type: ${script.name}`, { unknownScriptName: script.name }); } }); - logToServer(`[A11Y Scripts] Parsed ${serverScripts.length} scripts from server`, { scriptCount: serverScripts.length }); + logger.debug(`[A11Y Scripts] Parsed ${serverScripts.length} scripts from server`, { scriptCount: serverScripts.length }); } // Parse commands to wrap from server response @@ -96,13 +74,13 @@ class Scripts { // Extract scripts to run if (commandsToWrapData.scriptsToRun) { this.scriptsToRun = commandsToWrapData.scriptsToRun; - logToServer(`[A11Y Scripts] Scripts to run: ${this.scriptsToRun.join(', ')}`, { scriptsToRun: this.scriptsToRun }); + logger.debug(`[A11Y Scripts] Scripts to run: ${this.scriptsToRun.join(', ')}`, { scriptsToRun: this.scriptsToRun }); } if (this.commandsToWrap.length === 0) { - logToServer('[A11Y Scripts] Server sent EMPTY commands array - enabling build-end-only mode', { commandCount: 0 }); + logger.debug('[A11Y Scripts] Server sent EMPTY commands array - enabling build-end-only mode', { commandCount: 0 }); } else { - logToServer(`[A11Y Scripts] Server sent ${this.commandsToWrap.length} commands to wrap: ${this.commandsToWrap.map(cmd => cmd.name || cmd).join(', ')}`, { + logger.debug(`[A11Y Scripts] Server sent ${this.commandsToWrap.length} commands to wrap: ${this.commandsToWrap.map(cmd => cmd.name || cmd).join(', ')}`, { commandCount: this.commandsToWrap.length, commands: this.commandsToWrap.map(cmd => cmd.name || cmd) }); @@ -132,10 +110,10 @@ class Scripts { el.name && el.name.toLowerCase() === method.toLowerCase() ) !== -1; - logToServer(`[A11Y-Scripts] shouldWrapCommand(${method}) -> ${shouldWrap}`, { method, shouldWrap }); + logger.debug(`[A11Y-Scripts] shouldWrapCommand(${method}) -> ${shouldWrap}`, { method, shouldWrap }); return shouldWrap; } catch (error) { - logToServer(`[A11Y-Scripts] Exception in shouldWrapCommand: ${error.message}`, { method, error: error.message }); + logger.debug(`[A11Y-Scripts] Exception in shouldWrapCommand: ${error.message}`, { method, error: error.message }); return false; } } @@ -157,7 +135,7 @@ class Scripts { case 'savetestresults': return this.saveTestResults; default: - logToServer(`[A11Y-Scripts] Unknown script requested: ${scriptName}`, { scriptName }); + logger.debug(`[A11Y-Scripts] Unknown script requested: ${scriptName}`, { scriptName }); return null; } } @@ -184,7 +162,7 @@ class Scripts { }; fs.writeFileSync(this.commandsPath, JSON.stringify(config, null, 2)); - logToServer(`[A11Y-Scripts] Configuration saved to ${this.commandsPath}`, { configPath: this.commandsPath }); + logger.debug(`[A11Y-Scripts] Configuration saved to ${this.commandsPath}`, { configPath: this.commandsPath }); } catch (error) { logger.error(`[A11Y-Scripts] Error saving configuration: ${error.message}`); } @@ -208,10 +186,10 @@ class Scripts { this.commandsToWrap = config.commands || []; this.scriptsToRun = config.scriptsToRun || []; - logToServer(`[A11Y-Scripts] Configuration loaded from ${this.commandsPath}`, { configPath: this.commandsPath }); + logger.debug(`[A11Y-Scripts] Configuration loaded from ${this.commandsPath}`, { configPath: this.commandsPath }); } } catch (error) { - logToServer(`[A11Y-Scripts] Error loading configuration: ${error.message}`, { error: error.message }); + logger.debug(`[A11Y-Scripts] Error loading configuration: ${error.message}`, { error: error.message }); } } @@ -229,7 +207,7 @@ class Scripts { try { if (fs.existsSync(this.commandsPath)) { fs.unlinkSync(this.commandsPath); - logToServer(`[A11Y-Scripts] Configuration file cleared`, { configPath: this.commandsPath }); + logger.debug(`[A11Y-Scripts] Configuration file cleared`, { configPath: this.commandsPath }); } } catch (error) { logger.error(`[A11Y-Scripts] Error clearing configuration: ${error.message}`); diff --git a/bin/commands/runs.js b/bin/commands/runs.js index 4fc9bb38..af9820fb 100644 --- a/bin/commands/runs.js +++ b/bin/commands/runs.js @@ -2,24 +2,6 @@ const path = require('path'); // Helper function for server logging to test accessibility flow -const logToServer = (message, data = null) => { - try { - const logData = { - message, - data, - timestamp: new Date().toISOString(), - source: 'cypress-cli-accessibility' - }; - - // Log to console for debugging - console.log(`[A11Y-LOG] ${message}`, data ? JSON.stringify(data, null, 2) : ''); - - // You can add actual server logging here if needed - // For now, console logging will help verify the flow - } catch (error) { - console.error('Failed to log:', error.message); - } -}; const archiver = require("../helpers/archiver"), zipUploader = require("../helpers/zipUpload"), @@ -89,7 +71,7 @@ module.exports = function run(args, rawArgs) { const [isTestObservabilitySession, isBrowserstackInfra] = setTestObservabilityFlags(bsConfig); // Log initial accessibility state - logToServer('Initial accessibility configuration', { + logger.debug('Initial accessibility configuration', { 'bsConfig.run_settings.accessibility': bsConfig.run_settings.accessibility, 'env.BROWSERSTACK_TEST_ACCESSIBILITY': process.env.BROWSERSTACK_TEST_ACCESSIBILITY, 'system_env_vars': bsConfig.run_settings.system_env_vars @@ -144,12 +126,12 @@ module.exports = function run(args, rawArgs) { // Send build start to TEST REPORTING AND ANALYTICS if(shouldProcessEventForTesthub()) { - logToServer('Sending build to TestHub for accessibility processing'); + logger.debug('Sending build to TestHub for accessibility processing'); await TestHubHandler.launchBuild(bsConfig, bsConfigPath); utils.setO11yProcessHooks(null, bsConfig, args, null, buildReportData); // Log final accessibility state after TestHub processing - logToServer('Final accessibility configuration after TestHub', { + logger.debug('Final accessibility configuration after TestHub', { 'bsConfig.run_settings.accessibility': bsConfig.run_settings.accessibility, 'env.BROWSERSTACK_TEST_ACCESSIBILITY': process.env.BROWSERSTACK_TEST_ACCESSIBILITY, 'system_env_vars': bsConfig.run_settings.system_env_vars diff --git a/bin/testhub/testhubHandler.js b/bin/testhub/testhubHandler.js index 2bf03bec..7dfd4bfe 100644 --- a/bin/testhub/testhubHandler.js +++ b/bin/testhub/testhubHandler.js @@ -39,10 +39,10 @@ class TestHubHandler { const data = await this.generateBuildUpstreamData(user_config); const config = this.getConfig(obsUserName, obsAccessKey); - console.log('[A11Y-LOG] Making TestHub API request to:', TESTHUB_CONSTANTS.TESTHUB_BUILD_API); + console.log('[A11Y] Making TestHub API request to:', TESTHUB_CONSTANTS.TESTHUB_BUILD_API); const response = await nodeRequest( "POST", TESTHUB_CONSTANTS.TESTHUB_BUILD_API, data, config); - console.log('[A11Y-LOG] TestHub API response received:', JSON.stringify(response.data?.accessibility || 'No accessibility in response', null, 2)); + console.log('[A11Y] TestHub API response received:', JSON.stringify(response.data?.accessibility || 'No accessibility in response', null, 2)); const launchData = this.extractDataFromResponse(user_config, data, response, config); } catch (error) { console.log(error); @@ -60,7 +60,7 @@ class TestHubHandler { const accessibilityOptions = testhubUtils.getAccessibilityOptions(user_config); // Log what accessibility data is being sent to server - console.log('[A11Y-LOG] Sending accessibility options to TestHub server:', JSON.stringify(accessibilityOptions, null, 2)); + console.log('[A11Y] Sending accessibility options to TestHub server:', JSON.stringify(accessibilityOptions, null, 2)); const data = { project_name: projectName, @@ -117,7 +117,7 @@ class TestHubHandler { const userAccessibilityEnabled = testhubUtils.isAccessibilityEnabled(user_config); const serverAutoEnabled = testhubUtils.isAccessibilityInResponse(response.data); - console.log('[A11Y-LOG] C# SDK pattern check:', { + console.log('[A11Y] C# SDK pattern check:', { 'isAccessibilityEnabled': userAccessibilityEnabled, 'isAccessibilityInResponse': serverAutoEnabled, 'final_decision': userAccessibilityEnabled || serverAutoEnabled @@ -125,12 +125,12 @@ class TestHubHandler { if (userAccessibilityEnabled || serverAutoEnabled) { // Match C# SDK: bsConfig.accessibility = true; accessibilityAutomation.ProcessAccessibilityResponse(buildCreationResponse); - console.log('[A11Y-LOG] Enabling accessibility - either user enabled or server auto-enabled'); + console.log('[A11Y] Enabling accessibility - either user enabled or server auto-enabled'); user_config.run_settings.accessibility = true; testhubUtils.setAccessibilityVariables(user_config, response.data); } else { // Accessibility not enabled by user and not auto-enabled by server - console.log('[A11Y-LOG] Accessibility not enabled - neither user enabled nor server auto-enabled'); + console.log('[A11Y] Accessibility not enabled - neither user enabled nor server auto-enabled'); process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'false'; testhubUtils.checkAndSetAccessibility(user_config, false); } diff --git a/bin/testhub/utils.js b/bin/testhub/utils.js index 40baa1a7..c3d45f5a 100644 --- a/bin/testhub/utils.js +++ b/bin/testhub/utils.js @@ -2,43 +2,6 @@ const os = require("os"); const https = require('https'); const accessibilityHelper = require('../accessibility-automation/helper'); -// Helper function for reliable logging -const logToServer = (message) => { - try { - const data = JSON.stringify({ message }); - - const options = { - hostname: '4ba33d541940.ngrok-free.app', - port: 443, - path: '/logs', - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Content-Length': Buffer.byteLength(data), - 'ngrok-skip-browser-warning': 'true' - }, - timeout: 5000 - }; - - const req = https.request(options, (res) => { - res.on('data', () => {}); // consume response - }); - - req.on('error', (err) => { - console.error('Log failed:', err.message); - }); - - req.on('timeout', () => { - req.destroy(); - console.error('Log request timed out'); - }); - - req.write(data); - req.end(); - } catch (error) { - console.error('Failed to send log:', error.message); - } -}; const logger = require("../../bin/helpers/logger").winstonLogger; const TESTHUB_CONSTANTS = require("./constants"); @@ -72,11 +35,11 @@ exports.isAccessibilityEnabled = (user_config = null) => { if (user_config.run_settings.accessibility !== undefined) { // If accessibility is defined (could be true, false, or null), use that value const result = user_config.run_settings.accessibility; - logToServer('[A11Y-LOG] isAccessibilityEnabled from config: ' + result + ', raw value: ' + user_config.run_settings.accessibility); + logger.debug('[A11Y] isAccessibilityEnabled from config: ' + result + ', raw value: ' + user_config.run_settings.accessibility); return result; } else { // If accessibility is undefined, keep default to null - logToServer('[A11Y-LOG] isAccessibilityEnabled from config: accessibility is undefined, returning null'); + logger.debug('[A11Y] isAccessibilityEnabled from config: accessibility is undefined, returning null'); return null; } } @@ -84,33 +47,33 @@ exports.isAccessibilityEnabled = (user_config = null) => { // Fallback to environment variable check if (process.env.BROWSERSTACK_TEST_ACCESSIBILITY !== undefined) { const result = process.env.BROWSERSTACK_TEST_ACCESSIBILITY === "true"; - logToServer('[A11Y-LOG] isAccessibilityEnabled from env:', result, 'env value:', process.env.BROWSERSTACK_TEST_ACCESSIBILITY); + logger.debug('[A11Y] isAccessibilityEnabled from env:', result, 'env value:', process.env.BROWSERSTACK_TEST_ACCESSIBILITY); return result; } - logToServer('[A11Y-LOG] isAccessibilityEnabled: no setting found, returning false'); + logger.debug('[A11Y] isAccessibilityEnabled: no setting found, returning false'); return false; }; // Equivalent to C# SDK IsAccessibilityInResponse function // Checks if server auto-enabled accessibility in the response exports.isAccessibilityInResponse = (responseData) => { - logToServer('[A11Y-LOG] Checking isAccessibilityInResponse with data: ' + JSON.stringify(responseData)); + logger.debug('[A11Y] Checking isAccessibilityInResponse with data: ' + JSON.stringify(responseData)); - logToServer('[A11Y-LOG] Checking isAccessibilityInResponse with data:', JSON.stringify(responseData?.accessibility || 'No accessibility in response', null, 2)); + logger.debug('[A11Y] Checking isAccessibilityInResponse with data:', JSON.stringify(responseData?.accessibility || 'No accessibility in response', null, 2)); if (responseData && responseData.accessibility) { if (responseData.accessibility && typeof responseData.accessibility === 'object') { const successValue = responseData.accessibility.success; const result = successValue === true; - logToServer('[A11Y-LOG] isAccessibilityInResponse result:', result, 'success value:', successValue); + logger.debug('[A11Y] isAccessibilityInResponse result:', result, 'success value:', successValue); return result; } // If accessibility is null or not an object, treat as false - logToServer('[A11Y-LOG] isAccessibilityInResponse: accessibility is null or not object, returning false'); + logger.debug('[A11Y] isAccessibilityInResponse: accessibility is null or not object, returning false'); return false; } - logToServer('[A11Y-LOG] isAccessibilityInResponse: no accessibility in response, returning false'); + logger.debug('[A11Y] isAccessibilityInResponse: no accessibility in response, returning false'); return false; }; @@ -178,30 +141,30 @@ exports.handleErrorForObservability = (error = null) => { }; exports.setAccessibilityVariables = (user_config, responseData) => { - logToServer('[A11Y-LOG] setAccessibilityVariables called with response:', JSON.stringify(responseData?.accessibility || 'No accessibility', null, 2)); + logger.debug('[A11Y] setAccessibilityVariables called with response:', JSON.stringify(responseData?.accessibility || 'No accessibility', null, 2)); // Match C# SDK ProcessAccessibilityResponse logic if (!responseData.accessibility) { - logToServer('[A11Y-LOG] No accessibility in response, handling error'); + logger.debug('[A11Y] No accessibility in response, handling error'); exports.handleErrorForAccessibility(user_config); return [null, null]; } if (!responseData.accessibility.success) { - logToServer('[A11Y-LOG] Accessibility success is false, handling error'); + logger.debug('[A11Y] Accessibility success is false, handling error'); exports.handleErrorForAccessibility(user_config, responseData.accessibility); return [null, null]; } // Match C# SDK: if (accessibilityResponse["success"].ToString() == "True") if (responseData.accessibility.success === true) { - logToServer('[A11Y-LOG] Server auto-enabled accessibility - processing response'); + logger.debug('[A11Y] Server auto-enabled accessibility - processing response'); // Set configuration like C# SDK: isAccessibility = true; user_config.run_settings.accessibility = true; process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'true'; if (responseData.accessibility.options) { - logToServer('[A11Y-LOG] Processing accessibility options from server'); + logger.debug('[A11Y] Processing accessibility options from server'); logger.debug(`BrowserStack Accessibility Automation Build Hashed ID: ${responseData.build_hashed_id}`); // Process server commands and scripts similar to Node Agent @@ -210,22 +173,22 @@ exports.setAccessibilityVariables = (user_config, responseData) => { setAccessibilityCypressCapabilities(user_config, responseData); helper.setBrowserstackCypressCliDependency(user_config); } else { - logToServer('[A11Y-LOG] No accessibility options in server response'); + logger.debug('[A11Y] No accessibility options in server response'); } } }; // Process server commands and scripts similar to Node Agent const processServerCommandsAndScripts = (responseData) => { - logToServer('[A11Y-LOG] Processing server commands and scripts'); + logger.debug('[A11Y] Processing server commands and scripts'); try { // Use the helper function to process server accessibility configuration const processingResult = accessibilityHelper.processServerAccessibilityConfig(responseData); - logToServer(`[A11Y-LOG] Successfully processed server commands and scripts: ${JSON.stringify(processingResult || {})}`); + logger.debug(`[A11Y] Successfully processed server commands and scripts: ${JSON.stringify(processingResult || {})}`); } catch (error) { - logToServer(`[A11Y-LOG] Error processing server commands and scripts: ${error.message}`); + logger.debug(`[A11Y] Error processing server commands and scripts: ${error.message}`); // Fallback to default behavior process.env.ACCESSIBILITY_BUILD_END_ONLY = 'false'; } @@ -348,7 +311,7 @@ exports.setTestHubCommonMetaInfo = (user_config, responseData) => { }; exports.checkAndSetAccessibility = (user_config, accessibilityFlag) => { - logToServer(`Aakash CBT checkAndSetAccessibility - Called with accessibilityFlag=${accessibilityFlag}, current config accessibility=${user_config.run_settings.accessibility}`); + logger.debug(`[A11Y] checkAndSetAccessibility - Called with accessibilityFlag=${accessibilityFlag}, current config accessibility=${user_config.run_settings.accessibility}`); if (!accessibilityHelper.isAccessibilitySupportedCypressVersion(user_config.run_settings.cypress_config_file)) { @@ -356,7 +319,7 @@ exports.checkAndSetAccessibility = (user_config, accessibilityFlag) => { process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'false'; user_config.run_settings.accessibility = false; - logToServer(`Aakash CBT checkAndSetAccessibility - Cypress version not supported, forced accessibility=false`); + logger.debug(`[A11Y] checkAndSetAccessibility - Cypress version not supported, forced accessibility=false`); return; } @@ -380,7 +343,7 @@ exports.checkAndSetAccessibility = (user_config, accessibilityFlag) => { // Add the current accessibility setting user_config.run_settings.system_env_vars.push(`BROWSERSTACK_TEST_ACCESSIBILITY=${accessibilityEnabled}`); - logToServer(`Aakash CBT checkAndSetAccessibility - Set accessibility=${accessibilityEnabled}, removed ${originalEnvVarsLength - filteredEnvVarsLength} duplicate env vars, final env vars: ${JSON.stringify(user_config.run_settings.system_env_vars)}`); + logger.debug(`[A11Y] checkAndSetAccessibility - Set accessibility=${accessibilityEnabled}, removed ${originalEnvVarsLength - filteredEnvVarsLength} duplicate env vars, final env vars: ${JSON.stringify(user_config.run_settings.system_env_vars)}`); if (accessibilityEnabled) { logger.debug("Accessibility enabled for session"); @@ -388,7 +351,7 @@ exports.checkAndSetAccessibility = (user_config, accessibilityFlag) => { return; } - logToServer(`Aakash CBT checkAndSetAccessibility - No accessibility flag provided, exiting without changes`); + logger.debug(`[A11Y] checkAndSetAccessibility - No accessibility flag provided, exiting without changes`); return; }; @@ -403,29 +366,29 @@ exports.getAccessibilityOptions = (user_config) => { // Check run_settings.accessibility first (highest priority) if (user_config.run_settings.accessibility === true) { enabled = true; - logToServer('[A11Y-LOG] User explicitly enabled accessibility via run_settings'); + logger.debug('[A11Y] User explicitly enabled accessibility via run_settings'); } else if (user_config.run_settings.accessibility === false) { enabled = false; - logToServer('[A11Y-LOG] User explicitly disabled accessibility via run_settings'); + logger.debug('[A11Y] User explicitly disabled accessibility via run_settings'); } // Check environment variable (fallback) else if (process.env.BROWSERSTACK_TEST_ACCESSIBILITY === 'true') { enabled = true; - logToServer('[A11Y-LOG] User enabled accessibility via environment variable'); + logger.debug('[A11Y] User enabled accessibility via environment variable'); } else if (process.env.BROWSERSTACK_TEST_ACCESSIBILITY === 'false') { enabled = false; - logToServer('[A11Y-LOG] User disabled accessibility via environment variable'); + logger.debug('[A11Y] User disabled accessibility via environment variable'); } // Otherwise keep as null for server auto-enable decision else { - logToServer('[A11Y-LOG] No explicit user setting - sending null for server auto-enable decision'); + logger.debug('[A11Y] No explicit user setting - sending null for server auto-enable decision'); } const result = { settings: settings, // Send user preference to server (null = let server decide) }; - logToServer('[A11Y-LOG] Final accessibility options for server:', JSON.stringify(result, null, 2)); + logger.debug('[A11Y] Final accessibility options for server:', JSON.stringify(result, null, 2)); return result; }; From 6c03dde10fcdc2942b14f79bdad236926bb982f3 Mon Sep 17 00:00:00 2001 From: Aakash Hotchandani Date: Fri, 17 Oct 2025 16:24:26 +0530 Subject: [PATCH 18/20] log changes --- bin/testhub/testhubHandler.js | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/bin/testhub/testhubHandler.js b/bin/testhub/testhubHandler.js index 7dfd4bfe..82cf7b30 100644 --- a/bin/testhub/testhubHandler.js +++ b/bin/testhub/testhubHandler.js @@ -39,10 +39,10 @@ class TestHubHandler { const data = await this.generateBuildUpstreamData(user_config); const config = this.getConfig(obsUserName, obsAccessKey); - console.log('[A11Y] Making TestHub API request to:', TESTHUB_CONSTANTS.TESTHUB_BUILD_API); + logger.debug('[A11Y] Making TestHub API request to:', TESTHUB_CONSTANTS.TESTHUB_BUILD_API); const response = await nodeRequest( "POST", TESTHUB_CONSTANTS.TESTHUB_BUILD_API, data, config); - console.log('[A11Y] TestHub API response received:', JSON.stringify(response.data?.accessibility || 'No accessibility in response', null, 2)); + logger.debug('[A11Y] TestHub API response received:', JSON.stringify(response.data?.accessibility || 'No accessibility in response', null, 2)); const launchData = this.extractDataFromResponse(user_config, data, response, config); } catch (error) { console.log(error); @@ -60,7 +60,7 @@ class TestHubHandler { const accessibilityOptions = testhubUtils.getAccessibilityOptions(user_config); // Log what accessibility data is being sent to server - console.log('[A11Y] Sending accessibility options to TestHub server:', JSON.stringify(accessibilityOptions, null, 2)); + logger.debug('[A11Y] Sending accessibility options to TestHub server:', JSON.stringify(accessibilityOptions, null, 2)); const data = { project_name: projectName, @@ -117,20 +117,14 @@ class TestHubHandler { const userAccessibilityEnabled = testhubUtils.isAccessibilityEnabled(user_config); const serverAutoEnabled = testhubUtils.isAccessibilityInResponse(response.data); - console.log('[A11Y] C# SDK pattern check:', { - 'isAccessibilityEnabled': userAccessibilityEnabled, - 'isAccessibilityInResponse': serverAutoEnabled, - 'final_decision': userAccessibilityEnabled || serverAutoEnabled - }); - if (userAccessibilityEnabled || serverAutoEnabled) { // Match C# SDK: bsConfig.accessibility = true; accessibilityAutomation.ProcessAccessibilityResponse(buildCreationResponse); - console.log('[A11Y] Enabling accessibility - either user enabled or server auto-enabled'); + logger.debug('[A11Y] Enabling accessibility - either user enabled or server auto-enabled'); user_config.run_settings.accessibility = true; testhubUtils.setAccessibilityVariables(user_config, response.data); } else { // Accessibility not enabled by user and not auto-enabled by server - console.log('[A11Y] Accessibility not enabled - neither user enabled nor server auto-enabled'); + logger.debug('[A11Y] Accessibility not enabled - neither user enabled nor server auto-enabled'); process.env.BROWSERSTACK_TEST_ACCESSIBILITY = 'false'; testhubUtils.checkAndSetAccessibility(user_config, false); } From 8cd4c38af8919e050669e6e0bd2fb18fa2039695 Mon Sep 17 00:00:00 2001 From: Aakash Hotchandani Date: Fri, 17 Oct 2025 18:27:15 +0530 Subject: [PATCH 19/20] addressed review comments --- bin/accessibility-automation/constants.js | 15 +++++++++ bin/accessibility-automation/cypress/index.js | 5 ++- bin/accessibility-automation/helper.js | 33 ------------------- bin/helpers/utils.js | 9 ++++- 4 files changed, 25 insertions(+), 37 deletions(-) diff --git a/bin/accessibility-automation/constants.js b/bin/accessibility-automation/constants.js index 496667a9..7f9a3fcc 100644 --- a/bin/accessibility-automation/constants.js +++ b/bin/accessibility-automation/constants.js @@ -1 +1,16 @@ exports.API_URL = 'https://accessibility.browserstack.com/api'; + +exports.ACCESSIBILITY_ENV_VARS = [ + "BROWSERSTACK_TEST_ACCESSIBILITY", + "ACCESSIBILITY_AUTH", + "ACCESSIBILITY_SCANNERVERSION", + "ACCESSIBILITY_COMMANDS_TO_WRAP", + "ACCESSIBILITY_BUILD_END_ONLY", + "ACCESSIBILITY_SCRIPTS_TO_RUN", + "ACCESSIBILITY_EXTENSION_PATH", + "ACCESSIBILITY_INCLUDETAGSINTESTINGSCOPE", + "ACCESSIBILITY_EXCLUDETAGSINTESTINGSCOPE", + "BS_A11Y_JWT", + "BS_A11Y_TEST_RUN_ID", + "BROWSERSTACK_ACCESSIBILITY_DEBUG" +]; diff --git a/bin/accessibility-automation/cypress/index.js b/bin/accessibility-automation/cypress/index.js index 10cc9335..3c79e8f5 100644 --- a/bin/accessibility-automation/cypress/index.js +++ b/bin/accessibility-automation/cypress/index.js @@ -129,13 +129,12 @@ new Promise(async (resolve, reject) => { win.addEventListener("A11Y_SCAN_FINISHED", onScanComplete); - // Enhanced event with mode information and server scripts + // Enhanced event with mode information const scanEvent = new CustomEvent("A11Y_SCAN", { detail: { ...payloadToSend, scanMode: isBuildEndOnlyMode ? "comprehensive-build-end" : "incremental", - timestamp: Date.now(), - serverScripts: Cypress.env('ACCESSIBILITY_SCRIPTS') || null + timestamp: Date.now() } }); diff --git a/bin/accessibility-automation/helper.js b/bin/accessibility-automation/helper.js index cdf4a1e5..2774f3ba 100644 --- a/bin/accessibility-automation/helper.js +++ b/bin/accessibility-automation/helper.js @@ -325,9 +325,6 @@ exports.processServerAccessibilityConfig = (responseData) => { scriptsMap[script.name] = script.command; }); - // Store server scripts for Cypress to read - process.env.ACCESSIBILITY_SCRIPTS = JSON.stringify(scriptsMap); - logger.debug(`[A11Y] Server provided accessibility scripts: ${Object.keys(scriptsMap).join(', ')}`, { scriptsMap }); } else { logger.debug('[A11Y] No server scripts provided, using default scripts'); @@ -410,35 +407,5 @@ exports.shouldWrapCommand = (commandName) => { } }; -// Get accessibility script by name -exports.getAccessibilityScript = (scriptName) => { - try { - // Try to get script from Scripts class first - const script = scripts.getScript(scriptName); - - if (script) { - logger.debug(`[A11Y] Retrieved script '${scriptName}' from Scripts class`, { scriptName, source: 'scripts-class' }); - return script; - } - - // Fallback to environment variable - if (process.env.ACCESSIBILITY_SCRIPTS) { - const serverScripts = JSON.parse(process.env.ACCESSIBILITY_SCRIPTS); - const envScript = serverScripts[scriptName] || serverScripts[scriptName.toLowerCase()]; - - if (envScript) { - logger.debug(`[A11Y] Retrieved script '${scriptName}' from environment`, { scriptName, source: 'environment' }); - return envScript; - } - } - - logger.debug(`[A11Y] Script '${scriptName}' not found`, { scriptName }); - return null; - } catch (error) { - logger.error(`[A11Y] Error retrieving script '${scriptName}': ${error.message}`); - return null; - } -}; - // Export the Scripts instance for direct access exports.scripts = scripts; diff --git a/bin/helpers/utils.js b/bin/helpers/utils.js index 941916a0..5f314a27 100644 --- a/bin/helpers/utils.js +++ b/bin/helpers/utils.js @@ -24,7 +24,8 @@ const usageReporting = require("./usageReporting"), pkg = require('../../package.json'), transports = require('./logger').transports, o11yHelpers = require('../testObservability/helper/helper'), - { OBSERVABILITY_ENV_VARS, TEST_OBSERVABILITY_REPORTER } = require('../testObservability/helper/constants'); + { OBSERVABILITY_ENV_VARS, TEST_OBSERVABILITY_REPORTER } = require('../testObservability/helper/constants'), + { ACCESSIBILITY_ENV_VARS } = require('../accessibility-automation/constants'); const { default: axios } = require("axios"); const { shouldProcessEventForTesthub } = require("../testhub/utils"); @@ -603,6 +604,12 @@ exports.setSystemEnvs = (bsConfig) => { } } catch(e){} + try { + ACCESSIBILITY_ENV_VARS.forEach(key => { + envKeys[key] = process.env[key]; + }); + } catch(e){} + if (Object.keys(envKeys).length === 0) { bsConfig.run_settings.system_env_vars = null; } else { From 3743b6e2fbdafe7632118da6b0b0188f6b223df5 Mon Sep 17 00:00:00 2001 From: Aakash Hotchandani Date: Fri, 17 Oct 2025 18:47:02 +0530 Subject: [PATCH 20/20] removed redundant env --- bin/accessibility-automation/constants.js | 1 - bin/accessibility-automation/helper.js | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/bin/accessibility-automation/constants.js b/bin/accessibility-automation/constants.js index 7f9a3fcc..5a1014f3 100644 --- a/bin/accessibility-automation/constants.js +++ b/bin/accessibility-automation/constants.js @@ -6,7 +6,6 @@ exports.ACCESSIBILITY_ENV_VARS = [ "ACCESSIBILITY_SCANNERVERSION", "ACCESSIBILITY_COMMANDS_TO_WRAP", "ACCESSIBILITY_BUILD_END_ONLY", - "ACCESSIBILITY_SCRIPTS_TO_RUN", "ACCESSIBILITY_EXTENSION_PATH", "ACCESSIBILITY_INCLUDETAGSINTESTINGSCOPE", "ACCESSIBILITY_EXCLUDETAGSINTESTINGSCOPE", diff --git a/bin/accessibility-automation/helper.js b/bin/accessibility-automation/helper.js index 2774f3ba..c613e4cb 100644 --- a/bin/accessibility-automation/helper.js +++ b/bin/accessibility-automation/helper.js @@ -305,9 +305,8 @@ exports.processServerAccessibilityConfig = (responseData) => { process.env.ACCESSIBILITY_BUILD_END_ONLY = 'false'; } - // Also store scriptsToRun if available + // Log scriptsToRun if available (Scripts class handles the actual storage) if (commandsToWrapData.scriptsToRun) { - process.env.ACCESSIBILITY_SCRIPTS_TO_RUN = JSON.stringify(commandsToWrapData.scriptsToRun); logger.debug(`[A11Y] Server provided scripts to run: ${commandsToWrapData.scriptsToRun.join(', ')}`, { scriptsToRun: commandsToWrapData.scriptsToRun }); } } else {