Skip to content

Commit 57026ac

Browse files
committed
add support for XCUITest on BrowserStack
1 parent 3ca6448 commit 57026ac

File tree

2 files changed

+87
-9
lines changed

2 files changed

+87
-9
lines changed

src/tools/appautomate-utils/appautomate.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,26 @@ export async function uploadEspressoTestSuite(
200200
);
201201
}
202202

203+
//Uploads an iOS app (.ipa) to BrowserStack XCUITest endpoint and returns the app_url
204+
export async function uploadXcuiApp(appPath: string): Promise<string> {
205+
return uploadFileToBrowserStack(
206+
appPath,
207+
"https://api-cloud.browserstack.com/app-automate/xcuitest/v2/app",
208+
"app_url",
209+
);
210+
}
211+
212+
//Uploads an XCUITest test suite (.zip) to BrowserStack and returns the test_suite_url
213+
export async function uploadXcuiTestSuite(
214+
testSuitePath: string,
215+
): Promise<string> {
216+
return uploadFileToBrowserStack(
217+
testSuitePath,
218+
"https://api-cloud.browserstack.com/app-automate/xcuitest/v2/test-suite",
219+
"test_suite_url",
220+
);
221+
}
222+
203223
// Triggers an Espresso test run on BrowserStack and returns the build_id
204224
export async function triggerEspressoBuild(
205225
app_url: string,
@@ -228,3 +248,32 @@ export async function triggerEspressoBuild(
228248
`Failed to trigger Espresso build: ${JSON.stringify(response.data)}`,
229249
);
230250
}
251+
252+
// Triggers an XCUITest run on BrowserStack and returns the build_id
253+
export async function triggerXcuiBuild(
254+
app_url: string,
255+
test_suite_url: string,
256+
devices: string[],
257+
project: string,
258+
): Promise<string> {
259+
const response = await axios.post(
260+
"https://api-cloud.browserstack.com/app-automate/xcuitest/v2/build",
261+
{
262+
app: app_url,
263+
testSuite: test_suite_url,
264+
devices,
265+
project,
266+
},
267+
{
268+
auth,
269+
},
270+
);
271+
272+
if (response.data.build_id) {
273+
return response.data.build_id;
274+
}
275+
276+
throw new Error(
277+
`Failed to trigger XCUITest build: ${JSON.stringify(response.data)}`,
278+
);
279+
}

src/tools/appautomate.ts

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ import {
2222
uploadEspressoApp,
2323
uploadEspressoTestSuite,
2424
triggerEspressoBuild,
25+
uploadXcuiApp,
26+
uploadXcuiTestSuite,
27+
triggerXcuiBuild,
2528
} from "./appautomate-utils/appautomate.js";
2629

2730
// Types
@@ -166,7 +169,7 @@ async function runAppTestsOnBrowserStack(args: {
166169
content: [
167170
{
168171
type: "text",
169-
text: `✅ Test run started successfully!\n\n🔧 Build ID: ${build_id}\n🔗 View your build: https://app-automate.browserstack.com/builds/${build_id}`,
172+
text: `✅ Espresso run started successfully!\n\n🔧 Build ID: ${build_id}\n🔗 View your build: https://app-automate.browserstack.com/builds/${build_id}`,
170173
},
171174
],
172175
};
@@ -175,10 +178,32 @@ async function runAppTestsOnBrowserStack(args: {
175178
throw err;
176179
}
177180
}
178-
181+
case AppTestPlatform.XCUITEST: {
182+
try {
183+
const app_url = await uploadXcuiApp(args.appPath);
184+
const test_suite_url = await uploadXcuiTestSuite(args.testSuitePath);
185+
const build_id = await triggerXcuiBuild(
186+
app_url,
187+
test_suite_url,
188+
args.devices,
189+
args.project,
190+
);
191+
return {
192+
content: [
193+
{
194+
type: "text",
195+
text: `✅ XCUITest run started successfully!\n\n🔧 Build ID: ${build_id}\n🔗 View your build: https://app-automate.browserstack.com/builds/${build_id}`,
196+
},
197+
],
198+
};
199+
} catch (err) {
200+
logger.error("Error running XCUITest App Automate test", err);
201+
throw err;
202+
}
203+
}
179204
default:
180205
throw new Error(
181-
`Unsupported automation framework: ${args.detectedAutomationFramework}`,
206+
`Unsupported automation framework: ${args.detectedAutomationFramework}. If you need support for this framework, please open an issue at Github`,
182207
);
183208
}
184209
}
@@ -230,18 +255,22 @@ export default function addAppAutomationTools(server: McpServer) {
230255

231256
server.tool(
232257
"runAppTestsOnBrowserStack",
233-
"Run AppAutomate tests on BrowserStack by uploading app and test suite, then triggering a test run.",
258+
"Run AppAutomate tests on BrowserStack by uploading app and test suite, then triggering a test run. Supports both Espresso (Android) and XCUITest (iOS).",
234259
{
235260
appPath: z
236261
.string()
237-
.describe("Path to the .apk or .aab file for your app."),
262+
.describe(
263+
"Path to the .apk/.aab (Espresso) or .ipa (XCUITest) file for your app. Export on your own in local IDEs.",
264+
),
238265
testSuitePath: z
239266
.string()
240-
.describe("Path to the Espresso test suite .apk file."),
267+
.describe(
268+
"Path to the Espresso test suite .apk or XCUITest .zip file. Export on your own in local IDEs.",
269+
),
241270
devices: z
242271
.array(z.string())
243272
.describe(
244-
"List of devices to run the test on, e.g., ['Samsung Galaxy S20-10.0', 'Google Pixel 3-9.0'].",
273+
"List of devices to run the test on, e.g., ['Samsung Galaxy S20-10.0', 'iPhone 12 Pro-16.0'].",
245274
),
246275
project: z
247276
.string()
@@ -251,7 +280,7 @@ export default function addAppAutomationTools(server: McpServer) {
251280
detectedAutomationFramework: z
252281
.string()
253282
.describe(
254-
"The automation framework used in the project, such as 'espresso' or 'appium'.",
283+
"The automation framework used in the project, such as 'espresso' (Android) or 'xcuitest' (iOS).",
255284
),
256285
},
257286
async (args) => {
@@ -273,7 +302,7 @@ export default function addAppAutomationTools(server: McpServer) {
273302
content: [
274303
{
275304
type: "text",
276-
text: `Error running App Automate test: ${errorMessage}`
305+
text: `Error running App Automate test: ${errorMessage}`,
277306
},
278307
],
279308
isError: true,

0 commit comments

Comments
 (0)