@@ -6,6 +6,7 @@ import config from "../config.js";
6
6
import { trackMCP } from "../lib/instrumentation.js" ;
7
7
import { maybeCompressBase64 } from "../lib/utils.js" ;
8
8
import { remote } from "webdriverio" ;
9
+ import { AppTestPlatform } from "./appautomate-utils/types.js" ;
9
10
10
11
import {
11
12
getDevicesAndBrowsers ,
@@ -18,6 +19,12 @@ import {
18
19
resolveVersion ,
19
20
validateArgs ,
20
21
uploadApp ,
22
+ uploadEspressoApp ,
23
+ uploadEspressoTestSuite ,
24
+ triggerEspressoBuild ,
25
+ uploadXcuiApp ,
26
+ uploadXcuiTestSuite ,
27
+ triggerXcuiBuild ,
21
28
} from "./appautomate-utils/appautomate.js" ;
22
29
23
30
// Types
@@ -143,9 +150,72 @@ async function takeAppScreenshot(args: {
143
150
}
144
151
}
145
152
146
- /**
147
- * Registers the `takeAppScreenshot` tool with the MCP server.
148
- */
153
+ //Runs AppAutomate tests on BrowserStack by uploading app and test suite, then triggering a test run.
154
+ async function runAppTestsOnBrowserStack ( args : {
155
+ appPath : string ;
156
+ testSuitePath : string ;
157
+ devices : string [ ] ;
158
+ project : string ;
159
+ detectedAutomationFramework : string ;
160
+ } ) : Promise < CallToolResult > {
161
+ switch ( args . detectedAutomationFramework ) {
162
+ case AppTestPlatform . ESPRESSO : {
163
+ try {
164
+ const app_url = await uploadEspressoApp ( args . appPath ) ;
165
+ const test_suite_url = await uploadEspressoTestSuite (
166
+ args . testSuitePath ,
167
+ ) ;
168
+ const build_id = await triggerEspressoBuild (
169
+ app_url ,
170
+ test_suite_url ,
171
+ args . devices ,
172
+ args . project ,
173
+ ) ;
174
+
175
+ return {
176
+ content : [
177
+ {
178
+ type : "text" ,
179
+ text : `✅ Espresso run started successfully!\n\n🔧 Build ID: ${ build_id } \n🔗 View your build: https://app-automate.browserstack.com/builds/${ build_id } ` ,
180
+ } ,
181
+ ] ,
182
+ } ;
183
+ } catch ( err ) {
184
+ logger . error ( "Error running App Automate test" , err ) ;
185
+ throw err ;
186
+ }
187
+ }
188
+ case AppTestPlatform . XCUITEST : {
189
+ try {
190
+ const app_url = await uploadXcuiApp ( args . appPath ) ;
191
+ const test_suite_url = await uploadXcuiTestSuite ( args . testSuitePath ) ;
192
+ const build_id = await triggerXcuiBuild (
193
+ app_url ,
194
+ test_suite_url ,
195
+ args . devices ,
196
+ args . project ,
197
+ ) ;
198
+ return {
199
+ content : [
200
+ {
201
+ type : "text" ,
202
+ text : `✅ XCUITest run started successfully!\n\n🔧 Build ID: ${ build_id } \n🔗 View your build: https://app-automate.browserstack.com/builds/${ build_id } ` ,
203
+ } ,
204
+ ] ,
205
+ } ;
206
+ } catch ( err ) {
207
+ logger . error ( "Error running XCUITest App Automate test" , err ) ;
208
+ throw err ;
209
+ }
210
+ }
211
+ default :
212
+ throw new Error (
213
+ `Unsupported automation framework: ${ args . detectedAutomationFramework } . If you need support for this framework, please open an issue at Github` ,
214
+ ) ;
215
+ }
216
+ }
217
+
218
+ // Registers automation tools with the MCP server.
149
219
export default function addAppAutomationTools ( server : McpServer ) {
150
220
server . tool (
151
221
"takeAppScreenshot" ,
@@ -189,4 +259,76 @@ export default function addAppAutomationTools(server: McpServer) {
189
259
}
190
260
} ,
191
261
) ;
262
+
263
+ server . tool (
264
+ "runAppTestsOnBrowserStack" ,
265
+ "Run AppAutomate tests on BrowserStack by uploading app and test suite. If running from Android Studio or Xcode, the tool will help export app and test files automatically. For other environments, you'll need to provide the paths to your pre-built app and test files." ,
266
+ {
267
+ appPath : z
268
+ . string ( )
269
+ . describe (
270
+ "Path to your application file:\n" +
271
+ "If in development IDE directory:\n" +
272
+ "• For Android: 'gradle assembleDebug'\n" +
273
+ "• For iOS:\n" +
274
+ " xcodebuild clean -scheme YOUR_SCHEME && \\\n" +
275
+ " xcodebuild archive -scheme YOUR_SCHEME -configuration Release -archivePath build/app.xcarchive && \\\n" +
276
+ " xcodebuild -exportArchive -archivePath build/app.xcarchive -exportPath build/ipa -exportOptionsPlist exportOptions.plist\n\n" +
277
+ "If in other directory, provide existing app path"
278
+ ) ,
279
+ testSuitePath : z
280
+ . string ( )
281
+ . describe (
282
+ "Path to your test suite file:\n" +
283
+ "If in development IDE directory:\n" +
284
+ "• For Android: 'gradle assembleAndroidTest'\n" +
285
+ "• For iOS:\n" +
286
+ " xcodebuild test-without-building -scheme YOUR_SCHEME -destination 'generic/platform=iOS' && \\\n" +
287
+ " cd ~/Library/Developer/Xcode/DerivedData/*/Build/Products/Debug-iphonesimulator/ && \\\n" +
288
+ " zip -r Tests.zip *.xctestrun *-Runner.app\n\n" +
289
+ "If in other directory, provide existing test file path"
290
+ ) ,
291
+ devices : z
292
+ . array ( z . string ( ) )
293
+ . describe (
294
+ "List of devices to run the test on, e.g., ['Samsung Galaxy S20-10.0', 'iPhone 12 Pro-16.0']." ,
295
+ ) ,
296
+ project : z
297
+ . string ( )
298
+ . optional ( )
299
+ . default ( "BStack-AppAutomate-Suite" )
300
+ . describe ( "Project name for organizing test runs on BrowserStack." ) ,
301
+ detectedAutomationFramework : z
302
+ . string ( )
303
+ . describe (
304
+ "The automation framework used in the project, such as 'espresso' (Android) or 'xcuitest' (iOS)." ,
305
+ ) ,
306
+ } ,
307
+ async ( args ) => {
308
+ try {
309
+ trackMCP (
310
+ "runAppTestsOnBrowserStack" ,
311
+ server . server . getClientVersion ( ) ! ,
312
+ ) ;
313
+ return await runAppTestsOnBrowserStack ( args ) ;
314
+ } catch ( error ) {
315
+ trackMCP (
316
+ "runAppTestsOnBrowserStack" ,
317
+ server . server . getClientVersion ( ) ! ,
318
+ error ,
319
+ ) ;
320
+ const errorMessage =
321
+ error instanceof Error ? error . message : "Unknown error" ;
322
+ return {
323
+ content : [
324
+ {
325
+ type : "text" ,
326
+ text : `Error running App Automate test: ${ errorMessage } ` ,
327
+ } ,
328
+ ] ,
329
+ isError : true ,
330
+ } ;
331
+ }
332
+ } ,
333
+ ) ;
192
334
}
0 commit comments