Skip to content

Commit 9696c88

Browse files
authored
Merge pull request #76 from tech-sushant/cont-regression
Adding more SDK Support
2 parents 221c6ec + 22c242d commit 9696c88

File tree

8 files changed

+832
-65
lines changed

8 files changed

+832
-65
lines changed

src/tools/bstack-sdk.ts

Lines changed: 84 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,20 @@ import {
55
SDKSupportedBrowserAutomationFramework,
66
SDKSupportedLanguage,
77
SDKSupportedTestingFramework,
8+
SDKSupportedLanguageEnum,
9+
SDKSupportedBrowserAutomationFrameworkEnum,
10+
SDKSupportedTestingFrameworkEnum,
811
} from "./sdk-utils/types.js";
912
import {
1013
generateBrowserStackYMLInstructions,
1114
getInstructionsForProjectConfiguration,
1215
} from "./sdk-utils/instructions.js";
1316
import { trackMCP } from "../lib/instrumentation.js";
17+
import {
18+
formatPercyInstructions,
19+
getPercyInstructions,
20+
} from "./sdk-utils/percy/instructions.js";
21+
import { getSDKPrefixCommand } from "./sdk-utils/commands.js";
1422

1523
/**
1624
* BrowserStack SDK hooks into your test framework to seamlessly run tests on BrowserStack.
@@ -21,25 +29,85 @@ export async function bootstrapProjectWithSDK({
2129
detectedTestingFramework,
2230
detectedLanguage,
2331
desiredPlatforms,
32+
enablePercy,
2433
}: {
2534
detectedBrowserAutomationFramework: SDKSupportedBrowserAutomationFramework;
2635
detectedTestingFramework: SDKSupportedTestingFramework;
2736
detectedLanguage: SDKSupportedLanguage;
2837
desiredPlatforms: string[];
38+
enablePercy: boolean;
2939
}): Promise<CallToolResult> {
30-
const instructions = generateBrowserStackYMLInstructions(desiredPlatforms);
40+
// Handle frameworks with unique setup instructions that don't use browserstack.yml
41+
if (
42+
detectedBrowserAutomationFramework === "cypress" ||
43+
detectedTestingFramework === "webdriverio"
44+
) {
45+
let instructions = getInstructionsForProjectConfiguration(
46+
detectedBrowserAutomationFramework,
47+
detectedTestingFramework,
48+
detectedLanguage,
49+
);
50+
if (enablePercy) {
51+
const percyInstructions = getPercyInstructions(
52+
detectedLanguage,
53+
detectedBrowserAutomationFramework,
54+
detectedTestingFramework,
55+
);
56+
if (percyInstructions) {
57+
instructions += formatPercyInstructions(percyInstructions);
58+
} else {
59+
throw new Error(
60+
`Percy is currently not supported through MCP for ${detectedLanguage} with ${detectedTestingFramework}. If you want to run the test cases without Percy, disable Percy and run it again.`,
61+
);
62+
}
63+
}
64+
return {
65+
content: [{ type: "text", text: instructions, isError: false }],
66+
};
67+
}
68+
69+
let fullInstructions = "";
70+
// Add language-dependent prefix command
71+
fullInstructions += getSDKPrefixCommand(
72+
detectedLanguage,
73+
detectedTestingFramework,
74+
);
75+
76+
const ymlInstructions = generateBrowserStackYMLInstructions(
77+
desiredPlatforms,
78+
enablePercy,
79+
);
80+
fullInstructions += `${ymlInstructions}`;
81+
3182
const instructionsForProjectConfiguration =
3283
getInstructionsForProjectConfiguration(
3384
detectedBrowserAutomationFramework,
3485
detectedTestingFramework,
3586
detectedLanguage,
3687
);
3788

89+
if (enablePercy) {
90+
const percyInstructions = getPercyInstructions(
91+
detectedLanguage,
92+
detectedBrowserAutomationFramework,
93+
detectedTestingFramework,
94+
);
95+
if (percyInstructions) {
96+
fullInstructions += formatPercyInstructions(percyInstructions);
97+
} else {
98+
throw new Error(
99+
`Percy is currently not supported through MCP for ${detectedLanguage} with ${detectedTestingFramework}. If you want to run the test cases without Percy, disable Percy and run it again.`,
100+
);
101+
}
102+
}
103+
104+
fullInstructions += `\n\nAfter setting up the files above, follow these final steps:\n${instructionsForProjectConfiguration}`;
105+
38106
return {
39107
content: [
40108
{
41109
type: "text",
42-
text: `${instructions}\n\n After creating the browserstack.yml file above, do the following: ${instructionsForProjectConfiguration}`,
110+
text: fullInstructions,
43111
isError: false,
44112
},
45113
],
@@ -49,28 +117,35 @@ export async function bootstrapProjectWithSDK({
49117
export default function addSDKTools(server: McpServer) {
50118
server.tool(
51119
"runTestsOnBrowserStack",
52-
"Use this tool to get instructions for running tests on BrowserStack.",
120+
"Use this tool to get instructions for running tests on BrowserStack and browserstack percy",
53121
{
54122
detectedBrowserAutomationFramework: z
55-
.string()
123+
.nativeEnum(SDKSupportedBrowserAutomationFrameworkEnum)
56124
.describe(
57125
"The automation framework configured in the project. Example: 'playwright', 'selenium'",
58126
),
59127
detectedTestingFramework: z
60-
.string()
128+
.nativeEnum(SDKSupportedTestingFrameworkEnum)
61129
.describe(
62-
"The testing framework used in the project. Example: 'jest', 'pytest'",
130+
"The testing framework used in the project. Be precise with framework selection Example: 'webdriverio', 'jest', 'pytest', 'junit4', 'junit5', 'mocha'",
63131
),
64132
detectedLanguage: z
65-
.string()
133+
.nativeEnum(SDKSupportedLanguageEnum)
66134
.describe(
67-
"The programming language used in the project. Example: 'nodejs', 'python'",
135+
"The programming language used in the project. Example: 'nodejs', 'python', 'java', 'csharp'",
68136
),
69137
desiredPlatforms: z
70138
.array(z.enum(["windows", "macos", "android", "ios"]))
71139
.describe(
72140
"The platforms the user wants to test on. Always ask this to the user, do not try to infer this.",
73141
),
142+
enablePercy: z
143+
.boolean()
144+
.optional()
145+
.default(false)
146+
.describe(
147+
"Set to true if the user wants to enable Percy for visual testing. Defaults to false.",
148+
),
74149
},
75150
async (args) => {
76151
try {
@@ -83,6 +158,7 @@ export default function addSDKTools(server: McpServer) {
83158
args.detectedTestingFramework as SDKSupportedTestingFramework,
84159
detectedLanguage: args.detectedLanguage as SDKSupportedLanguage,
85160
desiredPlatforms: args.desiredPlatforms,
161+
enablePercy: args.enablePercy,
86162
});
87163
} catch (error) {
88164
trackMCP(

src/tools/sdk-utils/commands.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Utility to get the language-dependent prefix command for BrowserStack SDK setup
2+
import { SDKSupportedLanguage } from "./types.js";
3+
4+
// Framework mapping for Java Maven archetype generation
5+
const JAVA_FRAMEWORK_MAP: Record<string, string> = {
6+
testng: "testng",
7+
junit5: "junit5",
8+
junit4: "junit4",
9+
cucumber: "cucumber-testng",
10+
};
11+
12+
// Common Gradle setup instructions (platform-independent)
13+
const GRADLE_SETUP_INSTRUCTIONS = `
14+
**For Gradle setup:**
15+
1. Add browserstack-java-sdk to dependencies:
16+
compileOnly 'com.browserstack:browserstack-java-sdk:latest.release'
17+
18+
2. Add browserstackSDK path variable:
19+
def browserstackSDKArtifact = configurations.compileClasspath.resolvedConfiguration.resolvedArtifacts.find { it.name == 'browserstack-java-sdk' }
20+
21+
3. Add javaagent to gradle tasks:
22+
jvmArgs "-javaagent:\${browserstackSDKArtifact.file}"
23+
`;
24+
25+
export function getSDKPrefixCommand(
26+
language: SDKSupportedLanguage,
27+
framework: string,
28+
): string {
29+
switch (language) {
30+
case "nodejs":
31+
return `Install BrowserStack Node SDK\nusing command | npm i -D browserstack-node-sdk@latest\n| and then run following command to setup browserstack sdk:\n npx setup --username ${process.env.BROWSERSTACK_USERNAME} --key ${process.env.BROWSERSTACK_ACCESS_KEY}\n\n. This will create browserstack.yml file in the project root. Edit the file to add your desired platforms and browsers. If the file is not created :\n`;
32+
33+
case "java": {
34+
const mavenFramework = getJavaFrameworkForMaven(framework);
35+
const isWindows = process.platform === "win32";
36+
37+
const mavenCommand = isWindows
38+
? `mvn archetype:generate -B -DarchetypeGroupId="com.browserstack" -DarchetypeArtifactId="browserstack-sdk-archetype-integrate" -DarchetypeVersion="1.0" -DgroupId="com.browserstack" -DartifactId="browserstack-sdk-archetype-integrate" -Dversion="1.0" -DBROWSERSTACK_USERNAME="${process.env.BROWSERSTACK_USERNAME}" -DBROWSERSTACK_ACCESS_KEY="${process.env.BROWSERSTACK_ACCESS_KEY}" -DBROWSERSTACK_FRAMEWORK="${mavenFramework}"`
39+
: `mvn archetype:generate -B -DarchetypeGroupId=com.browserstack \\
40+
-DarchetypeArtifactId=browserstack-sdk-archetype-integrate -DarchetypeVersion=1.0 \\
41+
-DgroupId=com.browserstack -DartifactId=browserstack-sdk-archetype-integrate -Dversion=1.0 \\
42+
-DBROWSERSTACK_USERNAME="${process.env.BROWSERSTACK_USERNAME}" \\
43+
-DBROWSERSTACK_ACCESS_KEY="${process.env.BROWSERSTACK_ACCESS_KEY}" \\
44+
-DBROWSERSTACK_FRAMEWORK="${mavenFramework}"`;
45+
46+
const platformLabel = isWindows ? "Windows" : "macOS/Linux";
47+
48+
return `Install BrowserStack Java SDK
49+
50+
**Maven command for ${framework} (${platformLabel}):**
51+
Run the command, it is required to generate the browserstack-sdk-archetype-integrate project:
52+
${mavenCommand}
53+
${GRADLE_SETUP_INSTRUCTIONS}`;
54+
}
55+
56+
// Add more languages as needed
57+
default:
58+
return "";
59+
}
60+
}
61+
62+
export function getJavaFrameworkForMaven(framework: string): string {
63+
return JAVA_FRAMEWORK_MAP[framework] || framework;
64+
}

0 commit comments

Comments
 (0)