|
1 | 1 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
2 |
| -import { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; |
3 |
| -import { z } from "zod"; |
4 |
| -import { trackMCP } from "../lib/instrumentation.js"; |
5 |
| -import { getSDKPrefixCommand } from "./sdk-utils/commands.js"; |
6 |
| - |
7 |
| -import { |
8 |
| - SDKSupportedBrowserAutomationFramework, |
9 |
| - SDKSupportedLanguage, |
10 |
| - SDKSupportedTestingFramework, |
11 |
| - SDKSupportedLanguageEnum, |
12 |
| - SDKSupportedBrowserAutomationFrameworkEnum, |
13 |
| - SDKSupportedTestingFrameworkEnum, |
14 |
| -} from "./sdk-utils/types.js"; |
15 |
| - |
16 |
| -import { |
17 |
| - generateBrowserStackYMLInstructions, |
18 |
| - getInstructionsForProjectConfiguration, |
19 |
| - formatInstructionsWithNumbers, |
20 |
| -} from "./sdk-utils/instructions.js"; |
21 |
| - |
22 |
| -import { |
23 |
| - formatPercyInstructions, |
24 |
| - getPercyInstructions, |
25 |
| -} from "./sdk-utils/percy/instructions.js"; |
26 |
| -import { getBrowserStackAuth } from "../lib/get-auth.js"; |
27 | 2 | import { BrowserStackConfig } from "../lib/types.js";
|
| 3 | +import { RunTestsOnBrowserStackParamsShape } from "./sdk-utils/common/schema.js"; |
| 4 | +import { runTestsOnBrowserStackHandler } from "./sdk-utils/handler.js"; |
| 5 | +import { RUN_ON_BROWSERSTACK_DESCRIPTION } from "./sdk-utils/common/constants.js"; |
28 | 6 |
|
29 |
| -/** |
30 |
| - * BrowserStack SDK hooks into your test framework to seamlessly run tests on BrowserStack. |
31 |
| - * This tool gives instructions to setup a browserstack.yml file in the project root and installs the necessary dependencies. |
32 |
| - */ |
33 |
| -export async function bootstrapProjectWithSDK({ |
34 |
| - detectedBrowserAutomationFramework, |
35 |
| - detectedTestingFramework, |
36 |
| - detectedLanguage, |
37 |
| - desiredPlatforms, |
38 |
| - enablePercy, |
39 |
| - config, |
40 |
| -}: { |
41 |
| - detectedBrowserAutomationFramework: SDKSupportedBrowserAutomationFramework; |
42 |
| - detectedTestingFramework: SDKSupportedTestingFramework; |
43 |
| - detectedLanguage: SDKSupportedLanguage; |
44 |
| - desiredPlatforms: string[]; |
45 |
| - enablePercy: boolean; |
46 |
| - config: BrowserStackConfig; |
47 |
| -}): Promise<CallToolResult> { |
48 |
| - // Get credentials from config |
49 |
| - const authString = getBrowserStackAuth(config); |
50 |
| - const [username, accessKey] = authString.split(":"); |
51 |
| - |
52 |
| - // Handle frameworks with unique setup instructions that don't use browserstack.yml |
53 |
| - if ( |
54 |
| - detectedBrowserAutomationFramework === "cypress" || |
55 |
| - detectedTestingFramework === "webdriverio" |
56 |
| - ) { |
57 |
| - let combinedInstructions = getInstructionsForProjectConfiguration( |
58 |
| - detectedBrowserAutomationFramework, |
59 |
| - detectedTestingFramework, |
60 |
| - detectedLanguage, |
61 |
| - username, |
62 |
| - accessKey, |
63 |
| - ); |
64 |
| - |
65 |
| - if (enablePercy) { |
66 |
| - const percyInstructions = getPercyInstructions( |
67 |
| - detectedLanguage, |
68 |
| - detectedBrowserAutomationFramework, |
69 |
| - detectedTestingFramework, |
70 |
| - ); |
71 |
| - |
72 |
| - if (percyInstructions) { |
73 |
| - combinedInstructions += |
74 |
| - "\n\n" + formatPercyInstructions(percyInstructions); |
75 |
| - } else { |
76 |
| - throw new Error( |
77 |
| - `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.`, |
78 |
| - ); |
79 |
| - } |
80 |
| - } |
81 |
| - |
82 |
| - // Apply consistent formatting for all configurations |
83 |
| - return formatFinalInstructions(combinedInstructions); |
84 |
| - } |
85 |
| - |
86 |
| - // Handle default flow using browserstack.yml |
87 |
| - const sdkSetupCommand = getSDKPrefixCommand( |
88 |
| - detectedLanguage, |
89 |
| - detectedTestingFramework, |
90 |
| - username, |
91 |
| - accessKey, |
92 |
| - ); |
93 |
| - |
94 |
| - const ymlInstructions = generateBrowserStackYMLInstructions( |
95 |
| - desiredPlatforms, |
96 |
| - enablePercy, |
97 |
| - ); |
98 |
| - |
99 |
| - const instructionsForProjectConfiguration = |
100 |
| - getInstructionsForProjectConfiguration( |
101 |
| - detectedBrowserAutomationFramework, |
102 |
| - detectedTestingFramework, |
103 |
| - detectedLanguage, |
104 |
| - username, |
105 |
| - accessKey, |
106 |
| - ); |
107 |
| - |
108 |
| - let combinedInstructions = ""; |
109 |
| - |
110 |
| - // Step 1: Add SDK setup command |
111 |
| - if (sdkSetupCommand) { |
112 |
| - combinedInstructions += sdkSetupCommand; |
113 |
| - } |
114 |
| - |
115 |
| - // Step 2: Add browserstack.yml setup |
116 |
| - if (ymlInstructions) { |
117 |
| - combinedInstructions += "\n\n---STEP---\n" + ymlInstructions; |
118 |
| - } |
119 |
| - |
120 |
| - // Step 3: Add language/framework-specific setup |
121 |
| - if (instructionsForProjectConfiguration) { |
122 |
| - combinedInstructions += "\n\n" + instructionsForProjectConfiguration; |
123 |
| - } |
124 |
| - |
125 |
| - // Step 4: Add Percy setup if applicable |
126 |
| - if (enablePercy) { |
127 |
| - const percyInstructions = getPercyInstructions( |
128 |
| - detectedLanguage, |
129 |
| - detectedBrowserAutomationFramework, |
130 |
| - detectedTestingFramework, |
131 |
| - ); |
132 |
| - |
133 |
| - if (percyInstructions) { |
134 |
| - combinedInstructions += |
135 |
| - "\n\n" + formatPercyInstructions(percyInstructions); |
136 |
| - } else { |
137 |
| - throw new Error( |
138 |
| - `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.`, |
139 |
| - ); |
140 |
| - } |
141 |
| - } |
142 |
| - |
143 |
| - // Apply consistent formatting for all configurations |
144 |
| - return formatFinalInstructions(combinedInstructions); |
145 |
| -} |
146 |
| - |
147 |
| -// Helper function to apply consistent formatting to all instruction types |
148 |
| -function formatFinalInstructions(combinedInstructions: string): CallToolResult { |
149 |
| - const fullInstructions = `⚠️ IMPORTANT: DO NOT SKIP ANY STEP |
150 |
| - All the setup steps described in this file MUST be executed regardless of any existing configuration or setup. |
151 |
| - This ensures proper BrowserStack SDK setup. |
152 |
| -
|
153 |
| - ${formatInstructionsWithNumbers(combinedInstructions)}`; |
154 |
| - |
155 |
| - return { |
156 |
| - content: [ |
157 |
| - { |
158 |
| - type: "text", |
159 |
| - text: fullInstructions, |
160 |
| - isError: false, |
161 |
| - }, |
162 |
| - ], |
163 |
| - }; |
164 |
| -} |
165 |
| - |
166 |
| -export default function addSDKTools( |
| 7 | +export function registerRunBrowserStackTestsTool( |
167 | 8 | server: McpServer,
|
168 | 9 | config: BrowserStackConfig,
|
169 | 10 | ) {
|
170 | 11 | const tools: Record<string, any> = {};
|
171 | 12 |
|
172 | 13 | tools.setupBrowserStackAutomateTests = server.tool(
|
173 | 14 | "setupBrowserStackAutomateTests",
|
174 |
| - "Set up and run automated web-based tests on BrowserStack using the BrowserStack SDK. Use for functional or integration tests on BrowserStack, with optional Percy visual testing for supported frameworks. Example prompts: run this test on browserstack; run this test on browserstack with Percy; set up this project for browserstack with Percy. Integrate BrowserStack SDK into your project", |
175 |
| - { |
176 |
| - detectedBrowserAutomationFramework: z |
177 |
| - .nativeEnum(SDKSupportedBrowserAutomationFrameworkEnum) |
178 |
| - .describe( |
179 |
| - "The automation framework configured in the project. Example: 'playwright', 'selenium'", |
180 |
| - ), |
181 |
| - |
182 |
| - detectedTestingFramework: z |
183 |
| - .nativeEnum(SDKSupportedTestingFrameworkEnum) |
184 |
| - .describe( |
185 |
| - "The testing framework used in the project. Be precise with framework selection Example: 'webdriverio', 'jest', 'pytest', 'junit4', 'junit5', 'mocha'", |
186 |
| - ), |
187 |
| - |
188 |
| - detectedLanguage: z |
189 |
| - .nativeEnum(SDKSupportedLanguageEnum) |
190 |
| - .describe( |
191 |
| - "The programming language used in the project. Example: 'nodejs', 'python', 'java', 'csharp'", |
192 |
| - ), |
193 |
| - |
194 |
| - desiredPlatforms: z |
195 |
| - .array(z.enum(["windows", "macos", "android", "ios"])) |
196 |
| - .describe( |
197 |
| - "The platforms the user wants to test on. Always ask this to the user, do not try to infer this.", |
198 |
| - ), |
199 |
| - |
200 |
| - enablePercy: z |
201 |
| - .boolean() |
202 |
| - .optional() |
203 |
| - .default(false) |
204 |
| - .describe( |
205 |
| - "Set to true if the user wants to enable Percy for visual testing. Defaults to false.", |
206 |
| - ), |
207 |
| - }, |
208 |
| - |
| 15 | + RUN_ON_BROWSERSTACK_DESCRIPTION, |
| 16 | + RunTestsOnBrowserStackParamsShape, |
209 | 17 | async (args) => {
|
210 |
| - try { |
211 |
| - trackMCP( |
212 |
| - "runTestsOnBrowserStack", |
213 |
| - server.server.getClientVersion()!, |
214 |
| - undefined, |
215 |
| - config, |
216 |
| - ); |
217 |
| - |
218 |
| - return await bootstrapProjectWithSDK({ |
219 |
| - detectedBrowserAutomationFramework: |
220 |
| - args.detectedBrowserAutomationFramework as SDKSupportedBrowserAutomationFramework, |
221 |
| - |
222 |
| - detectedTestingFramework: |
223 |
| - args.detectedTestingFramework as SDKSupportedTestingFramework, |
224 |
| - |
225 |
| - detectedLanguage: args.detectedLanguage as SDKSupportedLanguage, |
226 |
| - |
227 |
| - desiredPlatforms: args.desiredPlatforms, |
228 |
| - enablePercy: args.enablePercy, |
229 |
| - config, |
230 |
| - }); |
231 |
| - } catch (error) { |
232 |
| - trackMCP( |
233 |
| - "runTestsOnBrowserStack", |
234 |
| - server.server.getClientVersion()!, |
235 |
| - error, |
236 |
| - config, |
237 |
| - ); |
238 |
| - |
239 |
| - return { |
240 |
| - content: [ |
241 |
| - { |
242 |
| - type: "text", |
243 |
| - text: `Failed to bootstrap project with BrowserStack SDK. Error: ${error}. Please open an issue on GitHub if the problem persists`, |
244 |
| - isError: true, |
245 |
| - }, |
246 |
| - ], |
247 |
| - isError: true, |
248 |
| - }; |
249 |
| - } |
| 18 | + return runTestsOnBrowserStackHandler(args, config); |
250 | 19 | },
|
251 | 20 | );
|
252 | 21 |
|
253 | 22 | return tools;
|
254 | 23 | }
|
| 24 | + |
| 25 | +export default registerRunBrowserStackTestsTool; |
0 commit comments