@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
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { AppSDKSupportedTestingFramework } from "./index.js";
|
|
2
|
+
import { SUPPORTED_CONFIGURATIONS } from "./types.js";
|
|
3
|
+
export declare function isBrowserStackAppUrl(appPath: string): boolean;
|
|
4
|
+
export declare function generateBuildName(baseName?: string): string;
|
|
5
|
+
export declare function createError(message: string, context?: Record<string, any>): Error;
|
|
6
|
+
export declare const PLATFORM_UTILS: {
|
|
7
|
+
isWindows: boolean;
|
|
8
|
+
isMac: boolean;
|
|
9
|
+
isAppleSilicon: boolean;
|
|
10
|
+
getPlatformLabel: () => "Windows" | "macOS";
|
|
11
|
+
};
|
|
12
|
+
export declare function getAppUploadInstruction(appPath: string, username: string, accessKey: string, detectedTestingFramework: AppSDKSupportedTestingFramework): Promise<string>;
|
|
13
|
+
export type SupportedFramework = keyof typeof SUPPORTED_CONFIGURATIONS;
|
|
14
|
+
type SupportedLanguage = keyof (typeof SUPPORTED_CONFIGURATIONS)[SupportedFramework];
|
|
15
|
+
type SupportedTestingFramework = string;
|
|
16
|
+
export declare function validateSupportforAppAutomate(framework: SupportedFramework, language: SupportedLanguage, testingFramework: SupportedTestingFramework): void;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { uploadApp } from "../native-execution/appautomate.js";
|
|
2
|
+
import { AppSDKSupportedTestingFrameworkEnum, createStep, } from "./index.js";
|
|
3
|
+
import { SUPPORTED_CONFIGURATIONS } from "./types.js";
|
|
4
|
+
export function isBrowserStackAppUrl(appPath) {
|
|
5
|
+
return appPath.startsWith("bs://");
|
|
6
|
+
}
|
|
7
|
+
export function generateBuildName(baseName = "app-automate") {
|
|
8
|
+
const timestamp = new Date().toISOString().slice(0, 19).replace(/[:-]/g, "");
|
|
9
|
+
return `${baseName}-${timestamp}`;
|
|
10
|
+
}
|
|
11
|
+
export function createError(message, context) {
|
|
12
|
+
const error = new Error(message);
|
|
13
|
+
if (context) {
|
|
14
|
+
error.context = context;
|
|
15
|
+
}
|
|
16
|
+
return error;
|
|
17
|
+
}
|
|
18
|
+
// Platform utilities for cross-platform support
|
|
19
|
+
export const PLATFORM_UTILS = {
|
|
20
|
+
isWindows: process.platform === "win32",
|
|
21
|
+
isMac: process.platform === "darwin",
|
|
22
|
+
isAppleSilicon: process.platform === "darwin" && process.arch === "arm64",
|
|
23
|
+
getPlatformLabel: () => {
|
|
24
|
+
switch (process.platform) {
|
|
25
|
+
case "win32":
|
|
26
|
+
return "Windows";
|
|
27
|
+
case "darwin":
|
|
28
|
+
return "macOS";
|
|
29
|
+
default:
|
|
30
|
+
return "macOS";
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
export async function getAppUploadInstruction(appPath, username, accessKey, detectedTestingFramework) {
|
|
35
|
+
if (detectedTestingFramework ===
|
|
36
|
+
AppSDKSupportedTestingFrameworkEnum.nightwatch ||
|
|
37
|
+
detectedTestingFramework ===
|
|
38
|
+
AppSDKSupportedTestingFrameworkEnum.webdriverio ||
|
|
39
|
+
detectedTestingFramework ===
|
|
40
|
+
AppSDKSupportedTestingFrameworkEnum.cucumberRuby) {
|
|
41
|
+
const app_url = await uploadApp(appPath, username, accessKey);
|
|
42
|
+
if (app_url) {
|
|
43
|
+
return createStep("Updating app_path with app_url", `Replace the value of app_path in your configuration with: ${app_url}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return "";
|
|
47
|
+
}
|
|
48
|
+
export function validateSupportforAppAutomate(framework, language, testingFramework) {
|
|
49
|
+
const frameworks = Object.keys(SUPPORTED_CONFIGURATIONS);
|
|
50
|
+
if (!SUPPORTED_CONFIGURATIONS[framework]) {
|
|
51
|
+
throw new Error(`Unsupported framework '${framework}'. Supported frameworks: ${frameworks.join(", ")}`);
|
|
52
|
+
}
|
|
53
|
+
const languages = Object.keys(SUPPORTED_CONFIGURATIONS[framework]);
|
|
54
|
+
if (!SUPPORTED_CONFIGURATIONS[framework][language]) {
|
|
55
|
+
throw new Error(`Unsupported language '${language}' for framework '${framework}'. Supported languages: ${languages.join(", ")}`);
|
|
56
|
+
}
|
|
57
|
+
const testingFrameworks = SUPPORTED_CONFIGURATIONS[framework][language];
|
|
58
|
+
if (testingFrameworks.length === 0) {
|
|
59
|
+
throw new Error(`No testing frameworks are supported for language '${language}' and framework '${framework}'.`);
|
|
60
|
+
}
|
|
61
|
+
if (!testingFrameworks.includes(testingFramework)) {
|
|
62
|
+
throw new Error(`Unsupported testing framework '${testingFramework}' for language '${language}' and framework '${framework}'. Supported testing frameworks: ${testingFrameworks.join(", ")}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import FormData from "form-data";
|
|
3
|
-
import { apiClient } from "
|
|
4
|
-
import { customFuzzySearch } from "
|
|
3
|
+
import { apiClient } from "../../../lib/apiClient.js";
|
|
4
|
+
import { customFuzzySearch } from "../../../lib/fuzzy.js";
|
|
5
5
|
/**
|
|
6
6
|
* Finds devices that exactly match the provided display name.
|
|
7
7
|
* Uses fuzzy search first, and then filters for exact case-insensitive match.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { AppTestPlatform } from "./types.js";
|
|
3
|
+
export declare const RUN_APP_AUTOMATE_DESCRIPTION = "Execute pre-built native mobile test suites (Espresso for Android, XCUITest for iOS) by direct upload to BrowserStack. ONLY for compiled .apk/.ipa test files. This is NOT for SDK integration or Appium tests. For Appium-based testing with SDK setup, use 'setupBrowserStackAppAutomateTests' instead.";
|
|
4
|
+
export declare const RUN_APP_AUTOMATE_SCHEMA: {
|
|
5
|
+
appPath: z.ZodString;
|
|
6
|
+
testSuitePath: z.ZodString;
|
|
7
|
+
devices: z.ZodArray<z.ZodString, "many">;
|
|
8
|
+
project: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
9
|
+
detectedAutomationFramework: z.ZodNativeEnum<typeof AppTestPlatform>;
|
|
10
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { AppTestPlatform } from "./types.js";
|
|
3
|
+
export const RUN_APP_AUTOMATE_DESCRIPTION = `Execute pre-built native mobile test suites (Espresso for Android, XCUITest for iOS) by direct upload to BrowserStack. ONLY for compiled .apk/.ipa test files. This is NOT for SDK integration or Appium tests. For Appium-based testing with SDK setup, use 'setupBrowserStackAppAutomateTests' instead.`;
|
|
4
|
+
export const RUN_APP_AUTOMATE_SCHEMA = {
|
|
5
|
+
appPath: z
|
|
6
|
+
.string()
|
|
7
|
+
.describe("Path to your application file:\n" +
|
|
8
|
+
"If in development IDE directory:\n" +
|
|
9
|
+
"• For Android: 'gradle assembleDebug'\n" +
|
|
10
|
+
"• For iOS:\n" +
|
|
11
|
+
" xcodebuild clean -scheme YOUR_SCHEME && \\\n" +
|
|
12
|
+
" xcodebuild archive -scheme YOUR_SCHEME -configuration Release -archivePath build/app.xcarchive && \\\n" +
|
|
13
|
+
" xcodebuild -exportArchive -archivePath build/app.xcarchive -exportPath build/ipa -exportOptionsPlist exportOptions.plist\n\n" +
|
|
14
|
+
"If in other directory, provide existing app path"),
|
|
15
|
+
testSuitePath: z
|
|
16
|
+
.string()
|
|
17
|
+
.describe("Path to your test suite file:\n" +
|
|
18
|
+
"If in development IDE directory:\n" +
|
|
19
|
+
"• For Android: 'gradle assembleAndroidTest'\n" +
|
|
20
|
+
"• For iOS:\n" +
|
|
21
|
+
" xcodebuild test-without-building -scheme YOUR_SCHEME -destination 'generic/platform=iOS' && \\\n" +
|
|
22
|
+
" cd ~/Library/Developer/Xcode/DerivedData/*/Build/Products/Debug-iphonesimulator/ && \\\n" +
|
|
23
|
+
" zip -r Tests.zip *.xctestrun *-Runner.app\n\n" +
|
|
24
|
+
"If in other directory, provide existing test file path"),
|
|
25
|
+
devices: z
|
|
26
|
+
.array(z.string())
|
|
27
|
+
.describe("List of devices to run the test on, e.g., ['Samsung Galaxy S20-10.0', 'iPhone 12 Pro-16.0']."),
|
|
28
|
+
project: z
|
|
29
|
+
.string()
|
|
30
|
+
.optional()
|
|
31
|
+
.default("BStack-AppAutomate-Suite")
|
|
32
|
+
.describe("Project name for organizing test runs on BrowserStack."),
|
|
33
|
+
detectedAutomationFramework: z
|
|
34
|
+
.nativeEnum(AppTestPlatform)
|
|
35
|
+
.describe("The automation framework used in the project, such as 'espresso' (Android) or 'xcuitest' (iOS)."),
|
|
36
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare enum AppTestPlatform {
|
|
2
|
+
ESPRESSO = "espresso",
|
|
3
|
+
XCUITEST = "xcuitest"
|
|
4
|
+
}
|
|
5
|
+
export interface Device {
|
|
6
|
+
device: string;
|
|
7
|
+
display_name: string;
|
|
8
|
+
os_version: string;
|
|
9
|
+
real_mobile: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface PlatformDevices {
|
|
12
|
+
os: string;
|
|
13
|
+
os_display_name: string;
|
|
14
|
+
devices: Device[];
|
|
15
|
+
}
|
|
16
|
+
export declare enum Platform {
|
|
17
|
+
ANDROID = "android",
|
|
18
|
+
IOS = "ios"
|
|
19
|
+
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
export var AppTestPlatform;
|
|
2
2
|
(function (AppTestPlatform) {
|
|
3
3
|
AppTestPlatform["ESPRESSO"] = "espresso";
|
|
4
|
-
AppTestPlatform["APPIUM"] = "appium";
|
|
5
4
|
AppTestPlatform["XCUITEST"] = "xcuitest";
|
|
6
5
|
})(AppTestPlatform || (AppTestPlatform = {}));
|
|
6
|
+
export var Platform;
|
|
7
|
+
(function (Platform) {
|
|
8
|
+
Platform["ANDROID"] = "android";
|
|
9
|
+
Platform["IOS"] = "ios";
|
|
10
|
+
})(Platform || (Platform = {}));
|
|
@@ -4,14 +4,13 @@ import { getBrowserStackAuth } from "../lib/get-auth.js";
|
|
|
4
4
|
import { trackMCP } from "../lib/instrumentation.js";
|
|
5
5
|
import { maybeCompressBase64 } from "../lib/utils.js";
|
|
6
6
|
import { remote } from "webdriverio";
|
|
7
|
-
import { AppTestPlatform } from "./appautomate-utils/types.js";
|
|
7
|
+
import { AppTestPlatform } from "./appautomate-utils/native-execution/types.js";
|
|
8
|
+
import { setupAppAutomateHandler } from "./appautomate-utils/appium-sdk/handler.js";
|
|
9
|
+
import { SETUP_APP_AUTOMATE_DESCRIPTION, SETUP_APP_AUTOMATE_SCHEMA, } from "./appautomate-utils/appium-sdk/constants.js";
|
|
10
|
+
import { Platform, } from "./appautomate-utils/native-execution/types.js";
|
|
8
11
|
import { getDevicesAndBrowsers, BrowserStackProducts, } from "../lib/device-cache.js";
|
|
9
|
-
import { findMatchingDevice, getDeviceVersions, resolveVersion, validateArgs, uploadApp, uploadEspressoApp, uploadEspressoTestSuite, triggerEspressoBuild, uploadXcuiApp, uploadXcuiTestSuite, triggerXcuiBuild, } from "./appautomate-utils/appautomate.js";
|
|
10
|
-
|
|
11
|
-
(function (Platform) {
|
|
12
|
-
Platform["ANDROID"] = "android";
|
|
13
|
-
Platform["IOS"] = "ios";
|
|
14
|
-
})(Platform || (Platform = {}));
|
|
12
|
+
import { findMatchingDevice, getDeviceVersions, resolveVersion, validateArgs, uploadApp, uploadEspressoApp, uploadEspressoTestSuite, triggerEspressoBuild, uploadXcuiApp, uploadXcuiTestSuite, triggerXcuiBuild, } from "./appautomate-utils/native-execution/appautomate.js";
|
|
13
|
+
import { RUN_APP_AUTOMATE_DESCRIPTION, RUN_APP_AUTOMATE_SCHEMA, } from "./appautomate-utils/native-execution/constants.js";
|
|
15
14
|
/**
|
|
16
15
|
* Launches an app on a selected BrowserStack device and takes a screenshot.
|
|
17
16
|
*/
|
|
@@ -214,39 +213,7 @@ export default function addAppAutomationTools(server, config) {
|
|
|
214
213
|
};
|
|
215
214
|
}
|
|
216
215
|
});
|
|
217
|
-
tools.runAppTestsOnBrowserStack = server.tool("runAppTestsOnBrowserStack",
|
|
218
|
-
appPath: z
|
|
219
|
-
.string()
|
|
220
|
-
.describe("Path to your application file:\n" +
|
|
221
|
-
"If in development IDE directory:\n" +
|
|
222
|
-
"• For Android: 'gradle assembleDebug'\n" +
|
|
223
|
-
"• For iOS:\n" +
|
|
224
|
-
" xcodebuild clean -scheme YOUR_SCHEME && \\\n" +
|
|
225
|
-
" xcodebuild archive -scheme YOUR_SCHEME -configuration Release -archivePath build/app.xcarchive && \\\n" +
|
|
226
|
-
" xcodebuild -exportArchive -archivePath build/app.xcarchive -exportPath build/ipa -exportOptionsPlist exportOptions.plist\n\n" +
|
|
227
|
-
"If in other directory, provide existing app path"),
|
|
228
|
-
testSuitePath: z
|
|
229
|
-
.string()
|
|
230
|
-
.describe("Path to your test suite file:\n" +
|
|
231
|
-
"If in development IDE directory:\n" +
|
|
232
|
-
"• For Android: 'gradle assembleAndroidTest'\n" +
|
|
233
|
-
"• For iOS:\n" +
|
|
234
|
-
" xcodebuild test-without-building -scheme YOUR_SCHEME -destination 'generic/platform=iOS' && \\\n" +
|
|
235
|
-
" cd ~/Library/Developer/Xcode/DerivedData/*/Build/Products/Debug-iphonesimulator/ && \\\n" +
|
|
236
|
-
" zip -r Tests.zip *.xctestrun *-Runner.app\n\n" +
|
|
237
|
-
"If in other directory, provide existing test file path"),
|
|
238
|
-
devices: z
|
|
239
|
-
.array(z.string())
|
|
240
|
-
.describe("List of devices to run the test on, e.g., ['Samsung Galaxy S20-10.0', 'iPhone 12 Pro-16.0']."),
|
|
241
|
-
project: z
|
|
242
|
-
.string()
|
|
243
|
-
.optional()
|
|
244
|
-
.default("BStack-AppAutomate-Suite")
|
|
245
|
-
.describe("Project name for organizing test runs on BrowserStack."),
|
|
246
|
-
detectedAutomationFramework: z
|
|
247
|
-
.string()
|
|
248
|
-
.describe("The automation framework used in the project, such as 'espresso' (Android) or 'xcuitest' (iOS)."),
|
|
249
|
-
}, async (args) => {
|
|
216
|
+
tools.runAppTestsOnBrowserStack = server.tool("runAppTestsOnBrowserStack", RUN_APP_AUTOMATE_DESCRIPTION, RUN_APP_AUTOMATE_SCHEMA, async (args) => {
|
|
250
217
|
try {
|
|
251
218
|
trackMCP("runAppTestsOnBrowserStack", server.server.getClientVersion(), undefined, config);
|
|
252
219
|
return await runAppTestsOnBrowserStack(args, config);
|
|
@@ -265,5 +232,23 @@ export default function addAppAutomationTools(server, config) {
|
|
|
265
232
|
};
|
|
266
233
|
}
|
|
267
234
|
});
|
|
235
|
+
tools.setupBrowserStackAppAutomateTests = server.tool("setupBrowserStackAppAutomateTests", SETUP_APP_AUTOMATE_DESCRIPTION, SETUP_APP_AUTOMATE_SCHEMA, async (args) => {
|
|
236
|
+
try {
|
|
237
|
+
return await setupAppAutomateHandler(args, config);
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
const error_message = error instanceof Error ? error.message : "Unknown error";
|
|
241
|
+
return {
|
|
242
|
+
content: [
|
|
243
|
+
{
|
|
244
|
+
type: "text",
|
|
245
|
+
text: `Failed to bootstrap project with BrowserStack App Automate SDK. Error: ${error_message}. Please open an issue on GitHub if the problem persists`,
|
|
246
|
+
isError: true,
|
|
247
|
+
},
|
|
248
|
+
],
|
|
249
|
+
isError: true,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
});
|
|
268
253
|
return tools;
|
|
269
254
|
}
|
|
@@ -1,17 +1,4 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
-
import { SDKSupportedBrowserAutomationFramework, SDKSupportedLanguage, SDKSupportedTestingFramework } from "./sdk-utils/types.js";
|
|
4
2
|
import { BrowserStackConfig } from "../lib/types.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* This tool gives instructions to setup a browserstack.yml file in the project root and installs the necessary dependencies.
|
|
8
|
-
*/
|
|
9
|
-
export declare function bootstrapProjectWithSDK({ detectedBrowserAutomationFramework, detectedTestingFramework, detectedLanguage, desiredPlatforms, enablePercy, config, }: {
|
|
10
|
-
detectedBrowserAutomationFramework: SDKSupportedBrowserAutomationFramework;
|
|
11
|
-
detectedTestingFramework: SDKSupportedTestingFramework;
|
|
12
|
-
detectedLanguage: SDKSupportedLanguage;
|
|
13
|
-
desiredPlatforms: string[];
|
|
14
|
-
enablePercy: boolean;
|
|
15
|
-
config: BrowserStackConfig;
|
|
16
|
-
}): Promise<CallToolResult>;
|
|
17
|
-
export default function addSDKTools(server: McpServer, config: BrowserStackConfig): Record<string, any>;
|
|
3
|
+
export declare function registerRunBrowserStackTestsTool(server: McpServer, config: BrowserStackConfig): Record<string, any>;
|
|
4
|
+
export default registerRunBrowserStackTestsTool;
|
package/dist/tools/bstack-sdk.js
CHANGED
|
@@ -1,128 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RunTestsOnBrowserStackParamsShape } from "./sdk-utils/common/schema.js";
|
|
2
|
+
import { runTestsOnBrowserStackHandler } from "./sdk-utils/handler.js";
|
|
3
|
+
import { RUN_ON_BROWSERSTACK_DESCRIPTION } from "./sdk-utils/common/constants.js";
|
|
4
|
+
import { handleMCPError } from "../lib/utils.js";
|
|
2
5
|
import { trackMCP } from "../lib/instrumentation.js";
|
|
3
|
-
|
|
4
|
-
import { SDKSupportedLanguageEnum, SDKSupportedBrowserAutomationFrameworkEnum, SDKSupportedTestingFrameworkEnum, } from "./sdk-utils/types.js";
|
|
5
|
-
import { generateBrowserStackYMLInstructions, getInstructionsForProjectConfiguration, formatInstructionsWithNumbers, } from "./sdk-utils/instructions.js";
|
|
6
|
-
import { formatPercyInstructions, getPercyInstructions, } from "./sdk-utils/percy/instructions.js";
|
|
7
|
-
import { getBrowserStackAuth } from "../lib/get-auth.js";
|
|
8
|
-
/**
|
|
9
|
-
* BrowserStack SDK hooks into your test framework to seamlessly run tests on BrowserStack.
|
|
10
|
-
* This tool gives instructions to setup a browserstack.yml file in the project root and installs the necessary dependencies.
|
|
11
|
-
*/
|
|
12
|
-
export async function bootstrapProjectWithSDK({ detectedBrowserAutomationFramework, detectedTestingFramework, detectedLanguage, desiredPlatforms, enablePercy, config, }) {
|
|
13
|
-
// Get credentials from config
|
|
14
|
-
const authString = getBrowserStackAuth(config);
|
|
15
|
-
const [username, accessKey] = authString.split(":");
|
|
16
|
-
// Handle frameworks with unique setup instructions that don't use browserstack.yml
|
|
17
|
-
if (detectedBrowserAutomationFramework === "cypress" ||
|
|
18
|
-
detectedTestingFramework === "webdriverio") {
|
|
19
|
-
let combinedInstructions = getInstructionsForProjectConfiguration(detectedBrowserAutomationFramework, detectedTestingFramework, detectedLanguage, username, accessKey);
|
|
20
|
-
if (enablePercy) {
|
|
21
|
-
const percyInstructions = getPercyInstructions(detectedLanguage, detectedBrowserAutomationFramework, detectedTestingFramework);
|
|
22
|
-
if (percyInstructions) {
|
|
23
|
-
combinedInstructions +=
|
|
24
|
-
"\n\n" + formatPercyInstructions(percyInstructions);
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
throw new Error(`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.`);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
// Apply consistent formatting for all configurations
|
|
31
|
-
return formatFinalInstructions(combinedInstructions);
|
|
32
|
-
}
|
|
33
|
-
// Handle default flow using browserstack.yml
|
|
34
|
-
const sdkSetupCommand = getSDKPrefixCommand(detectedLanguage, detectedTestingFramework, username, accessKey);
|
|
35
|
-
const ymlInstructions = generateBrowserStackYMLInstructions(desiredPlatforms, enablePercy);
|
|
36
|
-
const instructionsForProjectConfiguration = getInstructionsForProjectConfiguration(detectedBrowserAutomationFramework, detectedTestingFramework, detectedLanguage, username, accessKey);
|
|
37
|
-
let combinedInstructions = "";
|
|
38
|
-
// Step 1: Add SDK setup command
|
|
39
|
-
if (sdkSetupCommand) {
|
|
40
|
-
combinedInstructions += sdkSetupCommand;
|
|
41
|
-
}
|
|
42
|
-
// Step 2: Add browserstack.yml setup
|
|
43
|
-
if (ymlInstructions) {
|
|
44
|
-
combinedInstructions += "\n\n---STEP---\n" + ymlInstructions;
|
|
45
|
-
}
|
|
46
|
-
// Step 3: Add language/framework-specific setup
|
|
47
|
-
if (instructionsForProjectConfiguration) {
|
|
48
|
-
combinedInstructions += "\n\n" + instructionsForProjectConfiguration;
|
|
49
|
-
}
|
|
50
|
-
// Step 4: Add Percy setup if applicable
|
|
51
|
-
if (enablePercy) {
|
|
52
|
-
const percyInstructions = getPercyInstructions(detectedLanguage, detectedBrowserAutomationFramework, detectedTestingFramework);
|
|
53
|
-
if (percyInstructions) {
|
|
54
|
-
combinedInstructions +=
|
|
55
|
-
"\n\n" + formatPercyInstructions(percyInstructions);
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
58
|
-
throw new Error(`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.`);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
// Apply consistent formatting for all configurations
|
|
62
|
-
return formatFinalInstructions(combinedInstructions);
|
|
63
|
-
}
|
|
64
|
-
// Helper function to apply consistent formatting to all instruction types
|
|
65
|
-
function formatFinalInstructions(combinedInstructions) {
|
|
66
|
-
const fullInstructions = `⚠️ IMPORTANT: DO NOT SKIP ANY STEP
|
|
67
|
-
All the setup steps described in this file MUST be executed regardless of any existing configuration or setup.
|
|
68
|
-
This ensures proper BrowserStack SDK setup.
|
|
69
|
-
|
|
70
|
-
${formatInstructionsWithNumbers(combinedInstructions)}`;
|
|
71
|
-
return {
|
|
72
|
-
content: [
|
|
73
|
-
{
|
|
74
|
-
type: "text",
|
|
75
|
-
text: fullInstructions,
|
|
76
|
-
isError: false,
|
|
77
|
-
},
|
|
78
|
-
],
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
export default function addSDKTools(server, config) {
|
|
6
|
+
export function registerRunBrowserStackTestsTool(server, config) {
|
|
82
7
|
const tools = {};
|
|
83
|
-
tools.setupBrowserStackAutomateTests = server.tool("setupBrowserStackAutomateTests",
|
|
84
|
-
detectedBrowserAutomationFramework: z
|
|
85
|
-
.nativeEnum(SDKSupportedBrowserAutomationFrameworkEnum)
|
|
86
|
-
.describe("The automation framework configured in the project. Example: 'playwright', 'selenium'"),
|
|
87
|
-
detectedTestingFramework: z
|
|
88
|
-
.nativeEnum(SDKSupportedTestingFrameworkEnum)
|
|
89
|
-
.describe("The testing framework used in the project. Be precise with framework selection Example: 'webdriverio', 'jest', 'pytest', 'junit4', 'junit5', 'mocha'"),
|
|
90
|
-
detectedLanguage: z
|
|
91
|
-
.nativeEnum(SDKSupportedLanguageEnum)
|
|
92
|
-
.describe("The programming language used in the project. Example: 'nodejs', 'python', 'java', 'csharp'"),
|
|
93
|
-
desiredPlatforms: z
|
|
94
|
-
.array(z.enum(["windows", "macos", "android", "ios"]))
|
|
95
|
-
.describe("The platforms the user wants to test on. Always ask this to the user, do not try to infer this."),
|
|
96
|
-
enablePercy: z
|
|
97
|
-
.boolean()
|
|
98
|
-
.optional()
|
|
99
|
-
.default(false)
|
|
100
|
-
.describe("Set to true if the user wants to enable Percy for visual testing. Defaults to false."),
|
|
101
|
-
}, async (args) => {
|
|
8
|
+
tools.setupBrowserStackAutomateTests = server.tool("setupBrowserStackAutomateTests", RUN_ON_BROWSERSTACK_DESCRIPTION, RunTestsOnBrowserStackParamsShape, async (args) => {
|
|
102
9
|
try {
|
|
103
|
-
trackMCP("runTestsOnBrowserStack", server.server.getClientVersion(),
|
|
104
|
-
return await
|
|
105
|
-
detectedBrowserAutomationFramework: args.detectedBrowserAutomationFramework,
|
|
106
|
-
detectedTestingFramework: args.detectedTestingFramework,
|
|
107
|
-
detectedLanguage: args.detectedLanguage,
|
|
108
|
-
desiredPlatforms: args.desiredPlatforms,
|
|
109
|
-
enablePercy: args.enablePercy,
|
|
110
|
-
config,
|
|
111
|
-
});
|
|
10
|
+
trackMCP("runTestsOnBrowserStack", server.server.getClientVersion(), config);
|
|
11
|
+
return await runTestsOnBrowserStackHandler(args, config);
|
|
112
12
|
}
|
|
113
13
|
catch (error) {
|
|
114
|
-
|
|
115
|
-
return {
|
|
116
|
-
content: [
|
|
117
|
-
{
|
|
118
|
-
type: "text",
|
|
119
|
-
text: `Failed to bootstrap project with BrowserStack SDK. Error: ${error}. Please open an issue on GitHub if the problem persists`,
|
|
120
|
-
isError: true,
|
|
121
|
-
},
|
|
122
|
-
],
|
|
123
|
-
isError: true,
|
|
124
|
-
};
|
|
14
|
+
return handleMCPError("runTestsOnBrowserStack", server, config, error);
|
|
125
15
|
}
|
|
126
16
|
});
|
|
127
17
|
return tools;
|
|
128
18
|
}
|
|
19
|
+
export default registerRunBrowserStackTestsTool;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import { BrowserStackConfig } from "../lib/types.js";
|
|
4
|
+
export declare function fetchBuildInsightsTool(args: {
|
|
5
|
+
buildId: string;
|
|
6
|
+
}, config: BrowserStackConfig): Promise<CallToolResult>;
|
|
7
|
+
export default function addBuildInsightsTools(server: McpServer, config: BrowserStackConfig): Record<string, any>;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import logger from "../logger.js";
|
|
3
|
+
import { fetchFromBrowserStackAPI, handleMCPError } from "../lib/utils.js";
|
|
4
|
+
import { trackMCP } from "../lib/instrumentation.js";
|
|
5
|
+
// Tool function that fetches build insights from two APIs
|
|
6
|
+
export async function fetchBuildInsightsTool(args, config) {
|
|
7
|
+
try {
|
|
8
|
+
const buildUrl = `https://api-automation.browserstack.com/ext/v1/builds/${args.buildId}`;
|
|
9
|
+
const qualityGateUrl = `https://api-automation.browserstack.com/ext/v1/quality-gates/${args.buildId}`;
|
|
10
|
+
const [buildData, qualityData] = await Promise.all([
|
|
11
|
+
fetchFromBrowserStackAPI(buildUrl, config),
|
|
12
|
+
fetchFromBrowserStackAPI(qualityGateUrl, config),
|
|
13
|
+
]);
|
|
14
|
+
// Select useful fields for users
|
|
15
|
+
const insights = {
|
|
16
|
+
name: buildData.name,
|
|
17
|
+
status: buildData.status,
|
|
18
|
+
duration: buildData.duration,
|
|
19
|
+
user: buildData.user,
|
|
20
|
+
tags: buildData.tags,
|
|
21
|
+
alerts: buildData.alerts,
|
|
22
|
+
status_stats: buildData.status_stats,
|
|
23
|
+
failure_categories: buildData.failure_categories,
|
|
24
|
+
smart_tags: buildData.smart_tags,
|
|
25
|
+
unique_errors: buildData.unique_errors?.overview,
|
|
26
|
+
observability_url: buildData?.observability_url,
|
|
27
|
+
ci_build_url: buildData.ci_info?.build_url,
|
|
28
|
+
quality_gate_result: qualityData.quality_gate_result,
|
|
29
|
+
};
|
|
30
|
+
const qualityProfiles = qualityData.quality_profiles?.map((profile) => ({
|
|
31
|
+
name: profile.name,
|
|
32
|
+
result: profile.result,
|
|
33
|
+
}));
|
|
34
|
+
const qualityProfilesText = qualityProfiles && qualityProfiles.length > 0
|
|
35
|
+
? `Quality Gate Profiles (respond only if explicitly requested): ${JSON.stringify(qualityProfiles, null, 2)}`
|
|
36
|
+
: "No Quality Gate Profiles available.";
|
|
37
|
+
return {
|
|
38
|
+
content: [
|
|
39
|
+
{
|
|
40
|
+
type: "text",
|
|
41
|
+
text: "Build insights:\n" + JSON.stringify(insights, null, 2),
|
|
42
|
+
},
|
|
43
|
+
{ type: "text", text: qualityProfilesText },
|
|
44
|
+
],
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
logger.error("Error fetching build insights", error);
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Registers the fetchBuildInsights tool with the MCP server
|
|
53
|
+
export default function addBuildInsightsTools(server, config) {
|
|
54
|
+
const tools = {};
|
|
55
|
+
tools.fetchBuildInsights = server.tool("fetchBuildInsights", "Fetches insights about a BrowserStack build by combining build details and quality gate results.", {
|
|
56
|
+
buildId: z.string().describe("The build UUID of the BrowserStack build"),
|
|
57
|
+
}, async (args) => {
|
|
58
|
+
try {
|
|
59
|
+
trackMCP("fetchBuildInsights", server.server.getClientVersion(), config);
|
|
60
|
+
return await fetchBuildInsightsTool(args, config);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
return handleMCPError("fetchBuildInsights", server, config, error);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
return tools;
|
|
67
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { listTestFiles } from "./percy-snapshot-utils/detect-test-files.js";
|
|
2
|
+
import { testFilePathsMap } from "../lib/inmemory-store.js";
|
|
3
|
+
import crypto from "crypto";
|
|
4
|
+
export async function addListTestFiles(args) {
|
|
5
|
+
const { dirs, language, framework } = args;
|
|
6
|
+
let testFiles = [];
|
|
7
|
+
if (!dirs || dirs.length === 0) {
|
|
8
|
+
throw new Error("No directories provided to add the test files. Please provide test directories to add percy snapshot commands.");
|
|
9
|
+
}
|
|
10
|
+
for (const dir of dirs) {
|
|
11
|
+
const files = await listTestFiles({
|
|
12
|
+
language,
|
|
13
|
+
framework,
|
|
14
|
+
baseDir: dir,
|
|
15
|
+
});
|
|
16
|
+
testFiles = testFiles.concat(files);
|
|
17
|
+
}
|
|
18
|
+
if (testFiles.length === 0) {
|
|
19
|
+
throw new Error("No test files found");
|
|
20
|
+
}
|
|
21
|
+
// Generate a UUID and store the test files in memory
|
|
22
|
+
const uuid = crypto.randomUUID();
|
|
23
|
+
testFilePathsMap.set(uuid, testFiles);
|
|
24
|
+
return {
|
|
25
|
+
content: [
|
|
26
|
+
{
|
|
27
|
+
type: "text",
|
|
28
|
+
text: `The Test files are stored in memory with id ${uuid} and the total number of tests files found is ${testFiles.length}. You can use this UUID to retrieve the tests file paths later.`,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
type: "text",
|
|
32
|
+
text: `You can now use the tool addPercySnapshotCommands to update the test file with Percy commands for visual testing with the UUID ${uuid}`,
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { BrowserStackConfig } from "../lib/types.js";
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
export declare function registerPercyTools(server: McpServer, config: BrowserStackConfig): Record<string, any>;
|
|
4
|
+
export default registerPercyTools;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { trackMCP } from "../index.js";
|
|
2
|
+
import { fetchPercyChanges } from "./review-agent.js";
|
|
3
|
+
import { addListTestFiles } from "./list-test-files.js";
|
|
4
|
+
import { runPercyScan } from "./run-percy-scan.js";
|
|
5
|
+
import { SetUpPercyParamsShape } from "./sdk-utils/common/schema.js";
|
|
6
|
+
import { updateTestsWithPercyCommands } from "./add-percy-snapshots.js";
|
|
7
|
+
import { approveOrDeclinePercyBuild } from "./review-agent-utils/percy-approve-reject.js";
|
|
8
|
+
import { setUpPercyHandler } from "./sdk-utils/handler.js";
|
|
9
|
+
import { SETUP_PERCY_DESCRIPTION, LIST_TEST_FILES_DESCRIPTION, PERCY_SNAPSHOT_COMMANDS_DESCRIPTION, } from "./sdk-utils/common/constants.js";
|
|
10
|
+
import { ListTestFilesParamsShape, UpdateTestFileWithInstructionsParams, } from "./percy-snapshot-utils/constants.js";
|
|
11
|
+
import { RunPercyScanParamsShape, FetchPercyChangesParamsShape, ManagePercyBuildApprovalParamsShape, } from "./sdk-utils/common/schema.js";
|
|
12
|
+
import { handleMCPError } from "../lib/utils.js";
|
|
13
|
+
export function registerPercyTools(server, config) {
|
|
14
|
+
const tools = {};
|
|
15
|
+
tools.setupPercyVisualTesting = server.tool("setupPercyVisualTesting", SETUP_PERCY_DESCRIPTION, SetUpPercyParamsShape, async (args) => {
|
|
16
|
+
try {
|
|
17
|
+
trackMCP("setupPercyVisualTesting", server.server.getClientVersion(), config);
|
|
18
|
+
return setUpPercyHandler(args, config);
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
return handleMCPError("setupPercyVisualTesting", server, config, error);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
tools.addPercySnapshotCommands = server.tool("addPercySnapshotCommands", PERCY_SNAPSHOT_COMMANDS_DESCRIPTION, UpdateTestFileWithInstructionsParams, async (args) => {
|
|
25
|
+
try {
|
|
26
|
+
trackMCP("addPercySnapshotCommands", server.server.getClientVersion(), config);
|
|
27
|
+
return await updateTestsWithPercyCommands(args);
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
return handleMCPError("addPercySnapshotCommands", server, config, error);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
tools.listTestFiles = server.tool("listTestFiles", LIST_TEST_FILES_DESCRIPTION, ListTestFilesParamsShape, async (args) => {
|
|
34
|
+
try {
|
|
35
|
+
trackMCP("listTestFiles", server.server.getClientVersion(), config);
|
|
36
|
+
return addListTestFiles(args);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
return handleMCPError("listTestFiles", server, config, error);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
tools.runPercyScan = server.tool("runPercyScan", "Run a Percy visual test scan. Example prompts : Run this Percy build/scan. Never run percy scan/build without this tool", RunPercyScanParamsShape, async (args) => {
|
|
43
|
+
try {
|
|
44
|
+
trackMCP("runPercyScan", server.server.getClientVersion(), config);
|
|
45
|
+
return runPercyScan(args, config);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
return handleMCPError("runPercyScan", server, config, error);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
tools.fetchPercyChanges = server.tool("fetchPercyChanges", "Retrieves and summarizes all visual changes detected by Percy AI between the latest and previous builds, helping quickly review what has changed in your project.", FetchPercyChangesParamsShape, async (args) => {
|
|
52
|
+
try {
|
|
53
|
+
trackMCP("fetchPercyChanges", server.server.getClientVersion(), config);
|
|
54
|
+
return await fetchPercyChanges(args, config);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
return handleMCPError("fetchPercyChanges", server, config, error);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
tools.managePercyBuildApproval = server.tool("managePercyBuildApproval", "Approve or reject a Percy build", ManagePercyBuildApprovalParamsShape, async (args) => {
|
|
61
|
+
try {
|
|
62
|
+
trackMCP("managePercyBuildApproval", server.server.getClientVersion(), config);
|
|
63
|
+
return await approveOrDeclinePercyBuild(args, config);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
return handleMCPError("managePercyBuildApproval", server, config, error);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
return tools;
|
|
70
|
+
}
|
|
71
|
+
export default registerPercyTools;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { SDKSupportedLanguage } from "../sdk-utils/common/types.js";
|
|
3
|
+
import { DetectionConfig } from "./types.js";
|
|
4
|
+
export declare const UpdateTestFileWithInstructionsParams: {
|
|
5
|
+
uuid: z.ZodString;
|
|
6
|
+
index: z.ZodNumber;
|
|
7
|
+
};
|
|
8
|
+
export declare const ListTestFilesParamsShape: {
|
|
9
|
+
dirs: z.ZodArray<z.ZodString, "many">;
|
|
10
|
+
language: z.ZodEnum<[string, ...string[]]>;
|
|
11
|
+
framework: z.ZodEnum<[string, ...string[]]>;
|
|
12
|
+
};
|
|
13
|
+
export declare const TEST_FILE_DETECTION: Record<SDKSupportedLanguage, DetectionConfig>;
|
|
14
|
+
export declare const EXCLUDED_DIRS: Set<string>;
|
|
15
|
+
export declare const backendIndicators: RegExp[];
|
|
16
|
+
export declare const strongUIIndicators: RegExp[];
|