Skip to content

Commit e096ad3

Browse files
committed
Additional improvements
1 parent 326c64a commit e096ad3

File tree

5 files changed

+85
-64
lines changed

5 files changed

+85
-64
lines changed

src/tools/appautomate-utils/appium-sdk/handler.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@ import { z } from "zod";
22
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
33
import { BrowserStackConfig } from "../../../lib/types.js";
44
import { getBrowserStackAuth } from "../../../lib/get-auth.js";
5+
import { getAppUploadInstruction, validateSupportforAppAutomate, SupportedFramework } from "./utils.js";
6+
import logger from "../../../logger.js";
7+
8+
import {
9+
getAppSDKPrefixCommand,
10+
generateAppBrowserStackYMLInstructions,
11+
} from "./index.js";
12+
513
import {
614
AppSDKSupportedLanguage,
715
AppSDKSupportedTestingFramework,
@@ -10,17 +18,12 @@ import {
1018
getAppInstructionsForProjectConfiguration,
1119
SETUP_APP_AUTOMATE_SCHEMA,
1220
} from "./index.js";
13-
import {
14-
getAppSDKPrefixCommand,
15-
generateAppBrowserStackYMLInstructions,
16-
} from "./index.js";
17-
import { getAppUploadInstruction } from "./utils.js";
18-
import logger from "../../../logger.js";
1921

2022
export async function setupAppAutomateHandler(
2123
rawInput: unknown,
2224
config: BrowserStackConfig,
2325
): Promise<CallToolResult> {
26+
2427
const input = z.object(SETUP_APP_AUTOMATE_SCHEMA).parse(rawInput);
2528
const auth = getBrowserStackAuth(config);
2629
const [username, accessKey] = auth.split(":");
@@ -33,10 +36,10 @@ export async function setupAppAutomateHandler(
3336
const language = input.detectedLanguage as AppSDKSupportedLanguage;
3437
const platforms = (input.desiredPlatforms as string[]) ?? ["android"];
3538
const appPath = input.appPath as string;
36-
const framework = input.detectedFramework as string;
39+
const framework = input.detectedFramework as SupportedFramework;
3740

38-
logger.info("Generating SDK setup command...");
39-
logger.debug(`Input: ${JSON.stringify(input)}`);
41+
//Validating if supported framework or not
42+
validateSupportforAppAutomate(framework, language, testingFramework);
4043

4144
// Step 1: Generate SDK setup command
4245
const sdkCommand = getAppSDKPrefixCommand(

src/tools/appautomate-utils/appium-sdk/languages/ruby.ts

Lines changed: 25 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ browser_caps:
2626
-
2727
"deviceName": "Google Pixel 3"
2828
"os_version": "9.0"
29-
"app": "bs://<app-id>"
29+
"app": "<replace with the APK path from the upload step>"
3030
"name": "first_test"
31-
\`\`\``,
31+
\`\`\``
3232
);
3333

3434
const envStep = createStep(
@@ -46,7 +46,7 @@ password = "${accessKey}"
4646
desired_caps = {
4747
caps: caps,
4848
appium_lib: {
49-
server_url = "https://#{username}:#{password}@#{caps['server']}/wd/hub"
49+
server_url: "https://#{username}:#{password}@#{caps['server']}/wd/hub"
5050
}
5151
}
5252
@@ -63,14 +63,14 @@ end
6363
at_exit do
6464
$driver.quit if $driver
6565
end
66-
\`\`\``,
66+
\`\`\``
6767
);
6868

6969
const runStep = createStep(
7070
"Run the test:",
7171
`\`\`\`bash
7272
bundle exec cucumber
73-
\`\`\``,
73+
\`\`\``
7474
);
7575

7676
return combineInstructions(configStep, envStep, runStep);
@@ -79,22 +79,21 @@ bundle exec cucumber
7979
export function getRubySDKCommand(
8080
framework: string,
8181
username: string,
82-
accessKey: string,
82+
accessKey: string
8383
): string {
8484
const { isWindows, getPlatformLabel } = PLATFORM_UTILS;
8585

86-
if (framework === "cucumberRuby") {
87-
const envStep = createEnvStep(
88-
username,
89-
accessKey,
90-
isWindows,
91-
getPlatformLabel(),
92-
"Set your BrowserStack credentials as environment variables:",
93-
);
94-
95-
const installStep = createStep(
96-
"Install required Ruby gems:",
97-
`\`\`\`bash
86+
const envStep = createEnvStep(
87+
username,
88+
accessKey,
89+
isWindows,
90+
getPlatformLabel(),
91+
"Set your BrowserStack credentials as environment variables:"
92+
);
93+
94+
const installStep = createStep(
95+
"Install required Ruby gems:",
96+
`\`\`\`bash
9897
# Install Bundler if not already installed
9998
gem install bundler
10099
@@ -103,12 +102,12 @@ gem install appium_lib
103102
104103
# Install Cucumber
105104
gem install cucumber
106-
\`\`\``,
107-
);
105+
\`\`\``
106+
);
108107

109-
const gemfileStep = createStep(
110-
"Create a Gemfile for dependency management:",
111-
`\`\`\`ruby
108+
const gemfileStep = createStep(
109+
"Create a Gemfile for dependency management:",
110+
`\`\`\`ruby
112111
# Gemfile
113112
source 'https://rubygems.org'
114113
@@ -119,11 +118,8 @@ gem 'cucumber'
119118
Then run:
120119
\`\`\`bash
121120
bundle install
122-
\`\`\``,
123-
);
124-
125-
return combineInstructions(envStep, installStep, gemfileStep);
126-
}
121+
\`\`\``
122+
);
127123

128-
return "";
124+
return combineInstructions(envStep, installStep, gemfileStep);
129125
}

src/tools/appautomate-utils/appium-sdk/types.ts

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,7 @@ export enum AppSDKSupportedLanguageEnum {
99
export type AppSDKSupportedLanguage = keyof typeof AppSDKSupportedLanguageEnum;
1010

1111
export enum AppSDKSupportedFrameworkEnum {
12-
appium = "appium",
13-
webdriverio = "webdriverio",
14-
nightwatch = "nightwatch",
15-
jest = "jest",
16-
mocha = "mocha",
17-
cucumberJs = "cucumberJs",
18-
pytest = "pytest",
19-
rspec = "rspec",
20-
cucumberRuby = "cucumberRuby",
12+
appium = "appium"
2113
}
2214

2315
export type AppSDKSupportedFramework =
@@ -26,6 +18,7 @@ export type AppSDKSupportedFramework =
2618
export enum AppSDKSupportedTestingFrameworkEnum {
2719
testng = "testng",
2820
junit5 = "junit5",
21+
junit4 = "junit4",
2922
selenide = "selenide",
3023
jbehave = "jbehave",
3124
cucumberTestng = "cucumberTestng",
@@ -58,23 +51,18 @@ export enum AppSDKSupportedPlatformEnum {
5851
}
5952
export type AppSDKSupportedPlatform = keyof typeof AppSDKSupportedPlatformEnum;
6053

61-
export type AppConfigMapping = Record<
62-
AppSDKSupportedLanguageEnum,
63-
Partial<
64-
Record<
65-
AppSDKSupportedFrameworkEnum,
66-
Partial<
67-
Record<
68-
AppSDKSupportedTestingFrameworkEnum,
69-
{ instructions: (username: string, accessKey: string) => string }
70-
>
71-
>
72-
>
73-
>
74-
>;
75-
7654
// App SDK instruction type
7755
export interface AppSDKInstruction {
7856
content: string;
7957
type: "config" | "run" | "setup";
8058
}
59+
60+
export const SUPPORTED_CONFIGURATIONS = {
61+
appium: {
62+
ruby: ["cucumberRuby"],
63+
java: ["junit5", "junit4", "testng", "cucumberTestng", "selenide", "jbehave"],
64+
csharp: ["nunit", "xunit", "mstest", "specflow", "reqnroll"],
65+
python: ["pytest", "robot", "behave", "lettuce"],
66+
nodejs: ["jest", "mocha", "cucumberJs", "webdriverio", "nightwatch"],
67+
},
68+
};

src/tools/appautomate-utils/appium-sdk/utils.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
AppSDKSupportedTestingFrameworkEnum,
44
createStep,
55
} from "./index.js";
6+
import {SUPPORTED_CONFIGURATIONS} from "./types.js"
67

78
export function isBrowserStackAppUrl(appPath: string): boolean {
89
return appPath.startsWith("bs://");
@@ -50,7 +51,8 @@ export async function getAppUploadInstruction(
5051
if (
5152
detectedTestingFramework ===
5253
AppSDKSupportedTestingFrameworkEnum.nightwatch ||
53-
detectedTestingFramework === AppSDKSupportedTestingFrameworkEnum.webdriverio
54+
detectedTestingFramework === AppSDKSupportedTestingFrameworkEnum.webdriverio ||
55+
detectedTestingFramework === AppSDKSupportedTestingFrameworkEnum.cucumberRuby
5456
) {
5557
const app_url = "bs://ff4e358328a3e914fe4f0e46ec7af73f9c08cd55";
5658
if (app_url) {
@@ -62,3 +64,34 @@ export async function getAppUploadInstruction(
6264
}
6365
return "";
6466
}
67+
68+
export type SupportedFramework = keyof typeof SUPPORTED_CONFIGURATIONS;
69+
type SupportedLanguage = keyof typeof SUPPORTED_CONFIGURATIONS[SupportedFramework];
70+
type SupportedTestingFramework = string;
71+
72+
export function validateSupportforAppAutomate(
73+
framework: SupportedFramework,
74+
language: SupportedLanguage,
75+
testingFramework: SupportedTestingFramework
76+
) {
77+
const frameworks = Object.keys(SUPPORTED_CONFIGURATIONS) as SupportedFramework[];
78+
if (!SUPPORTED_CONFIGURATIONS[framework]) {
79+
throw new Error(
80+
`Unsupported framework '${framework}'. Supported frameworks: ${frameworks.join(", ")}`
81+
);
82+
}
83+
84+
const languages = Object.keys(SUPPORTED_CONFIGURATIONS[framework]) as SupportedLanguage[];
85+
if (!SUPPORTED_CONFIGURATIONS[framework][language]) {
86+
throw new Error(
87+
`Unsupported language '${language}' for framework '${framework}'. Supported languages: ${languages.join(", ")}`
88+
);
89+
}
90+
91+
const testingFrameworks = SUPPORTED_CONFIGURATIONS[framework][language];
92+
if (!testingFrameworks.includes(testingFramework)) {
93+
throw new Error(
94+
`Unsupported testing framework '${testingFramework}' for language '${language}' and framework '${framework}'. Supported testing frameworks: ${testingFrameworks.join(", ")}`
95+
);
96+
}
97+
}

src/tools/appautomate.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,11 +393,12 @@ export default function addAppAutomationTools(
393393
try {
394394
return await setupAppAutomateHandler(args, config);
395395
} catch (error) {
396+
const error_message = error instanceof Error ? error.message : "Unknown error";
396397
return {
397398
content: [
398399
{
399400
type: "text",
400-
text: `Failed to bootstrap project with BrowserStack App Automate SDK. Error: ${error}. Please open an issue on GitHub if the problem persists`,
401+
text: `Failed to bootstrap project with BrowserStack App Automate SDK. Error: ${error_message}. Please open an issue on GitHub if the problem persists`,
401402
isError: true,
402403
},
403404
],

0 commit comments

Comments
 (0)