diff --git a/src/lib/local.ts b/src/lib/local.ts index 1da31ae..a0faa0d 100644 --- a/src/lib/local.ts +++ b/src/lib/local.ts @@ -73,7 +73,7 @@ export async function killExistingBrowserStackLocalProcesses() { } } -export async function ensureLocalBinarySetup(): Promise { +export async function ensureLocalBinarySetup(localIdentifier?: string): Promise { logger.info( "Ensuring local binary setup as it is required for private URLs...", ); @@ -81,12 +81,22 @@ export async function ensureLocalBinarySetup(): Promise { const localBinary = new Local(); await killExistingBrowserStackLocalProcesses(); + const requestBody: { + key: string; + username: string; + localIdentifier?: string; + } = { + key: config.browserstackAccessKey, + username: config.browserstackUsername + }; + + if (localIdentifier) { + requestBody.localIdentifier = localIdentifier; + } + return await new Promise((resolve, reject) => { localBinary.start( - { - key: config.browserstackAccessKey, - username: config.browserstackUsername, - }, + requestBody, (error?: Error) => { if (error) { logger.error( diff --git a/src/tools/accessiblity-utils/scanner.ts b/src/tools/accessiblity-utils/scanner.ts index 8a02016..6da16bc 100644 --- a/src/tools/accessiblity-utils/scanner.ts +++ b/src/tools/accessiblity-utils/scanner.ts @@ -1,5 +1,11 @@ import axios from "axios"; import config from "../../config.js"; +import logger from "../../logger.js"; +import { + isLocalURL, + ensureLocalBinarySetup, + killExistingBrowserStackLocalProcesses, +} from "../../lib/local.js"; export interface AccessibilityScanResponse { success: boolean; @@ -23,10 +29,54 @@ export class AccessibilityScanner { name: string, urlList: string[], ): Promise { + + // Check if any URL is local + const hasLocal = urlList.some(isLocalURL); + const localIdentifier = crypto.randomUUID(); + const LOCAL_IP = "127.0.0.1"; + const BS_LOCAL_DOMAIN = "bs-local.com"; + + if (hasLocal) { + await ensureLocalBinarySetup(localIdentifier); + } else { + await killExistingBrowserStackLocalProcesses(); + } + + const transformedUrlList = urlList.map((url) => { + try { + const parsed = new URL(url); + if (parsed.hostname === LOCAL_IP) { + parsed.hostname = BS_LOCAL_DOMAIN; + return parsed.toString(); + } + return url; + } catch (e) { + logger.warn(`[AccessibilityScan] Invalid URL skipped: ${url}`); + return url; + } + }); + + const baseRequestBody = { + name, + urlList: transformedUrlList, + recurring: false, + }; + + let requestBody = baseRequestBody; + if (hasLocal) { + const localConfig = { + localTestingInfo: { + localIdentifier, + localEnabled: true, + } + }; + requestBody = { ...baseRequestBody, ...localConfig }; + } + try { const { data } = await axios.post( "https://api-accessibility.browserstack.com/api/website-scanner/v1/scans", - { name, urlList, recurring: false }, + requestBody, { auth: this.auth }, ); if (!data.success)