From 995ed2fdfc7bb3de06cb39c066311e44923e4048 Mon Sep 17 00:00:00 2001 From: tech-sushant Date: Wed, 13 Aug 2025 01:33:33 +0530 Subject: [PATCH] Add Support to NodeJS Frameworks --- src/tools/app-sdk-utils/commands.ts | 186 +++++++++++++++++------- src/tools/app-sdk-utils/constants.ts | 78 ++++++++++ src/tools/app-sdk-utils/instructions.ts | 44 +++++- src/tools/app-sdk-utils/types.ts | 5 + src/tools/app-sdk-utils/utils.ts | 27 ++++ 5 files changed, 278 insertions(+), 62 deletions(-) create mode 100644 src/tools/app-sdk-utils/constants.ts create mode 100644 src/tools/app-sdk-utils/utils.ts diff --git a/src/tools/app-sdk-utils/commands.ts b/src/tools/app-sdk-utils/commands.ts index 96f0af2..69f6a8b 100644 --- a/src/tools/app-sdk-utils/commands.ts +++ b/src/tools/app-sdk-utils/commands.ts @@ -1,84 +1,162 @@ // Utility to get the language-dependent prefix command for BrowserStack App Automate SDK setup import { AppSDKSupportedLanguage } from "./types.js"; +import { + GRADLE_APP_SETUP_INSTRUCTIONS, + getMavenAppAutomateCommand, +} from "./constants.js"; +import { getSetBrowserStackCredentialsStep } from "./utils.js"; +import { + AppSDKSupportedLanguageEnum, + AppSDKSupportedFrameworkEnum, +} from "./types.js"; // Framework mapping for Java Maven archetype generation for App Automate const JAVA_APP_FRAMEWORK_MAP: Record = { - testng: "browserstack-sdk-archetype-integrate", + "testng": "browserstack-sdk-archetype-integrate", "cucumber-testng": "browserstack-sdk-archetype-integrate", "cucumber-junit4": "browserstack-sdk-archetype-integrate", "cucumber-junit5": "browserstack-sdk-archetype-integrate", }; -// Common Gradle setup instructions for App Automate (platform-independent) -const GRADLE_APP_SETUP_INSTRUCTIONS = ` -**For Gradle setup:** -1. Add browserstack-java-sdk to dependencies: - compileOnly 'com.browserstack:browserstack-java-sdk:latest.release' - -2. Add browserstackSDK path variable: - def browserstackSDKArtifact = configurations.compileClasspath.resolvedConfiguration.resolvedArtifacts.find { it.name == 'browserstack-java-sdk' } - -3. Add javaagent to gradle tasks: - jvmArgs "-javaagent:\${browserstackSDKArtifact.file}" -`; +export function getJavaAppFrameworkForMaven(framework: string): string { + return JAVA_APP_FRAMEWORK_MAP[framework] || framework; +} export function getAppSDKPrefixCommand( language: AppSDKSupportedLanguage, framework: string, username: string, - accessKey: string, + accessKey: string ): string { switch (language) { - case "java": { + case AppSDKSupportedLanguageEnum.java: { const mavenFramework = getJavaAppFrameworkForMaven(framework); - const isWindows = process.platform === "win32"; + const mavenCommand = getMavenAppAutomateCommand( + mavenFramework, + framework, + username, + accessKey + ); - const frameworkParam = `-DBROWSERSTACK_FRAMEWORK="${framework}"`; + return ( + getSetBrowserStackCredentialsStep(username, accessKey) + + `---STEP--- + Install BrowserStack SDK using Maven Archetype for App Automate - const mavenCommand = isWindows - ? `mvn archetype:generate -B -DarchetypeGroupId="com.browserstack" -DarchetypeArtifactId="${mavenFramework}" -DarchetypeVersion="1.0" -DgroupId="com.browserstack" -DartifactId="${mavenFramework}" -Dversion="1.0" -DBROWSERSTACK_USERNAME="${username}" -DBROWSERSTACK_ACCESS_KEY="${accessKey}" ${frameworkParam}` - : `mvn archetype:generate -B -DarchetypeGroupId=com.browserstack \\ --DarchetypeArtifactId=${mavenFramework} -DarchetypeVersion=1.0 \\ --DgroupId=com.browserstack -DartifactId=${mavenFramework} -Dversion=1.0 \\ --DBROWSERSTACK_USERNAME="${username}" \\ --DBROWSERSTACK_ACCESS_KEY="${accessKey}" \\ -${frameworkParam}`; + Maven command for ${framework} (${ + process.platform === "win32" ? "Windows" : "macOS/Linux" + }): + \`\`\`bash + ${mavenCommand} + \`\`\` - const platformLabel = isWindows ? "Windows" : "macOS/Linux"; + Alternative setup for Gradle users: + ${GRADLE_APP_SETUP_INSTRUCTIONS}` + ); + } - return `---STEP--- -Set BrowserStack credentials as environment variables: + case AppSDKSupportedLanguageEnum.nodejs: { + if (framework === AppSDKSupportedFrameworkEnum.webdriverio) { + return ( + getSetBrowserStackCredentialsStep(username, accessKey) + + `---STEP--- + Install BrowserStack WDIO service: -**${platformLabel}:** -${ - isWindows - ? `\`\`\`cmd -set BROWSERSTACK_USERNAME=${username} -set BROWSERSTACK_ACCESS_KEY=${accessKey} -\`\`\`` - : `\`\`\`bash -export BROWSERSTACK_USERNAME="${username}" -export BROWSERSTACK_ACCESS_KEY="${accessKey}" -\`\`\`` -} + \`\`\`bash + npm install @wdio/browserstack-service --save-dev + \`\`\` ----STEP--- -Install BrowserStack SDK using Maven Archetype for App Automate + ---STEP--- + Update your WebdriverIO config file (e.g., \`wdio.conf.js\`) to add the BrowserStack service and capabilities: -**Maven command for ${framework} (${platformLabel}):** -\`\`\`bash -${mavenCommand} -\`\`\` + \`\`\`js + exports.config = { + user: process.env.BROWSERSTACK_USERNAME || '${username}', + key: process.env.BROWSERSTACK_ACCESS_KEY || '${accessKey}', + hostname: 'hub.browserstack.com', + services: [ + [ + 'browserstack', + { + app: 'bs://sample.app', + browserstackLocal: true, + accessibility: false, + testObservabilityOptions: { + buildName: "bstack-demo", + projectName: "BrowserStack Sample", + buildTag: 'Any build tag goes here. For e.g. ["Tag1","Tag2"]' + }, + }, + ] + ], + capabilities: [{ + 'bstack:options': { + deviceName: 'Samsung Galaxy S22 Ultra', + platformVersion: '12.0', + platformName: 'android', + } + }], + commonCapabilities: { + 'bstack:options': { + debug: true, + networkLogs: true, + percy: false, + percyCaptureMode: 'auto' + } + }, + maxInstances: 10, + // ...other config + };` + ); + } + if (framework === AppSDKSupportedFrameworkEnum.nightwatch) { + return ( + getSetBrowserStackCredentialsStep(username, accessKey) + + `---STEP--- + Install Nightwatch and BrowserStack integration: -Alternative setup for Gradle users: -${GRADLE_APP_SETUP_INSTRUCTIONS}`; - } + \`\`\`bash + npm install nightwatch nightwatch-browserstack --save-dev + \`\`\` + + ---STEP--- + Update your Nightwatch config file (e.g., \`nightwatch.conf.js\`) to add the BrowserStack settings and capabilities: - default: - return ""; + \`\`\`js + module.exports = { + src_folders: ["tests"], + test_settings: { + default: { + selenium: { + start_process: false, + host: "hub.browserstack.com", + port: 443, + }, + desiredCapabilities: { + "bstack:options": { + userName: process.env.BROWSERSTACK_USERNAME || "${username}", + accessKey: process.env.BROWSERSTACK_ACCESS_KEY || "${accessKey}", + deviceName: "Samsung Galaxy S22 Ultra", + osVersion: "12.0", + projectName: "BrowserStack Sample", + buildName: "bstack-demo", + sessionName: "Nightwatch App Automate Test", + debug: true, + networkLogs: true, + }, + app: "bs://sample.app", + platformName: "android", + }, + }, + }, + }; + \`\`\` + ` + ); + } + break; + } } -} -export function getJavaAppFrameworkForMaven(framework: string): string { - return JAVA_APP_FRAMEWORK_MAP[framework] || framework; + return ""; } diff --git a/src/tools/app-sdk-utils/constants.ts b/src/tools/app-sdk-utils/constants.ts new file mode 100644 index 0000000..53996d5 --- /dev/null +++ b/src/tools/app-sdk-utils/constants.ts @@ -0,0 +1,78 @@ +// Common Gradle setup instructions for App Automate (platform-independent) +export const GRADLE_APP_SETUP_INSTRUCTIONS = ` +**For Gradle setup:** +1. Add browserstack-java-sdk to dependencies: + compileOnly 'com.browserstack:browserstack-java-sdk:latest.release' + +2. Add browserstackSDK path variable: + def browserstackSDKArtifact = configurations.compileClasspath.resolvedConfiguration.resolvedArtifacts.find { it.name == 'browserstack-java-sdk' } + +3. Add javaagent to gradle tasks: + jvmArgs "-javaagent:\${browserstackSDKArtifact.file}" +`; + +/** + * Maven archetype constants for App Automate + */ +export const MAVEN_ARCHETYPE_GROUP_ID = "com.browserstack"; +export const MAVEN_ARCHETYPE_VERSION = "1.0"; + +/** + * Returns the Maven command for Windows for App Automate SDK setup + */ +export function getMavenCommandForWindows( + mavenFramework: string, + framework: string, + username: string, + accessKey: string +): string { + return ( + `mvn archetype:generate -B ` + + `-DarchetypeGroupId="${MAVEN_ARCHETYPE_GROUP_ID}" ` + + `-DarchetypeArtifactId="${mavenFramework}" ` + + `-DarchetypeVersion="${MAVEN_ARCHETYPE_VERSION}" ` + + `-DgroupId="${MAVEN_ARCHETYPE_GROUP_ID}" ` + + `-DartifactId="${mavenFramework}" ` + + `-Dversion="${MAVEN_ARCHETYPE_VERSION}" ` + + `-DBROWSERSTACK_USERNAME="${username}" ` + + `-DBROWSERSTACK_ACCESS_KEY="${accessKey}" ` + + `-DBROWSERSTACK_FRAMEWORK="${framework}"` + ); +} + +/** + * Returns the Maven command for macOS/Linux for App Automate SDK setup + */ +export function getMavenCommandForUnix( + mavenFramework: string, + framework: string, + username: string, + accessKey: string +): string { + return ( + `mvn archetype:generate -B \\\n` + + `-DarchetypeGroupId=${MAVEN_ARCHETYPE_GROUP_ID} \\\n` + + `-DarchetypeArtifactId=${mavenFramework} -DarchetypeVersion=${MAVEN_ARCHETYPE_VERSION} \\\n` + + `-DgroupId=${MAVEN_ARCHETYPE_GROUP_ID} -DartifactId=${mavenFramework} -Dversion=${MAVEN_ARCHETYPE_VERSION} \\\n` + + `-DBROWSERSTACK_USERNAME="${username}" \\\n` + + `-DBROWSERSTACK_ACCESS_KEY="${accessKey}" \\\n` + + `-DBROWSERSTACK_FRAMEWORK="${framework}"` + ); +} + +/** + * Utility to generate the Maven command for App Automate SDK setup (platform-aware) + */ +export function getMavenAppAutomateCommand( + mavenFramework: string, + framework: string, + username: string, + accessKey: string +): string { + const isWindows = process.platform === "win32"; + if (isWindows) { + return getMavenCommandForWindows(mavenFramework, framework, username, accessKey); + } else { + return getMavenCommandForUnix(mavenFramework, framework, username, accessKey); + } +} diff --git a/src/tools/app-sdk-utils/instructions.ts b/src/tools/app-sdk-utils/instructions.ts index 52b813a..d1e43a9 100644 --- a/src/tools/app-sdk-utils/instructions.ts +++ b/src/tools/app-sdk-utils/instructions.ts @@ -3,6 +3,7 @@ import { AppSDKSupportedFramework, AppSDKSupportedTestingFramework, } from "./types.js"; +import { AppSDKSupportedLanguageEnum, AppSDKSupportedTestingFrameworkEnum } from "./types.js"; // App Automate specific device configurations const APP_DEVICE_CONFIGS = { @@ -33,8 +34,8 @@ export function generateAppBrowserStackYMLInstructions( return devices .map( (device) => ` - platformName: ${platform} - deviceName: ${device.deviceName} - platformVersion: "${device.platformVersion}"`, + deviceName: ${device.deviceName} + platformVersion: "${device.platformVersion}"`, ) .join("\n"); }) @@ -80,8 +81,10 @@ export function getAppInstructionsForProjectConfiguration( return ""; } switch (language) { - case "java": + case AppSDKSupportedLanguageEnum.java: return getJavaAppInstructions(testingFramework); + case AppSDKSupportedLanguageEnum.nodejs: + return getNodejsAppInstructions(testingFramework); default: return ""; } @@ -90,15 +93,40 @@ export function getAppInstructionsForProjectConfiguration( function getJavaAppInstructions( testingFramework: AppSDKSupportedTestingFramework, ): string { - if (testingFramework === "testng") { + if (testingFramework === AppSDKSupportedTestingFrameworkEnum.testng) { return `---STEP--- -Run your App Automate test suite: + Run your App Automate test suite: -\`\`\`bash -mvn test -\`\`\``; + \`\`\`bash + mvn test + \`\`\``; } + return ""; +} +function getNodejsAppInstructions( + testingFramework: AppSDKSupportedTestingFramework, +): string { + if (testingFramework === AppSDKSupportedTestingFrameworkEnum.webdriverio) { + return `---STEP--- + Run your App Automate test suite: + + \`\`\`bash + npx wdio run ./wdio.conf.js + \`\`\``; + } + else if (testingFramework === AppSDKSupportedTestingFrameworkEnum.nightwatch) { + return `---STEP--- + Run your App Automate test suite: + For Android: + \`\`\`bash + npx nightwatch --env browserstack.android + \`\`\` + For iOS: + \`\`\`bash + npx nightwatch --env browserstack.ios + \`\`\``; + } return ""; } diff --git a/src/tools/app-sdk-utils/types.ts b/src/tools/app-sdk-utils/types.ts index 24bd540..2298d75 100644 --- a/src/tools/app-sdk-utils/types.ts +++ b/src/tools/app-sdk-utils/types.ts @@ -1,10 +1,13 @@ export enum AppSDKSupportedLanguageEnum { java = "java", + nodejs = "nodejs", } export type AppSDKSupportedLanguage = keyof typeof AppSDKSupportedLanguageEnum; export enum AppSDKSupportedFrameworkEnum { appium = "appium", + webdriverio = "webdriverio", + nightwatch = "nightwatch", } export type AppSDKSupportedFramework = keyof typeof AppSDKSupportedFrameworkEnum; @@ -14,6 +17,8 @@ export enum AppSDKSupportedTestingFrameworkEnum { "cucumber-testng" = "cucumber-testng", "cucumber-junit4" = "cucumber-junit4", "cucumber-junit5" = "cucumber-junit5", + webdriverio = "webdriverio", + nightwatch = "nightwatch", } export type AppSDKSupportedTestingFramework = keyof typeof AppSDKSupportedTestingFrameworkEnum; diff --git a/src/tools/app-sdk-utils/utils.ts b/src/tools/app-sdk-utils/utils.ts new file mode 100644 index 0000000..b9caab2 --- /dev/null +++ b/src/tools/app-sdk-utils/utils.ts @@ -0,0 +1,27 @@ +export function getSetBrowserStackCredentialsStep(username: string, accessKey: string): string { + const isWindows = process.platform === "win32"; + const platformLabel = isWindows ? "Windows" : "macOS/Linux"; + + const commands = isWindows + ? [ + `set BROWSERSTACK_USERNAME=${username}`, + `set BROWSERSTACK_ACCESS_KEY=${accessKey}`, + ].join("\n") + : [ + `export BROWSERSTACK_USERNAME="${username}"`, + `export BROWSERSTACK_ACCESS_KEY="${accessKey}"`, + ].join("\n"); + + const codeBlockLang = isWindows ? "cmd" : "bash"; + + return `---STEP--- +Set BrowserStack credentials as environment variables: + +${platformLabel} +---------------- + +\`\`\`${codeBlockLang} +${commands} +\`\`\` +`; +}