@browserstack/mcp-server 1.2.3 → 1.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -2
- package/dist/lib/device-cache.js +20 -17
- package/dist/lib/inmemory-store.d.ts +1 -0
- package/dist/lib/inmemory-store.js +1 -0
- package/dist/lib/utils.d.ts +5 -0
- package/dist/lib/utils.js +27 -0
- package/dist/server-factory.js +6 -0
- package/dist/tools/add-percy-snapshots.d.ts +5 -0
- package/dist/tools/add-percy-snapshots.js +17 -0
- package/dist/tools/appautomate-utils/appium-sdk/config-generator.d.ts +1 -0
- package/dist/tools/appautomate-utils/appium-sdk/config-generator.js +50 -0
- package/dist/tools/appautomate-utils/appium-sdk/constants.d.ts +23 -0
- package/dist/tools/appautomate-utils/appium-sdk/constants.js +43 -0
- package/dist/tools/appautomate-utils/appium-sdk/formatter.d.ts +8 -0
- package/dist/tools/appautomate-utils/appium-sdk/formatter.js +59 -0
- package/dist/tools/appautomate-utils/appium-sdk/handler.d.ts +3 -0
- package/dist/tools/appautomate-utils/appium-sdk/handler.js +52 -0
- package/dist/tools/appautomate-utils/appium-sdk/index.d.ts +7 -0
- package/dist/tools/appautomate-utils/appium-sdk/index.js +8 -0
- package/dist/tools/appautomate-utils/appium-sdk/instructions.d.ts +3 -0
- package/dist/tools/appautomate-utils/appium-sdk/instructions.js +47 -0
- package/dist/tools/appautomate-utils/appium-sdk/languages/csharp.d.ts +2 -0
- package/dist/tools/appautomate-utils/appium-sdk/languages/csharp.js +78 -0
- package/dist/tools/appautomate-utils/appium-sdk/languages/java.d.ts +8 -0
- package/dist/tools/appautomate-utils/appium-sdk/languages/java.js +87 -0
- package/dist/tools/appautomate-utils/appium-sdk/languages/nodejs.d.ts +3 -0
- package/dist/tools/appautomate-utils/appium-sdk/languages/nodejs.js +194 -0
- package/dist/tools/appautomate-utils/appium-sdk/languages/python.d.ts +3 -0
- package/dist/tools/appautomate-utils/appium-sdk/languages/python.js +76 -0
- package/dist/tools/appautomate-utils/appium-sdk/languages/ruby.d.ts +2 -0
- package/dist/tools/appautomate-utils/appium-sdk/languages/ruby.js +85 -0
- package/dist/tools/appautomate-utils/appium-sdk/types.d.ts +57 -0
- package/dist/tools/appautomate-utils/appium-sdk/types.js +54 -0
- package/dist/tools/appautomate-utils/appium-sdk/utils.d.ts +17 -0
- package/dist/tools/appautomate-utils/appium-sdk/utils.js +64 -0
- package/dist/tools/appautomate-utils/{appautomate.d.ts → native-execution/appautomate.d.ts} +1 -1
- package/dist/tools/appautomate-utils/{appautomate.js → native-execution/appautomate.js} +2 -2
- package/dist/tools/appautomate-utils/native-execution/constants.d.ts +10 -0
- package/dist/tools/appautomate-utils/native-execution/constants.js +36 -0
- package/dist/tools/appautomate-utils/native-execution/types.d.ts +19 -0
- package/dist/tools/appautomate-utils/{types.js → native-execution/types.js} +5 -1
- package/dist/tools/appautomate.js +25 -40
- package/dist/tools/bstack-sdk.d.ts +2 -15
- package/dist/tools/bstack-sdk.js +10 -119
- package/dist/tools/build-insights.d.ts +7 -0
- package/dist/tools/build-insights.js +67 -0
- package/dist/tools/list-test-files.d.ts +2 -0
- package/dist/tools/list-test-files.js +36 -0
- package/dist/tools/percy-sdk.d.ts +4 -0
- package/dist/tools/percy-sdk.js +71 -0
- package/dist/tools/percy-snapshot-utils/constants.d.ts +16 -0
- package/dist/tools/percy-snapshot-utils/constants.js +500 -0
- package/dist/tools/percy-snapshot-utils/detect-test-files.d.ts +10 -0
- package/dist/tools/percy-snapshot-utils/detect-test-files.js +175 -0
- package/dist/tools/percy-snapshot-utils/types.d.ts +15 -0
- package/dist/tools/percy-snapshot-utils/utils.d.ts +4 -0
- package/dist/tools/percy-snapshot-utils/utils.js +30 -0
- package/dist/tools/rca-agent-utils/constants.d.ts +13 -0
- package/dist/tools/rca-agent-utils/constants.js +24 -0
- package/dist/tools/rca-agent-utils/format-rca.d.ts +1 -0
- package/dist/tools/rca-agent-utils/format-rca.js +37 -0
- package/dist/tools/rca-agent-utils/get-build-id.d.ts +1 -0
- package/dist/tools/rca-agent-utils/get-build-id.js +18 -0
- package/dist/tools/rca-agent-utils/get-failed-test-id.d.ts +2 -0
- package/dist/tools/rca-agent-utils/get-failed-test-id.js +69 -0
- package/dist/tools/rca-agent-utils/rca-data.d.ts +9 -0
- package/dist/tools/rca-agent-utils/rca-data.js +196 -0
- package/dist/tools/rca-agent-utils/types.d.ts +48 -0
- package/dist/tools/rca-agent-utils/types.js +20 -0
- package/dist/tools/rca-agent.d.ts +14 -0
- package/dist/tools/rca-agent.js +119 -0
- package/dist/tools/review-agent-utils/build-counts.d.ts +7 -0
- package/dist/tools/review-agent-utils/build-counts.js +44 -0
- package/dist/tools/review-agent-utils/percy-approve-reject.d.ts +6 -0
- package/dist/tools/review-agent-utils/percy-approve-reject.js +39 -0
- package/dist/tools/review-agent-utils/percy-diffs.d.ts +9 -0
- package/dist/tools/review-agent-utils/percy-diffs.js +35 -0
- package/dist/tools/review-agent-utils/percy-snapshots.d.ts +11 -0
- package/dist/tools/review-agent-utils/percy-snapshots.js +58 -0
- package/dist/tools/review-agent.d.ts +5 -0
- package/dist/tools/review-agent.js +56 -0
- package/dist/tools/run-percy-scan.d.ts +8 -0
- package/dist/tools/run-percy-scan.js +37 -0
- package/dist/tools/sdk-utils/{commands.d.ts → bstack/commands.d.ts} +1 -1
- package/dist/tools/sdk-utils/bstack/commands.js +88 -0
- package/dist/tools/sdk-utils/bstack/configUtils.d.ts +4 -0
- package/dist/tools/sdk-utils/bstack/configUtils.js +66 -0
- package/dist/tools/sdk-utils/bstack/constants.d.ts +58 -0
- package/dist/tools/sdk-utils/{constants.js → bstack/constants.js} +117 -78
- package/dist/tools/sdk-utils/{constants.d.ts → bstack/frameworks.d.ts} +1 -1
- package/dist/tools/sdk-utils/bstack/frameworks.js +57 -0
- package/dist/tools/sdk-utils/bstack/index.d.ts +4 -0
- package/dist/tools/sdk-utils/bstack/index.js +5 -0
- package/dist/tools/sdk-utils/bstack/sdkHandler.d.ts +4 -0
- package/dist/tools/sdk-utils/bstack/sdkHandler.js +74 -0
- package/dist/tools/sdk-utils/common/constants.d.ts +10 -0
- package/dist/tools/sdk-utils/common/constants.js +86 -0
- package/dist/tools/sdk-utils/common/formatUtils.d.ts +5 -0
- package/dist/tools/sdk-utils/common/formatUtils.js +27 -0
- package/dist/tools/sdk-utils/common/index.d.ts +3 -0
- package/dist/tools/sdk-utils/common/index.js +4 -0
- package/dist/tools/sdk-utils/common/instructionUtils.d.ts +8 -0
- package/dist/tools/sdk-utils/common/instructionUtils.js +20 -0
- package/dist/tools/sdk-utils/common/schema.d.ts +73 -0
- package/dist/tools/sdk-utils/common/schema.js +51 -0
- package/dist/tools/sdk-utils/common/types.d.ts +66 -0
- package/dist/tools/sdk-utils/{types.js → common/types.js} +15 -2
- package/dist/tools/sdk-utils/common/utils.d.ts +25 -0
- package/dist/tools/sdk-utils/common/utils.js +90 -0
- package/dist/tools/sdk-utils/handler.d.ts +4 -0
- package/dist/tools/sdk-utils/handler.js +119 -0
- package/dist/tools/sdk-utils/percy-automate/constants.d.ts +11 -0
- package/dist/tools/sdk-utils/percy-automate/constants.js +338 -0
- package/dist/tools/sdk-utils/percy-automate/frameworks.d.ts +8 -0
- package/dist/tools/sdk-utils/percy-automate/frameworks.js +50 -0
- package/dist/tools/sdk-utils/percy-automate/handler.d.ts +3 -0
- package/dist/tools/sdk-utils/percy-automate/handler.js +30 -0
- package/dist/tools/sdk-utils/percy-automate/index.d.ts +1 -0
- package/dist/tools/sdk-utils/percy-automate/index.js +2 -0
- package/dist/tools/sdk-utils/percy-automate/types.d.ts +13 -0
- package/dist/tools/sdk-utils/percy-automate/types.js +1 -0
- package/dist/tools/sdk-utils/percy-bstack/constants.d.ts +4 -0
- package/dist/tools/sdk-utils/{percy → percy-bstack}/constants.js +13 -39
- package/dist/tools/sdk-utils/percy-bstack/frameworks.d.ts +2 -0
- package/dist/tools/sdk-utils/percy-bstack/frameworks.js +27 -0
- package/dist/tools/sdk-utils/percy-bstack/handler.d.ts +4 -0
- package/dist/tools/sdk-utils/percy-bstack/handler.js +99 -0
- package/dist/tools/sdk-utils/percy-bstack/index.d.ts +4 -0
- package/dist/tools/sdk-utils/percy-bstack/index.js +4 -0
- package/dist/tools/sdk-utils/percy-bstack/instructions.d.ts +7 -0
- package/dist/tools/sdk-utils/{percy → percy-bstack}/instructions.js +5 -9
- package/dist/tools/sdk-utils/percy-bstack/types.d.ts +13 -0
- package/dist/tools/sdk-utils/percy-bstack/types.js +5 -0
- package/dist/tools/sdk-utils/percy-web/constants.d.ts +41 -0
- package/dist/tools/sdk-utils/percy-web/constants.js +883 -0
- package/dist/tools/sdk-utils/percy-web/fetchPercyToken.d.ts +4 -0
- package/dist/tools/sdk-utils/percy-web/fetchPercyToken.js +32 -0
- package/dist/tools/sdk-utils/percy-web/frameworks.d.ts +7 -0
- package/dist/tools/sdk-utils/percy-web/frameworks.js +103 -0
- package/dist/tools/sdk-utils/percy-web/handler.d.ts +4 -0
- package/dist/tools/sdk-utils/percy-web/handler.js +27 -0
- package/dist/tools/sdk-utils/percy-web/index.d.ts +4 -0
- package/dist/tools/sdk-utils/percy-web/index.js +4 -0
- package/dist/tools/sdk-utils/percy-web/types.d.ts +12 -0
- package/dist/tools/sdk-utils/percy-web/types.js +1 -0
- package/dist/tools/testmanagement-utils/create-testrun.d.ts +4 -4
- package/dist/tools/testmanagement-utils/update-testrun.d.ts +4 -4
- package/package.json +2 -1
- package/dist/tools/appautomate-utils/types.d.ts +0 -5
- package/dist/tools/sdk-utils/commands.js +0 -65
- package/dist/tools/sdk-utils/instructions.d.ts +0 -6
- package/dist/tools/sdk-utils/instructions.js +0 -99
- package/dist/tools/sdk-utils/percy/constants.d.ts +0 -3
- package/dist/tools/sdk-utils/percy/instructions.d.ts +0 -10
- package/dist/tools/sdk-utils/percy/types.d.ts +0 -5
- package/dist/tools/sdk-utils/types.d.ts +0 -40
- /package/dist/tools/{sdk-utils/percy → percy-snapshot-utils}/types.js +0 -0
package/README.md
CHANGED
|
@@ -38,7 +38,15 @@ Stay in flow—keep all project context in one place and trigger actions directl
|
|
|
38
38
|
## ⚡️ One Click MCP Setup
|
|
39
39
|
|
|
40
40
|
[](http://mcp.browserstack.com/one-click-setup?client=vscode) [](http://mcp.browserstack.com/one-click-setup?client=cursor)
|
|
41
|
-
|
|
41
|
+
#### Note : Ensure you are using Node version >= `18.0`
|
|
42
|
+
- Check your node version using `node --version`. Recommended version: `v22.15.0` (LTS)
|
|
43
|
+
- To Upgrade Node :
|
|
44
|
+
- 1. On macOS `(Homebrew) - brew update && brew upgrade node or if using (nvm) - nvm install 22.15.0 && nvm use 22.15.0 && nvm alias default 22.15.0`
|
|
45
|
+
- 2. On Windows `(nvm-windows) : nvm install 22.15.0 && nvm use 22.15.0`
|
|
46
|
+
- 👉 <a href="https://nodejs.org/en/download" target="_blank">Or directly download the Node.js LTS Installer</a>
|
|
47
|
+
|
|
48
|
+
.
|
|
49
|
+
|
|
42
50
|
## 💡 Usage Examples
|
|
43
51
|
|
|
44
52
|
### 📱 Manual App Testing
|
|
@@ -142,6 +150,10 @@ Generate test cases from PRDs, convert manual tests to low-code automation, and
|
|
|
142
150
|
|
|
143
151
|
## 🛠️ Installation
|
|
144
152
|
|
|
153
|
+
### 📋 Prerequisites for MCP Setup
|
|
154
|
+
#### Note : Ensure you are using Node version >= `18.0`
|
|
155
|
+
- Check your node version using `node --version`. Recommended version: `v22.15.0` (LTS)
|
|
156
|
+
|
|
145
157
|
### **One Click MCP Setup**
|
|
146
158
|
|
|
147
159
|
[](http://mcp.browserstack.com/one-click-setup?client=vscode) [](http://mcp.browserstack.com/one-click-setup?client=cursor)
|
|
@@ -158,7 +170,9 @@ Generate test cases from PRDs, convert manual tests to low-code automation, and
|
|
|
158
170
|
|
|
159
171
|
- Once you have an account (and purchased appropriate plan), note down your `username` and `access_key` from [Account Settings](https://www.browserstack.com/accounts/profile/details).
|
|
160
172
|
|
|
161
|
-
2. Ensure you are using Node version >= `18.0
|
|
173
|
+
2. #### Note : Ensure you are using Node version >= `18.0`
|
|
174
|
+
- Check your node version using `node --version`. Recommended version: `v22.15.0` (LTS)
|
|
175
|
+
|
|
162
176
|
|
|
163
177
|
3. **Install the MCP Server**
|
|
164
178
|
|
|
@@ -456,7 +470,79 @@ As of now we support 20 tools.
|
|
|
456
470
|
```text
|
|
457
471
|
Upload PRD from /Users/xyz/Desktop/login-flow.pdf and use BrowserStack AI to generate test cases
|
|
458
472
|
```
|
|
473
|
+
## 🚀 Remote MCP Server
|
|
474
|
+
|
|
475
|
+
Remote MCP comes with all the functionalities of an MCP server without the hassles of complex setup or local installation.
|
|
476
|
+
|
|
477
|
+
### Key benefits:
|
|
478
|
+
|
|
479
|
+
- ✅ Works seamlessly in enterprise networks without worrying about firewalls or binaries or where local installation is not allowed.
|
|
480
|
+
|
|
481
|
+
- ✅ Secure OAuth integration – no password sharing or manual credential handling.
|
|
482
|
+
|
|
483
|
+
### Limitations:
|
|
484
|
+
|
|
485
|
+
- ❌ No Local Testing support (cannot test apps behind VPNs, firewalls, or localhost). If you have to do Local Testing, you would have to use a BrowserStack Local MCP server.
|
|
486
|
+
- ❌ Latency can be slightly higher, but nothing considerable — you generally won’t notice it in normal use.
|
|
487
|
+
|
|
488
|
+
### Installation Steps:
|
|
459
489
|
|
|
490
|
+
- On VSCode (Copilot - Agent Mode): `.vscode/mcp.json`:
|
|
491
|
+
|
|
492
|
+
- Locate or Create the Configuration File:
|
|
493
|
+
- In the root directory of your project, look for a folder named .vscode. This folder is usually hidden so you will need to find it as mentioned in the expand.
|
|
494
|
+
- If this folder doesn't exist, create it.
|
|
495
|
+
- Inside the .vscode folder, create a new file named mcp.json
|
|
496
|
+
- To setup Remote BrowserStack MCP instead of local BrowserStack MCP you can add the following JSON content :
|
|
497
|
+
<div align="center">
|
|
498
|
+
<img src="assets/remotemcp_json_file.png" alt="Remote MCP JSON file" height="300" width="300">
|
|
499
|
+
</div>
|
|
500
|
+
|
|
501
|
+
### Alternative way to Setup Remote MCP
|
|
502
|
+
|
|
503
|
+
- Step 1.Click on the gear icon to Select Tools
|
|
504
|
+
|
|
505
|
+
<div align="center">
|
|
506
|
+
<img src="assets/select_tools.png" alt="Select Tools" height="300" width="300">
|
|
507
|
+
</div>
|
|
508
|
+
|
|
509
|
+
- Step 2. A tool menu would appear at the top-centre, scroll down on the menu at the top and then Click on Add MCP Server
|
|
510
|
+
|
|
511
|
+
<div align="center">
|
|
512
|
+
<img src="assets/add_mcp_server.png" alt="Add MCP Server" height="300" width="300">
|
|
513
|
+
</div>
|
|
514
|
+
|
|
515
|
+
- Step 3. Click on HTTP option
|
|
516
|
+
<div align="center">
|
|
517
|
+
<img src="assets/http_option.png" alt="HTTP Option" height="300" width="300">
|
|
518
|
+
</div>
|
|
519
|
+
|
|
520
|
+
- Step 4. Paste Remote MCP Server URL : https://mcp.browserstack.com/mcp
|
|
521
|
+
<div align="center">
|
|
522
|
+
<img src="assets/server_url.png" alt="Remote MCP Server URL" height="300" width="300">
|
|
523
|
+
</div>
|
|
524
|
+
|
|
525
|
+
- Step 5. Give server id as : browserstack
|
|
526
|
+
|
|
527
|
+
<div align="center">
|
|
528
|
+
<img src="assets/server_id.png" alt="Remote MCP Server ID" height="300" width="300">
|
|
529
|
+
</div>
|
|
530
|
+
|
|
531
|
+
- Step 6. In VSCode Click on start MCP Server and then click on "Allow"
|
|
532
|
+
|
|
533
|
+
<div align="center">
|
|
534
|
+
<img src="assets/authentication1.png" alt="authentication1" height="300" width="300">
|
|
535
|
+
</div>
|
|
536
|
+
|
|
537
|
+
<div align="center">
|
|
538
|
+
<img src="assets/authentication2.png" alt="authentication2" height="300" width="300">
|
|
539
|
+
</div>
|
|
540
|
+
|
|
541
|
+
<div align="center">
|
|
542
|
+
<img src="assets/signin_success.png" alt="Sign_in_success" height="300" width="300">
|
|
543
|
+
</div>
|
|
544
|
+
|
|
545
|
+
|
|
460
546
|
|
|
461
547
|
## 🤝 Recommended MCP Clients
|
|
462
548
|
|
package/dist/lib/device-cache.js
CHANGED
|
@@ -26,30 +26,33 @@ export async function getDevicesAndBrowsers(type) {
|
|
|
26
26
|
fs.mkdirSync(CACHE_DIR, { recursive: true });
|
|
27
27
|
}
|
|
28
28
|
let cache = {};
|
|
29
|
+
// Load existing cache
|
|
29
30
|
if (fs.existsSync(CACHE_FILE)) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
31
|
+
try {
|
|
32
|
+
cache = JSON.parse(fs.readFileSync(CACHE_FILE, "utf8"));
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
console.error("Error parsing cache file:", err);
|
|
36
|
+
cache = {};
|
|
37
|
+
}
|
|
38
|
+
// Check per-product TTL
|
|
39
|
+
const cachedEntry = cache[type];
|
|
40
|
+
if (cachedEntry?.timestamp && Date.now() - cachedEntry.timestamp < TTL_MS) {
|
|
41
|
+
return cachedEntry.data;
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
+
// Fetch fresh data from BrowserStack
|
|
44
45
|
const liveRes = await apiClient.get({ url: URLS[type], raise_error: false });
|
|
45
46
|
if (!liveRes.ok) {
|
|
46
|
-
throw new Error(`Failed to fetch configuration from BrowserStack
|
|
47
|
+
throw new Error(`Failed to fetch configuration from BrowserStack: ${type} = ${liveRes.statusText}`);
|
|
47
48
|
}
|
|
48
|
-
cache
|
|
49
|
-
|
|
49
|
+
// Save to cache with timestamp and data directly under product key
|
|
50
|
+
cache[type] = {
|
|
51
|
+
timestamp: Date.now(),
|
|
52
|
+
data: liveRes.data,
|
|
50
53
|
};
|
|
51
|
-
fs.writeFileSync(CACHE_FILE, JSON.stringify(cache), "utf8");
|
|
52
|
-
return
|
|
54
|
+
fs.writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2), "utf8");
|
|
55
|
+
return liveRes.data;
|
|
53
56
|
}
|
|
54
57
|
// Rate limiter for started event (3H)
|
|
55
58
|
export function shouldSendStartedEvent() {
|
package/dist/lib/utils.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { ApiResponse } from "./apiClient.js";
|
|
2
|
+
import { BrowserStackConfig } from "./types.js";
|
|
3
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
+
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
5
|
export declare function sanitizeUrlParam(param: string): string;
|
|
3
6
|
export declare function maybeCompressBase64(base64: string): Promise<string>;
|
|
4
7
|
export declare function assertOkResponse(response: Response | ApiResponse, action: string): Promise<void>;
|
|
8
|
+
export declare function fetchFromBrowserStackAPI(url: string, config: BrowserStackConfig): Promise<any>;
|
|
9
|
+
export declare function handleMCPError(toolName: string, server: McpServer, config: BrowserStackConfig, error: unknown): CallToolResult;
|
package/dist/lib/utils.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import sharp from "sharp";
|
|
2
|
+
import { getBrowserStackAuth } from "./get-auth.js";
|
|
3
|
+
import { trackMCP } from "../index.js";
|
|
2
4
|
export function sanitizeUrlParam(param) {
|
|
3
5
|
// Remove any characters that could be used for command injection
|
|
4
6
|
return param.replace(/[;&|`$(){}[\]<>]/g, "");
|
|
@@ -24,3 +26,28 @@ export async function assertOkResponse(response, action) {
|
|
|
24
26
|
throw new Error(`Failed to fetch logs for ${action}: ${response.statusText}`);
|
|
25
27
|
}
|
|
26
28
|
}
|
|
29
|
+
export async function fetchFromBrowserStackAPI(url, config) {
|
|
30
|
+
const authString = getBrowserStackAuth(config);
|
|
31
|
+
const auth = Buffer.from(authString).toString("base64");
|
|
32
|
+
const res = await fetch(url, {
|
|
33
|
+
headers: {
|
|
34
|
+
Authorization: `Basic ${auth}`,
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
if (!res.ok) {
|
|
38
|
+
throw new Error(`Failed to fetch from ${url}: ${res.status} ${res.statusText}`);
|
|
39
|
+
}
|
|
40
|
+
return res.json();
|
|
41
|
+
}
|
|
42
|
+
function errorContent(message) {
|
|
43
|
+
return {
|
|
44
|
+
content: [{ type: "text", text: message }],
|
|
45
|
+
isError: true,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export function handleMCPError(toolName, server, config, error) {
|
|
49
|
+
trackMCP(toolName, server.server.getClientVersion(), error, config);
|
|
50
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
51
|
+
const readableToolName = toolName.replace(/([A-Z])/g, " $1").toLowerCase();
|
|
52
|
+
return errorContent(`Failed to ${readableToolName}: ${errorMessage}. Please open an issue on GitHub if the problem persists`);
|
|
53
|
+
}
|
package/dist/server-factory.js
CHANGED
|
@@ -4,6 +4,7 @@ const require = createRequire(import.meta.url);
|
|
|
4
4
|
const packageJson = require("../package.json");
|
|
5
5
|
import logger from "./logger.js";
|
|
6
6
|
import addSDKTools from "./tools/bstack-sdk.js";
|
|
7
|
+
import addPercyTools from "./tools/percy-sdk.js";
|
|
7
8
|
import addBrowserLiveTools from "./tools/live.js";
|
|
8
9
|
import addAccessibilityTools from "./tools/accessibility.js";
|
|
9
10
|
import addTestManagementTools from "./tools/testmanagement.js";
|
|
@@ -12,7 +13,9 @@ import addFailureLogsTools from "./tools/get-failure-logs.js";
|
|
|
12
13
|
import addAutomateTools from "./tools/automate.js";
|
|
13
14
|
import addSelfHealTools from "./tools/selfheal.js";
|
|
14
15
|
import addAppLiveTools from "./tools/applive.js";
|
|
16
|
+
import addBuildInsightsTools from "./tools/build-insights.js";
|
|
15
17
|
import { setupOnInitialized } from "./oninitialized.js";
|
|
18
|
+
import addRCATools from "./tools/rca-agent.js";
|
|
16
19
|
/**
|
|
17
20
|
* Wrapper class for BrowserStack MCP Server
|
|
18
21
|
* Stores a map of registered tools by name
|
|
@@ -38,6 +41,7 @@ export class BrowserStackMcpServer {
|
|
|
38
41
|
const toolAdders = [
|
|
39
42
|
addAccessibilityTools,
|
|
40
43
|
addSDKTools,
|
|
44
|
+
addPercyTools,
|
|
41
45
|
addAppLiveTools,
|
|
42
46
|
addBrowserLiveTools,
|
|
43
47
|
addTestManagementTools,
|
|
@@ -45,6 +49,8 @@ export class BrowserStackMcpServer {
|
|
|
45
49
|
addFailureLogsTools,
|
|
46
50
|
addAutomateTools,
|
|
47
51
|
addSelfHealTools,
|
|
52
|
+
addBuildInsightsTools,
|
|
53
|
+
addRCATools,
|
|
48
54
|
];
|
|
49
55
|
toolAdders.forEach((adder) => {
|
|
50
56
|
// Each adder now returns a Record<string, Tool>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { testFilePathsMap } from "../lib/inmemory-store.js";
|
|
2
|
+
import { updateFileAndStep } from "./percy-snapshot-utils/utils.js";
|
|
3
|
+
import { percyWebSetupInstructions } from "../tools/sdk-utils/percy-web/handler.js";
|
|
4
|
+
export async function updateTestsWithPercyCommands(args) {
|
|
5
|
+
const { uuid, index } = args;
|
|
6
|
+
const filePaths = testFilePathsMap.get(uuid);
|
|
7
|
+
if (!filePaths) {
|
|
8
|
+
throw new Error(`No test files found in memory for UUID: ${uuid}`);
|
|
9
|
+
}
|
|
10
|
+
if (index < 0 || index >= filePaths.length) {
|
|
11
|
+
throw new Error(`Invalid index: ${index}. There are ${filePaths.length} files for UUID: ${uuid}`);
|
|
12
|
+
}
|
|
13
|
+
const result = await updateFileAndStep(filePaths[index], index, filePaths.length, percyWebSetupInstructions);
|
|
14
|
+
return {
|
|
15
|
+
content: result,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function generateAppBrowserStackYMLInstructions(platforms: string[], username: string, accessKey: string, appPath: string | undefined, testingFramework: string): string;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Configuration utilities for BrowserStack App SDK
|
|
2
|
+
import { APP_DEVICE_CONFIGS, AppSDKSupportedTestingFrameworkEnum, DEFAULT_APP_PATH, createStep, } from "./index.js";
|
|
3
|
+
export function generateAppBrowserStackYMLInstructions(platforms, username, accessKey, appPath = DEFAULT_APP_PATH, testingFramework) {
|
|
4
|
+
if (testingFramework === AppSDKSupportedTestingFrameworkEnum.nightwatch ||
|
|
5
|
+
testingFramework === AppSDKSupportedTestingFrameworkEnum.webdriverio ||
|
|
6
|
+
testingFramework === AppSDKSupportedTestingFrameworkEnum.cucumberRuby) {
|
|
7
|
+
return "";
|
|
8
|
+
}
|
|
9
|
+
// Generate platform and device configurations
|
|
10
|
+
const platformConfigs = platforms
|
|
11
|
+
.map((platform) => {
|
|
12
|
+
const devices = APP_DEVICE_CONFIGS[platform];
|
|
13
|
+
if (!devices)
|
|
14
|
+
return "";
|
|
15
|
+
return devices
|
|
16
|
+
.map((device) => ` - platformName: ${platform}
|
|
17
|
+
deviceName: ${device.deviceName}
|
|
18
|
+
platformVersion: "${device.platformVersion}"`)
|
|
19
|
+
.join("\n");
|
|
20
|
+
})
|
|
21
|
+
.filter(Boolean)
|
|
22
|
+
.join("\n");
|
|
23
|
+
// Construct YAML content
|
|
24
|
+
const configContent = `\`\`\`yaml
|
|
25
|
+
userName: ${username}
|
|
26
|
+
accessKey: ${accessKey}
|
|
27
|
+
app: ${appPath}
|
|
28
|
+
platforms:
|
|
29
|
+
${platformConfigs}
|
|
30
|
+
parallelsPerPlatform: 1
|
|
31
|
+
browserstackLocal: true
|
|
32
|
+
buildName: bstack-demo
|
|
33
|
+
projectName: BrowserStack Sample
|
|
34
|
+
debug: true
|
|
35
|
+
networkLogs: true
|
|
36
|
+
percy: false
|
|
37
|
+
percyCaptureMode: auto
|
|
38
|
+
accessibility: false
|
|
39
|
+
\`\`\`
|
|
40
|
+
|
|
41
|
+
**Important notes:**
|
|
42
|
+
- Replace \`app: ${appPath}\` with the path to your actual app file (e.g., \`./SampleApp.apk\` for Android or \`./SampleApp.ipa\` for iOS)
|
|
43
|
+
- You can upload your app using BrowserStack's App Upload API or manually through the dashboard
|
|
44
|
+
- Set \`browserstackLocal: true\` if you need to test with local/staging servers
|
|
45
|
+
- Adjust \`parallelsPerPlatform\` based on your subscription limits`;
|
|
46
|
+
// Return formatted step for instructions
|
|
47
|
+
return createStep("Update browserstack.yml file with App Automate configuration:", `Create or update the browserstack.yml file in your project root with the following content:
|
|
48
|
+
|
|
49
|
+
${configContent}`);
|
|
50
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { AppSDKSupportedFrameworkEnum, AppSDKSupportedTestingFrameworkEnum, AppSDKSupportedLanguageEnum, AppSDKSupportedPlatformEnum } from "./index.js";
|
|
3
|
+
export declare const APP_DEVICE_CONFIGS: {
|
|
4
|
+
android: {
|
|
5
|
+
deviceName: string;
|
|
6
|
+
platformVersion: string;
|
|
7
|
+
}[];
|
|
8
|
+
ios: {
|
|
9
|
+
deviceName: string;
|
|
10
|
+
platformVersion: string;
|
|
11
|
+
}[];
|
|
12
|
+
};
|
|
13
|
+
export declare const STEP_DELIMITER = "---STEP---";
|
|
14
|
+
export declare const DEFAULT_APP_PATH = "bs://sample.app";
|
|
15
|
+
export declare const SETUP_APP_AUTOMATE_DESCRIPTION = "Set up BrowserStack App Automate SDK integration for Appium-based mobile app testing. ONLY for Appium based framework . This tool configures SDK for various languages with appium. For pre-built Espresso or XCUITest test suites, use 'runAppTestsOnBrowserStack' instead.";
|
|
16
|
+
export declare const SETUP_APP_AUTOMATE_SCHEMA: {
|
|
17
|
+
detectedFramework: z.ZodNativeEnum<typeof AppSDKSupportedFrameworkEnum>;
|
|
18
|
+
detectedTestingFramework: z.ZodNativeEnum<typeof AppSDKSupportedTestingFrameworkEnum>;
|
|
19
|
+
detectedLanguage: z.ZodNativeEnum<typeof AppSDKSupportedLanguageEnum>;
|
|
20
|
+
desiredPlatforms: z.ZodArray<z.ZodNativeEnum<typeof AppSDKSupportedPlatformEnum>, "many">;
|
|
21
|
+
appPath: z.ZodString;
|
|
22
|
+
project: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
23
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { AppSDKSupportedFrameworkEnum, AppSDKSupportedTestingFrameworkEnum, AppSDKSupportedLanguageEnum, AppSDKSupportedPlatformEnum, } from "./index.js";
|
|
3
|
+
// App Automate specific device configurations
|
|
4
|
+
export const APP_DEVICE_CONFIGS = {
|
|
5
|
+
android: [
|
|
6
|
+
{ deviceName: "Samsung Galaxy S22 Ultra", platformVersion: "12.0" },
|
|
7
|
+
{ deviceName: "Google Pixel 7 Pro", platformVersion: "13.0" },
|
|
8
|
+
{ deviceName: "OnePlus 9", platformVersion: "11.0" },
|
|
9
|
+
],
|
|
10
|
+
ios: [
|
|
11
|
+
{ deviceName: "iPhone 14", platformVersion: "16" },
|
|
12
|
+
{ deviceName: "iPhone 13", platformVersion: "15" },
|
|
13
|
+
{ deviceName: "iPad Air 4", platformVersion: "14" },
|
|
14
|
+
],
|
|
15
|
+
};
|
|
16
|
+
// Step delimiter for parsing instructions
|
|
17
|
+
export const STEP_DELIMITER = "---STEP---";
|
|
18
|
+
// Default app path for examples
|
|
19
|
+
export const DEFAULT_APP_PATH = "bs://sample.app";
|
|
20
|
+
// Tool description and schema for setupBrowserStackAppAutomateTests
|
|
21
|
+
export const SETUP_APP_AUTOMATE_DESCRIPTION = "Set up BrowserStack App Automate SDK integration for Appium-based mobile app testing. ONLY for Appium based framework . This tool configures SDK for various languages with appium. For pre-built Espresso or XCUITest test suites, use 'runAppTestsOnBrowserStack' instead.";
|
|
22
|
+
export const SETUP_APP_AUTOMATE_SCHEMA = {
|
|
23
|
+
detectedFramework: z
|
|
24
|
+
.nativeEnum(AppSDKSupportedFrameworkEnum)
|
|
25
|
+
.describe("The mobile automation framework configured in the project. Example: 'appium'"),
|
|
26
|
+
detectedTestingFramework: z
|
|
27
|
+
.nativeEnum(AppSDKSupportedTestingFrameworkEnum)
|
|
28
|
+
.describe("The testing framework used in the project. Be precise with framework selection Example: 'testng', 'behave', 'pytest', 'robot'"),
|
|
29
|
+
detectedLanguage: z
|
|
30
|
+
.nativeEnum(AppSDKSupportedLanguageEnum)
|
|
31
|
+
.describe("The programming language used in the project. Supports Java and C#. Example: 'java', 'csharp'"),
|
|
32
|
+
desiredPlatforms: z
|
|
33
|
+
.array(z.nativeEnum(AppSDKSupportedPlatformEnum))
|
|
34
|
+
.describe("The mobile platforms the user wants to test on. Always ask this to the user, do not try to infer this. Example: ['android', 'ios']"),
|
|
35
|
+
appPath: z
|
|
36
|
+
.string()
|
|
37
|
+
.describe("Path to the mobile app file (.apk for Android, .ipa for iOS). Can be a local file path or a BrowserStack app URL (bs://)"),
|
|
38
|
+
project: z
|
|
39
|
+
.string()
|
|
40
|
+
.optional()
|
|
41
|
+
.default("BStack-AppAutomate-Suite")
|
|
42
|
+
.describe("Project name for organizing test runs on BrowserStack."),
|
|
43
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
export declare function formatFinalAppInstructions(formattedInstructions: string): CallToolResult;
|
|
3
|
+
export declare function createStep(title: string, content: string): string;
|
|
4
|
+
export declare function combineInstructions(...instructionParts: string[]): string;
|
|
5
|
+
export declare function formatEnvCommands(username: string, accessKey: string, isWindows: boolean): string;
|
|
6
|
+
export declare function createEnvStep(username: string, accessKey: string, isWindows: boolean, platformLabel: string, title?: string): string;
|
|
7
|
+
export declare function formatMultiLineCommand(command: string, isWindows?: boolean): string;
|
|
8
|
+
export declare function formatAppInstructionsWithNumbers(instructions: string): string;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { STEP_DELIMITER } from "./constants.js";
|
|
2
|
+
export function formatFinalAppInstructions(formattedInstructions) {
|
|
3
|
+
const fullInstructions = `
|
|
4
|
+
⚠️ IMPORTANT: DO NOT SKIP ANY STEP
|
|
5
|
+
All the setup steps described in this file MUST be executed regardless of any existing configuration or setup.
|
|
6
|
+
This ensures proper BrowserStack App Automate SDK setup.
|
|
7
|
+
Each step is compulsory and sequence needs to be maintained.
|
|
8
|
+
|
|
9
|
+
${formattedInstructions}`;
|
|
10
|
+
return {
|
|
11
|
+
content: [
|
|
12
|
+
{
|
|
13
|
+
type: "text",
|
|
14
|
+
text: fullInstructions,
|
|
15
|
+
isError: false,
|
|
16
|
+
},
|
|
17
|
+
],
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export function createStep(title, content) {
|
|
21
|
+
return `${STEP_DELIMITER}
|
|
22
|
+
${title}
|
|
23
|
+
|
|
24
|
+
${content}`;
|
|
25
|
+
}
|
|
26
|
+
export function combineInstructions(...instructionParts) {
|
|
27
|
+
return instructionParts.filter(Boolean).join("\n\n");
|
|
28
|
+
}
|
|
29
|
+
export function formatEnvCommands(username, accessKey, isWindows) {
|
|
30
|
+
if (isWindows) {
|
|
31
|
+
return `\`\`\`cmd
|
|
32
|
+
setx BROWSERSTACK_USERNAME "${username}"
|
|
33
|
+
setx BROWSERSTACK_ACCESS_KEY "${accessKey}"
|
|
34
|
+
\`\`\``;
|
|
35
|
+
}
|
|
36
|
+
return `\`\`\`bash
|
|
37
|
+
export BROWSERSTACK_USERNAME=${username}
|
|
38
|
+
export BROWSERSTACK_ACCESS_KEY=${accessKey}
|
|
39
|
+
\`\`\``;
|
|
40
|
+
}
|
|
41
|
+
export function createEnvStep(username, accessKey, isWindows, platformLabel, title = "Set BrowserStack credentials as environment variables:") {
|
|
42
|
+
return createStep(title, `**${platformLabel}:**
|
|
43
|
+
${formatEnvCommands(username, accessKey, isWindows)}`);
|
|
44
|
+
}
|
|
45
|
+
export function formatMultiLineCommand(command, isWindows = process.platform === "win32") {
|
|
46
|
+
if (isWindows) {
|
|
47
|
+
// For Windows, keep commands on single line
|
|
48
|
+
return command.replace(/\s*\\\s*\n\s*/g, " ");
|
|
49
|
+
}
|
|
50
|
+
return command;
|
|
51
|
+
}
|
|
52
|
+
export function formatAppInstructionsWithNumbers(instructions) {
|
|
53
|
+
const steps = instructions
|
|
54
|
+
.split(STEP_DELIMITER)
|
|
55
|
+
.filter((step) => step.trim());
|
|
56
|
+
return steps
|
|
57
|
+
.map((step, index) => `**Step ${index + 1}:**\n${step.trim()}`)
|
|
58
|
+
.join("\n\n");
|
|
59
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getBrowserStackAuth } from "../../../lib/get-auth.js";
|
|
3
|
+
import { getAppUploadInstruction, validateSupportforAppAutomate, } from "./utils.js";
|
|
4
|
+
import { getAppSDKPrefixCommand, generateAppBrowserStackYMLInstructions, } from "./index.js";
|
|
5
|
+
import { formatAppInstructionsWithNumbers, getAppInstructionsForProjectConfiguration, SETUP_APP_AUTOMATE_SCHEMA, } from "./index.js";
|
|
6
|
+
export async function setupAppAutomateHandler(rawInput, config) {
|
|
7
|
+
const input = z.object(SETUP_APP_AUTOMATE_SCHEMA).parse(rawInput);
|
|
8
|
+
const auth = getBrowserStackAuth(config);
|
|
9
|
+
const [username, accessKey] = auth.split(":");
|
|
10
|
+
const instructions = [];
|
|
11
|
+
// Use variables for all major input properties
|
|
12
|
+
const testingFramework = input.detectedTestingFramework;
|
|
13
|
+
const language = input.detectedLanguage;
|
|
14
|
+
const platforms = input.desiredPlatforms ?? ["android"];
|
|
15
|
+
const appPath = input.appPath;
|
|
16
|
+
const framework = input.detectedFramework;
|
|
17
|
+
//Validating if supported framework or not
|
|
18
|
+
validateSupportforAppAutomate(framework, language, testingFramework);
|
|
19
|
+
// Step 1: Generate SDK setup command
|
|
20
|
+
const sdkCommand = getAppSDKPrefixCommand(language, testingFramework, username, accessKey, appPath);
|
|
21
|
+
if (sdkCommand) {
|
|
22
|
+
instructions.push({ content: sdkCommand, type: "setup" });
|
|
23
|
+
}
|
|
24
|
+
// Step 2: Generate browserstack.yml configuration
|
|
25
|
+
const configInstructions = generateAppBrowserStackYMLInstructions(platforms, username, accessKey, appPath, testingFramework);
|
|
26
|
+
if (configInstructions) {
|
|
27
|
+
instructions.push({ content: configInstructions, type: "config" });
|
|
28
|
+
}
|
|
29
|
+
// Step 3: Generate app upload instruction
|
|
30
|
+
const appUploadInstruction = await getAppUploadInstruction(appPath, username, accessKey, testingFramework);
|
|
31
|
+
if (appUploadInstruction) {
|
|
32
|
+
instructions.push({ content: appUploadInstruction, type: "setup" });
|
|
33
|
+
}
|
|
34
|
+
// Step 4: Generate project configuration and run instructions
|
|
35
|
+
const projectInstructions = getAppInstructionsForProjectConfiguration(framework, testingFramework, language);
|
|
36
|
+
if (projectInstructions) {
|
|
37
|
+
instructions.push({ content: projectInstructions, type: "run" });
|
|
38
|
+
}
|
|
39
|
+
const combinedInstructions = instructions
|
|
40
|
+
.map((instruction) => instruction.content)
|
|
41
|
+
.join("\n\n");
|
|
42
|
+
return {
|
|
43
|
+
content: [
|
|
44
|
+
{
|
|
45
|
+
type: "text",
|
|
46
|
+
text: formatAppInstructionsWithNumbers(combinedInstructions),
|
|
47
|
+
isError: false,
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
isError: false,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { getAppSDKPrefixCommand, getAppInstructionsForProjectConfiguration, } from "./instructions.js";
|
|
2
|
+
export { generateAppBrowserStackYMLInstructions } from "./config-generator.js";
|
|
3
|
+
export * from "./types.js";
|
|
4
|
+
export * from "./constants.js";
|
|
5
|
+
export * from "./utils.js";
|
|
6
|
+
export * from "./instructions.js";
|
|
7
|
+
export * from "./formatter.js";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Barrel exports for App BrowserStack module
|
|
2
|
+
export { getAppSDKPrefixCommand, getAppInstructionsForProjectConfiguration, } from "./instructions.js";
|
|
3
|
+
export { generateAppBrowserStackYMLInstructions } from "./config-generator.js";
|
|
4
|
+
export * from "./types.js";
|
|
5
|
+
export * from "./constants.js";
|
|
6
|
+
export * from "./utils.js";
|
|
7
|
+
export * from "./instructions.js";
|
|
8
|
+
export * from "./formatter.js";
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { AppSDKSupportedLanguage, AppSDKSupportedTestingFramework } from "./index.js";
|
|
2
|
+
export declare function getAppInstructionsForProjectConfiguration(framework: string, testingFramework: AppSDKSupportedTestingFramework, language: AppSDKSupportedLanguage): string;
|
|
3
|
+
export declare function getAppSDKPrefixCommand(language: AppSDKSupportedLanguage, testingFramework: string, username: string, accessKey: string, appPath?: string): string;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Language-specific instruction imports
|
|
2
|
+
import { getJavaAppInstructions } from "./languages/java.js";
|
|
3
|
+
import { getCSharpAppInstructions } from "./languages/csharp.js";
|
|
4
|
+
import { getNodejsAppInstructions } from "./languages/nodejs.js";
|
|
5
|
+
import { getPythonAppInstructions } from "./languages/python.js";
|
|
6
|
+
import { getRubyAppInstructions } from "./languages/ruby.js";
|
|
7
|
+
// Language-specific command imports
|
|
8
|
+
import { getCSharpSDKCommand } from "./languages/csharp.js";
|
|
9
|
+
import { getJavaSDKCommand } from "./languages/java.js";
|
|
10
|
+
import { getNodejsSDKCommand } from "./languages/nodejs.js";
|
|
11
|
+
import { getPythonSDKCommand } from "./languages/python.js";
|
|
12
|
+
import { getRubySDKCommand } from "./languages/ruby.js";
|
|
13
|
+
export function getAppInstructionsForProjectConfiguration(framework, testingFramework, language) {
|
|
14
|
+
if (!framework || !testingFramework || !language) {
|
|
15
|
+
return "";
|
|
16
|
+
}
|
|
17
|
+
switch (language) {
|
|
18
|
+
case "java":
|
|
19
|
+
return getJavaAppInstructions();
|
|
20
|
+
case "nodejs":
|
|
21
|
+
return getNodejsAppInstructions(testingFramework);
|
|
22
|
+
case "python":
|
|
23
|
+
return getPythonAppInstructions(testingFramework);
|
|
24
|
+
case "ruby":
|
|
25
|
+
return getRubyAppInstructions();
|
|
26
|
+
case "csharp":
|
|
27
|
+
return getCSharpAppInstructions();
|
|
28
|
+
default:
|
|
29
|
+
return "";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function getAppSDKPrefixCommand(language, testingFramework, username, accessKey, appPath) {
|
|
33
|
+
switch (language) {
|
|
34
|
+
case "csharp":
|
|
35
|
+
return getCSharpSDKCommand(username, accessKey);
|
|
36
|
+
case "java":
|
|
37
|
+
return getJavaSDKCommand(testingFramework, username, accessKey, appPath);
|
|
38
|
+
case "nodejs":
|
|
39
|
+
return getNodejsSDKCommand(testingFramework, username, accessKey);
|
|
40
|
+
case "python":
|
|
41
|
+
return getPythonSDKCommand(testingFramework, username, accessKey);
|
|
42
|
+
case "ruby":
|
|
43
|
+
return getRubySDKCommand(testingFramework, username, accessKey);
|
|
44
|
+
default:
|
|
45
|
+
return "";
|
|
46
|
+
}
|
|
47
|
+
}
|