@browserstack/mcp-server 1.1.9 → 1.2.0
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/dist/config.d.ts +13 -0
- package/dist/config.js +4 -6
- package/dist/index.d.ts +4 -0
- package/dist/index.js +20 -30
- package/dist/lib/api.d.ts +2 -0
- package/dist/lib/api.js +10 -5
- package/dist/lib/apiClient.d.ts +31 -0
- package/dist/lib/apiClient.js +108 -0
- package/dist/lib/constants.d.ts +17 -0
- package/dist/lib/device-cache.d.ts +9 -0
- package/dist/lib/device-cache.js +3 -3
- package/dist/lib/error.d.ts +7 -0
- package/dist/lib/fuzzy.d.ts +1 -0
- package/dist/lib/get-auth.d.ts +2 -0
- package/dist/lib/get-auth.js +8 -0
- package/dist/lib/inmemory-store.d.ts +1 -0
- package/dist/lib/instrumentation.d.ts +4 -0
- package/dist/lib/instrumentation.js +8 -7
- package/dist/lib/local.d.ts +3 -0
- package/dist/lib/local.js +3 -3
- package/dist/lib/types.d.ts +4 -0
- package/dist/lib/types.js +1 -0
- package/dist/lib/utils.d.ts +4 -0
- package/dist/lib/version-resolver.d.ts +6 -0
- package/dist/logger.d.ts +3 -0
- package/dist/logger.js +20 -4
- package/dist/oninitialized.d.ts +2 -0
- package/dist/oninitialized.js +2 -7
- package/dist/server-factory.d.ts +3 -0
- package/dist/server-factory.js +37 -0
- package/dist/tools/accessibility.d.ts +3 -0
- package/dist/tools/accessibility.js +17 -10
- package/dist/tools/accessiblity-utils/accessibility-rag.d.ts +12 -0
- package/dist/tools/accessiblity-utils/accessibility-rag.js +22 -12
- package/dist/tools/accessiblity-utils/report-fetcher.d.ts +8 -0
- package/dist/tools/accessiblity-utils/report-fetcher.js +26 -16
- package/dist/tools/accessiblity-utils/report-parser.d.ts +23 -0
- package/dist/tools/accessiblity-utils/report-parser.js +3 -3
- package/dist/tools/accessiblity-utils/scanner.d.ts +25 -0
- package/dist/tools/accessiblity-utils/scanner.js +43 -24
- package/dist/tools/appautomate-utils/appautomate.d.ts +42 -0
- package/dist/tools/appautomate-utils/appautomate.js +63 -38
- package/dist/tools/appautomate-utils/types.d.ts +5 -0
- package/dist/tools/appautomate.d.ts +3 -0
- package/dist/tools/appautomate.js +20 -19
- package/dist/tools/applive-utils/device-search.d.ts +6 -0
- package/dist/tools/applive-utils/start-session.d.ts +15 -0
- package/dist/tools/applive-utils/start-session.js +11 -4
- package/dist/tools/applive-utils/types.d.ts +7 -0
- package/dist/tools/applive-utils/upload-app.d.ts +5 -0
- package/dist/tools/applive-utils/upload-app.js +8 -12
- package/dist/tools/applive-utils/version-utils.d.ts +4 -0
- package/dist/tools/applive.d.ts +13 -0
- package/dist/tools/applive.js +6 -6
- package/dist/tools/automate-utils/fetch-screenshots.d.ts +6 -0
- package/dist/tools/automate-utils/fetch-screenshots.js +16 -12
- package/dist/tools/automate.d.ts +9 -0
- package/dist/tools/automate.js +6 -6
- package/dist/tools/bstack-sdk.d.ts +17 -0
- package/dist/tools/bstack-sdk.js +12 -7
- package/dist/tools/failurelogs-utils/app-automate.d.ts +7 -0
- package/dist/tools/failurelogs-utils/app-automate.js +29 -11
- package/dist/tools/failurelogs-utils/automate.d.ts +6 -0
- package/dist/tools/failurelogs-utils/automate.js +27 -12
- package/dist/tools/failurelogs-utils/utils.d.ts +30 -0
- package/dist/tools/getFailureLogs.d.ts +14 -0
- package/dist/tools/getFailureLogs.js +11 -11
- package/dist/tools/live-utils/desktop-filter.d.ts +2 -0
- package/dist/tools/live-utils/mobile-filter.d.ts +2 -0
- package/dist/tools/live-utils/start-session.d.ts +6 -0
- package/dist/tools/live-utils/start-session.js +18 -5
- package/dist/tools/live-utils/types.d.ts +33 -0
- package/dist/tools/live.d.ts +3 -0
- package/dist/tools/live.js +11 -11
- package/dist/tools/observability.d.ts +5 -0
- package/dist/tools/observability.js +14 -11
- package/dist/tools/sdk-utils/commands.d.ts +3 -0
- package/dist/tools/sdk-utils/commands.js +5 -4
- package/dist/tools/sdk-utils/constants.d.ts +2 -0
- package/dist/tools/sdk-utils/constants.js +82 -21
- package/dist/tools/sdk-utils/instructions.d.ts +6 -0
- package/dist/tools/sdk-utils/instructions.js +8 -6
- package/dist/tools/sdk-utils/percy/constants.d.ts +3 -0
- package/dist/tools/sdk-utils/percy/constants.js +1 -0
- package/dist/tools/sdk-utils/percy/instructions.d.ts +10 -0
- package/dist/tools/sdk-utils/percy/types.d.ts +5 -0
- package/dist/tools/sdk-utils/types.d.ts +39 -0
- package/dist/tools/sdk-utils/types.js +1 -0
- package/dist/tools/selfheal-utils/selfheal.d.ts +11 -0
- package/dist/tools/selfheal-utils/selfheal.js +10 -6
- package/dist/tools/selfheal.d.ts +7 -0
- package/dist/tools/selfheal.js +6 -6
- package/dist/tools/testmanagement-utils/TCG-utils/api.d.ts +34 -0
- package/dist/tools/testmanagement-utils/TCG-utils/api.js +57 -44
- package/dist/tools/testmanagement-utils/TCG-utils/config.d.ts +5 -0
- package/dist/tools/testmanagement-utils/TCG-utils/helpers.d.ts +13 -0
- package/dist/tools/testmanagement-utils/TCG-utils/helpers.js +2 -1
- package/dist/tools/testmanagement-utils/TCG-utils/types.d.ts +26 -0
- package/dist/tools/testmanagement-utils/add-test-result.d.ts +42 -0
- package/dist/tools/testmanagement-utils/add-test-result.js +23 -10
- package/dist/tools/testmanagement-utils/create-lca-steps.d.ts +100 -0
- package/dist/tools/testmanagement-utils/create-lca-steps.js +64 -55
- package/dist/tools/testmanagement-utils/create-project-folder.d.ts +31 -0
- package/dist/tools/testmanagement-utils/create-project-folder.js +31 -21
- package/dist/tools/testmanagement-utils/create-testcase.d.ts +122 -0
- package/dist/tools/testmanagement-utils/create-testcase.js +13 -10
- package/dist/tools/testmanagement-utils/create-testrun.d.ts +82 -0
- package/dist/tools/testmanagement-utils/create-testrun.js +11 -8
- package/dist/tools/testmanagement-utils/list-testcases.d.ts +30 -0
- package/dist/tools/testmanagement-utils/list-testcases.js +9 -7
- package/dist/tools/testmanagement-utils/list-testruns.d.ts +22 -0
- package/dist/tools/testmanagement-utils/list-testruns.js +9 -7
- package/dist/tools/testmanagement-utils/poll-lca-status.d.ts +11 -0
- package/dist/tools/testmanagement-utils/poll-lca-status.js +12 -8
- package/dist/tools/testmanagement-utils/testcase-from-file.d.ts +4 -0
- package/dist/tools/testmanagement-utils/testcase-from-file.js +6 -6
- package/dist/tools/testmanagement-utils/update-testrun.d.ts +40 -0
- package/dist/tools/testmanagement-utils/update-testrun.js +11 -7
- package/dist/tools/testmanagement-utils/upload-file.d.ts +20 -0
- package/dist/tools/testmanagement-utils/upload-file.js +8 -6
- package/dist/tools/testmanagement.d.ts +60 -0
- package/dist/tools/testmanagement.js +51 -53
- package/package.json +1 -1
|
@@ -5,7 +5,7 @@ import { retrieveNetworkFailures, retrieveSessionFailures, retrieveConsoleFailur
|
|
|
5
5
|
import { retrieveDeviceLogs, retrieveAppiumLogs, retrieveCrashLogs, } from "./failurelogs-utils/app-automate.js";
|
|
6
6
|
import { AppAutomateLogType, AutomateLogType, SessionType, } from "../lib/constants.js";
|
|
7
7
|
// Main log fetcher function
|
|
8
|
-
export async function getFailureLogs(args) {
|
|
8
|
+
export async function getFailureLogs(args, config) {
|
|
9
9
|
const results = [];
|
|
10
10
|
const errors = [];
|
|
11
11
|
let validLogTypes = [];
|
|
@@ -53,32 +53,32 @@ export async function getFailureLogs(args) {
|
|
|
53
53
|
for (const logType of validLogTypes) {
|
|
54
54
|
switch (logType) {
|
|
55
55
|
case AutomateLogType.NetworkLogs: {
|
|
56
|
-
response = await retrieveNetworkFailures(args.sessionId);
|
|
56
|
+
response = await retrieveNetworkFailures(args.sessionId, config);
|
|
57
57
|
results.push({ type: "text", text: response });
|
|
58
58
|
break;
|
|
59
59
|
}
|
|
60
60
|
case AutomateLogType.SessionLogs: {
|
|
61
|
-
response = await retrieveSessionFailures(args.sessionId);
|
|
61
|
+
response = await retrieveSessionFailures(args.sessionId, config);
|
|
62
62
|
results.push({ type: "text", text: response });
|
|
63
63
|
break;
|
|
64
64
|
}
|
|
65
65
|
case AutomateLogType.ConsoleLogs: {
|
|
66
|
-
response = await retrieveConsoleFailures(args.sessionId);
|
|
66
|
+
response = await retrieveConsoleFailures(args.sessionId, config);
|
|
67
67
|
results.push({ type: "text", text: response });
|
|
68
68
|
break;
|
|
69
69
|
}
|
|
70
70
|
case AppAutomateLogType.DeviceLogs: {
|
|
71
|
-
response = await retrieveDeviceLogs(args.sessionId, args.buildId);
|
|
71
|
+
response = await retrieveDeviceLogs(args.sessionId, args.buildId, config);
|
|
72
72
|
results.push({ type: "text", text: response });
|
|
73
73
|
break;
|
|
74
74
|
}
|
|
75
75
|
case AppAutomateLogType.AppiumLogs: {
|
|
76
|
-
response = await retrieveAppiumLogs(args.sessionId, args.buildId);
|
|
76
|
+
response = await retrieveAppiumLogs(args.sessionId, args.buildId, config);
|
|
77
77
|
results.push({ type: "text", text: response });
|
|
78
78
|
break;
|
|
79
79
|
}
|
|
80
80
|
case AppAutomateLogType.CrashLogs: {
|
|
81
|
-
response = await retrieveCrashLogs(args.sessionId, args.buildId);
|
|
81
|
+
response = await retrieveCrashLogs(args.sessionId, args.buildId, config);
|
|
82
82
|
results.push({ type: "text", text: response });
|
|
83
83
|
break;
|
|
84
84
|
}
|
|
@@ -98,7 +98,7 @@ export async function getFailureLogs(args) {
|
|
|
98
98
|
return { content: results };
|
|
99
99
|
}
|
|
100
100
|
// Register tool with the MCP server
|
|
101
|
-
export default function registerGetFailureLogs(server) {
|
|
101
|
+
export default function registerGetFailureLogs(server, config) {
|
|
102
102
|
server.tool("getFailureLogs", "Fetch various types of logs from a BrowserStack session. Supports both automate and app-automate sessions.", {
|
|
103
103
|
sessionType: z
|
|
104
104
|
.enum([SessionType.Automate, SessionType.AppAutomate])
|
|
@@ -122,12 +122,12 @@ export default function registerGetFailureLogs(server) {
|
|
|
122
122
|
.describe("The types of logs to fetch."),
|
|
123
123
|
}, async (args) => {
|
|
124
124
|
try {
|
|
125
|
-
trackMCP("getFailureLogs", server.server.getClientVersion());
|
|
126
|
-
return await getFailureLogs(args);
|
|
125
|
+
trackMCP("getFailureLogs", server.server.getClientVersion(), undefined, config);
|
|
126
|
+
return await getFailureLogs(args, config);
|
|
127
127
|
}
|
|
128
128
|
catch (error) {
|
|
129
129
|
const message = error instanceof Error ? error.message : String(error);
|
|
130
|
-
trackMCP("getFailureLogs", server.server.getClientVersion(), error);
|
|
130
|
+
trackMCP("getFailureLogs", server.server.getClientVersion(), error, config);
|
|
131
131
|
logger.error("Failed to fetch logs: %s", message);
|
|
132
132
|
return {
|
|
133
133
|
content: [
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { DesktopSearchArgs, MobileSearchArgs } from "./types.js";
|
|
2
|
+
import { BrowserStackConfig } from "../../lib/types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Entrypoint: detects platformType & delegates.
|
|
5
|
+
*/
|
|
6
|
+
export declare function startBrowserSession(args: DesktopSearchArgs | MobileSearchArgs, config: BrowserStackConfig): Promise<string>;
|
|
@@ -4,13 +4,18 @@ import { filterDesktop } from "./desktop-filter.js";
|
|
|
4
4
|
import { filterMobile } from "./mobile-filter.js";
|
|
5
5
|
import { PlatformType, } from "./types.js";
|
|
6
6
|
import { isLocalURL, ensureLocalBinarySetup, killExistingBrowserStackLocalProcesses, } from "../../lib/local.js";
|
|
7
|
+
import { getBrowserStackAuth } from "../../lib/get-auth.js";
|
|
8
|
+
import envConfig from "../../config.js";
|
|
7
9
|
/**
|
|
8
10
|
* Prepares local tunnel setup based on URL type
|
|
9
11
|
*/
|
|
10
|
-
async function prepareLocalTunnel(url) {
|
|
12
|
+
async function prepareLocalTunnel(url, username, password) {
|
|
11
13
|
const isLocal = isLocalURL(url);
|
|
14
|
+
if (isLocal && envConfig.REMOTE_MCP) {
|
|
15
|
+
throw new Error("Local URLs are not supported in this remote mcp. Please use a public URL.");
|
|
16
|
+
}
|
|
12
17
|
if (isLocal) {
|
|
13
|
-
await ensureLocalBinarySetup();
|
|
18
|
+
await ensureLocalBinarySetup(username, password);
|
|
14
19
|
}
|
|
15
20
|
else {
|
|
16
21
|
await killExistingBrowserStackLocalProcesses();
|
|
@@ -20,15 +25,23 @@ async function prepareLocalTunnel(url) {
|
|
|
20
25
|
/**
|
|
21
26
|
* Entrypoint: detects platformType & delegates.
|
|
22
27
|
*/
|
|
23
|
-
export async function startBrowserSession(args) {
|
|
28
|
+
export async function startBrowserSession(args, config) {
|
|
24
29
|
const entry = args.platformType === PlatformType.DESKTOP
|
|
25
30
|
? await filterDesktop(args)
|
|
26
31
|
: await filterMobile(args);
|
|
27
|
-
|
|
32
|
+
// Get credentials from config
|
|
33
|
+
const authString = getBrowserStackAuth(config);
|
|
34
|
+
const [username, password] = authString.split(":");
|
|
35
|
+
if (!username || !password) {
|
|
36
|
+
throw new Error("BrowserStack credentials are not set. Please configure them in the server settings.");
|
|
37
|
+
}
|
|
38
|
+
const isLocal = await prepareLocalTunnel(args.url, username, password);
|
|
28
39
|
const url = args.platformType === PlatformType.DESKTOP
|
|
29
40
|
? buildDesktopUrl(args, entry, isLocal)
|
|
30
41
|
: buildMobileUrl(args, entry, isLocal);
|
|
31
|
-
|
|
42
|
+
if (!envConfig.REMOTE_MCP) {
|
|
43
|
+
openBrowser(url);
|
|
44
|
+
}
|
|
32
45
|
return entry.notes ? `${url}, ${entry.notes}` : url;
|
|
33
46
|
}
|
|
34
47
|
function buildDesktopUrl(args, e, isLocal) {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface DesktopSearchArgs {
|
|
2
|
+
platformType: "desktop";
|
|
3
|
+
url: string;
|
|
4
|
+
os: string;
|
|
5
|
+
osVersion: string;
|
|
6
|
+
browser: string;
|
|
7
|
+
browserVersion: string;
|
|
8
|
+
}
|
|
9
|
+
export interface DesktopEntry {
|
|
10
|
+
os: string;
|
|
11
|
+
os_version: string;
|
|
12
|
+
browser: string;
|
|
13
|
+
browser_version: string;
|
|
14
|
+
notes?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface MobileSearchArgs {
|
|
17
|
+
platformType: "mobile";
|
|
18
|
+
url: string;
|
|
19
|
+
os: string;
|
|
20
|
+
osVersion: string;
|
|
21
|
+
device: string;
|
|
22
|
+
browser: string;
|
|
23
|
+
}
|
|
24
|
+
export interface MobileEntry {
|
|
25
|
+
os: string;
|
|
26
|
+
os_version: string;
|
|
27
|
+
display_name: string;
|
|
28
|
+
notes?: string;
|
|
29
|
+
}
|
|
30
|
+
export declare enum PlatformType {
|
|
31
|
+
DESKTOP = "desktop",
|
|
32
|
+
MOBILE = "mobile"
|
|
33
|
+
}
|
package/dist/tools/live.js
CHANGED
|
@@ -28,7 +28,7 @@ const LiveArgsSchema = z.object(LiveArgsShape);
|
|
|
28
28
|
/**
|
|
29
29
|
* Launches a desktop browser session
|
|
30
30
|
*/
|
|
31
|
-
async function launchDesktopSession(args) {
|
|
31
|
+
async function launchDesktopSession(args, config) {
|
|
32
32
|
if (!args.desiredBrowser)
|
|
33
33
|
throw new Error("You must provide a desiredBrowser");
|
|
34
34
|
if (!args.desiredBrowserVersion)
|
|
@@ -40,12 +40,12 @@ async function launchDesktopSession(args) {
|
|
|
40
40
|
osVersion: args.desiredOSVersion,
|
|
41
41
|
browser: args.desiredBrowser,
|
|
42
42
|
browserVersion: args.desiredBrowserVersion,
|
|
43
|
-
});
|
|
43
|
+
}, config);
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
46
|
* Launches a mobile browser session
|
|
47
47
|
*/
|
|
48
|
-
async function launchMobileSession(args) {
|
|
48
|
+
async function launchMobileSession(args, config) {
|
|
49
49
|
if (!args.desiredDevice)
|
|
50
50
|
throw new Error("You must provide a desiredDevice");
|
|
51
51
|
return startBrowserSession({
|
|
@@ -55,18 +55,18 @@ async function launchMobileSession(args) {
|
|
|
55
55
|
os: args.desiredOS,
|
|
56
56
|
osVersion: args.desiredOSVersion,
|
|
57
57
|
device: args.desiredDevice,
|
|
58
|
-
});
|
|
58
|
+
}, config);
|
|
59
59
|
}
|
|
60
60
|
/**
|
|
61
61
|
* Handles the core logic for running a browser session
|
|
62
62
|
*/
|
|
63
|
-
async function runBrowserSession(rawArgs) {
|
|
63
|
+
async function runBrowserSession(rawArgs, config) {
|
|
64
64
|
// Validate and narrow
|
|
65
65
|
const args = LiveArgsSchema.parse(rawArgs);
|
|
66
66
|
// Branch desktop vs mobile and delegate
|
|
67
67
|
const launchUrl = args.platformType === PlatformType.DESKTOP
|
|
68
|
-
? await launchDesktopSession(args)
|
|
69
|
-
: await launchMobileSession(args);
|
|
68
|
+
? await launchDesktopSession(args, config)
|
|
69
|
+
: await launchMobileSession(args, config);
|
|
70
70
|
return {
|
|
71
71
|
content: [
|
|
72
72
|
{
|
|
@@ -76,15 +76,15 @@ async function runBrowserSession(rawArgs) {
|
|
|
76
76
|
],
|
|
77
77
|
};
|
|
78
78
|
}
|
|
79
|
-
export default function addBrowserLiveTools(server) {
|
|
79
|
+
export default function addBrowserLiveTools(server, config) {
|
|
80
80
|
server.tool("runBrowserLiveSession", "Launch a BrowserStack Live session (desktop or mobile).", LiveArgsShape, async (args) => {
|
|
81
81
|
try {
|
|
82
|
-
trackMCP("runBrowserLiveSession", server.server.getClientVersion());
|
|
83
|
-
return await runBrowserSession(args);
|
|
82
|
+
trackMCP("runBrowserLiveSession", server.server.getClientVersion(), undefined, config);
|
|
83
|
+
return await runBrowserSession(args, config);
|
|
84
84
|
}
|
|
85
85
|
catch (error) {
|
|
86
86
|
logger.error("Live session failed: %s", error);
|
|
87
|
-
trackMCP("runBrowserLiveSession", server.server.getClientVersion(), error);
|
|
87
|
+
trackMCP("runBrowserLiveSession", server.server.getClientVersion(), error, config);
|
|
88
88
|
return {
|
|
89
89
|
content: [
|
|
90
90
|
{
|
|
@@ -0,0 +1,5 @@
|
|
|
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 getFailuresInLastRun(buildName: string, projectName: string, config: BrowserStackConfig): Promise<CallToolResult>;
|
|
5
|
+
export default function addObservabilityTools(server: McpServer, config: BrowserStackConfig): void;
|
|
@@ -2,19 +2,22 @@ import { z } from "zod";
|
|
|
2
2
|
import { getLatestO11YBuildInfo } from "../lib/api.js";
|
|
3
3
|
import { trackMCP } from "../lib/instrumentation.js";
|
|
4
4
|
import logger from "../logger.js";
|
|
5
|
-
export async function getFailuresInLastRun(buildName, projectName) {
|
|
6
|
-
const buildsData = await getLatestO11YBuildInfo(buildName, projectName);
|
|
7
|
-
|
|
5
|
+
export async function getFailuresInLastRun(buildName, projectName, config) {
|
|
6
|
+
const buildsData = await getLatestO11YBuildInfo(buildName, projectName, config);
|
|
7
|
+
if (!buildsData.data) {
|
|
8
|
+
throw new Error("No observability URL found in build data, this is likely because the build is not yet available on BrowserStack Observability.");
|
|
9
|
+
}
|
|
10
|
+
const observabilityUrl = buildsData.data.observability_url;
|
|
8
11
|
if (!observabilityUrl) {
|
|
9
12
|
throw new Error("No observability URL found in build data, this is likely because the build is not yet available on BrowserStack Observability.");
|
|
10
13
|
}
|
|
11
14
|
let overview = "No overview available";
|
|
12
|
-
if (buildsData.unique_errors?.overview?.insight) {
|
|
13
|
-
overview = buildsData.unique_errors.overview.insight;
|
|
15
|
+
if (buildsData.data.unique_errors?.overview?.insight) {
|
|
16
|
+
overview = buildsData.data.unique_errors.overview.insight;
|
|
14
17
|
}
|
|
15
18
|
let details = "No error details available";
|
|
16
|
-
if (buildsData.unique_errors?.top_unique_errors?.length > 0) {
|
|
17
|
-
details = buildsData.unique_errors.top_unique_errors
|
|
19
|
+
if (buildsData.data.unique_errors?.top_unique_errors?.length > 0) {
|
|
20
|
+
details = buildsData.data.unique_errors.top_unique_errors
|
|
18
21
|
.map((error) => error.error)
|
|
19
22
|
.filter(Boolean)
|
|
20
23
|
.join("\n");
|
|
@@ -28,7 +31,7 @@ export async function getFailuresInLastRun(buildName, projectName) {
|
|
|
28
31
|
],
|
|
29
32
|
};
|
|
30
33
|
}
|
|
31
|
-
export default function addObservabilityTools(server) {
|
|
34
|
+
export default function addObservabilityTools(server, config) {
|
|
32
35
|
server.tool("getFailuresInLastRun", "Use this tool to debug failures in the last run of the test suite on BrowserStack. Use only when browserstack.yml file is present in the project root.", {
|
|
33
36
|
buildName: z
|
|
34
37
|
.string()
|
|
@@ -38,12 +41,12 @@ export default function addObservabilityTools(server) {
|
|
|
38
41
|
.describe("Name of the project to get failures for. This is the 'projectName' key in the browserstack.yml file. If not sure, ask the user for the project name."),
|
|
39
42
|
}, async (args) => {
|
|
40
43
|
try {
|
|
41
|
-
trackMCP("getFailuresInLastRun", server.server.getClientVersion());
|
|
42
|
-
return await getFailuresInLastRun(args.buildName, args.projectName);
|
|
44
|
+
trackMCP("getFailuresInLastRun", server.server.getClientVersion(), undefined, config);
|
|
45
|
+
return await getFailuresInLastRun(args.buildName, args.projectName, config);
|
|
43
46
|
}
|
|
44
47
|
catch (error) {
|
|
45
48
|
logger.error("Failed to get failures in the last run: %s", error);
|
|
46
|
-
trackMCP("getFailuresInLastRun", server.server.getClientVersion(), error);
|
|
49
|
+
trackMCP("getFailuresInLastRun", server.server.getClientVersion(), error, config);
|
|
47
50
|
return {
|
|
48
51
|
content: [
|
|
49
52
|
{
|
|
@@ -4,6 +4,7 @@ const JAVA_FRAMEWORK_MAP = {
|
|
|
4
4
|
junit5: "junit5",
|
|
5
5
|
junit4: "junit4",
|
|
6
6
|
cucumber: "cucumber-testng",
|
|
7
|
+
serenity: "serenity",
|
|
7
8
|
};
|
|
8
9
|
// Common Gradle setup instructions (platform-independent)
|
|
9
10
|
const GRADLE_SETUP_INSTRUCTIONS = `
|
|
@@ -17,7 +18,7 @@ const GRADLE_SETUP_INSTRUCTIONS = `
|
|
|
17
18
|
3. Add javaagent to gradle tasks:
|
|
18
19
|
jvmArgs "-javaagent:\${browserstackSDKArtifact.file}"
|
|
19
20
|
`;
|
|
20
|
-
export function getSDKPrefixCommand(language, framework) {
|
|
21
|
+
export function getSDKPrefixCommand(language, framework, username, accessKey) {
|
|
21
22
|
switch (language) {
|
|
22
23
|
case "nodejs":
|
|
23
24
|
return `---STEP---
|
|
@@ -28,7 +29,7 @@ npm i -D browserstack-node-sdk@latest
|
|
|
28
29
|
---STEP---
|
|
29
30
|
Run the following command to setup browserstack sdk:
|
|
30
31
|
\`\`\`bash
|
|
31
|
-
npx setup --username ${
|
|
32
|
+
npx setup --username ${username} --key ${accessKey}
|
|
32
33
|
\`\`\`
|
|
33
34
|
---STEP---
|
|
34
35
|
Edit the browserstack.yml file that was created in the project root to add your desired platforms and browsers.`;
|
|
@@ -40,8 +41,8 @@ Edit the browserstack.yml file that was created in the project root to add your
|
|
|
40
41
|
: `mvn archetype:generate -B -DarchetypeGroupId=com.browserstack \\
|
|
41
42
|
-DarchetypeArtifactId=browserstack-sdk-archetype-integrate -DarchetypeVersion=1.0 \\
|
|
42
43
|
-DgroupId=com.browserstack -DartifactId=browserstack-sdk-archetype-integrate -Dversion=1.0 \\
|
|
43
|
-
-DBROWSERSTACK_USERNAME="${
|
|
44
|
-
-DBROWSERSTACK_ACCESS_KEY="${
|
|
44
|
+
-DBROWSERSTACK_USERNAME="${username}" \\
|
|
45
|
+
-DBROWSERSTACK_ACCESS_KEY="${accessKey}" \\
|
|
45
46
|
-DBROWSERSTACK_FRAMEWORK="${mavenFramework}"`;
|
|
46
47
|
const platformLabel = isWindows ? "Windows" : "macOS/Linux";
|
|
47
48
|
return `---STEP---
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import config from "../../config.js";
|
|
2
1
|
/**
|
|
3
2
|
* ---------- PYTHON INSTRUCTIONS ----------
|
|
4
3
|
*/
|
|
5
|
-
const pythonInstructions = `
|
|
4
|
+
const pythonInstructions = (username, accessKey) => `
|
|
6
5
|
---STEP---
|
|
7
6
|
|
|
8
7
|
Install the BrowserStack SDK:
|
|
@@ -14,7 +13,7 @@ python3 -m pip install browserstack-sdk
|
|
|
14
13
|
|
|
15
14
|
Setup the BrowserStack SDK with your credentials:
|
|
16
15
|
\`\`\`bash
|
|
17
|
-
browserstack-sdk setup --username "${
|
|
16
|
+
browserstack-sdk setup --username "${username}" --key "${accessKey}"
|
|
18
17
|
\`\`\`
|
|
19
18
|
|
|
20
19
|
---STEP---
|
|
@@ -24,10 +23,11 @@ Run your tests on BrowserStack:
|
|
|
24
23
|
browserstack-sdk python <path-to-test-file>
|
|
25
24
|
\`\`\`
|
|
26
25
|
`;
|
|
27
|
-
const generatePythonFrameworkInstructions = (framework) => `
|
|
26
|
+
const generatePythonFrameworkInstructions = (framework) => (username, accessKey) => `
|
|
28
27
|
---STEP---
|
|
29
28
|
|
|
30
29
|
Install the BrowserStack SDK:
|
|
30
|
+
|
|
31
31
|
\`\`\`bash
|
|
32
32
|
python3 -m pip install browserstack-sdk
|
|
33
33
|
\`\`\`
|
|
@@ -36,7 +36,7 @@ python3 -m pip install browserstack-sdk
|
|
|
36
36
|
|
|
37
37
|
Setup the BrowserStack SDK with framework-specific configuration:
|
|
38
38
|
\`\`\`bash
|
|
39
|
-
browserstack-sdk setup --framework "${framework}" --username "${
|
|
39
|
+
browserstack-sdk setup --framework "${framework}" --username "${username}" --key "${accessKey}"
|
|
40
40
|
\`\`\`
|
|
41
41
|
|
|
42
42
|
---STEP---
|
|
@@ -53,7 +53,7 @@ const pytestInstructions = generatePythonFrameworkInstructions("pytest");
|
|
|
53
53
|
* ---------- JAVA INSTRUCTIONS ----------
|
|
54
54
|
*/
|
|
55
55
|
const argsInstruction = '<argLine>-javaagent:"${com.browserstack:browserstack-java-sdk:jar}"</argLine>';
|
|
56
|
-
const javaInstructions = `
|
|
56
|
+
const javaInstructions = (username, accessKey) => `
|
|
57
57
|
---STEP---
|
|
58
58
|
|
|
59
59
|
Add the BrowserStack Java SDK dependency to your \`pom.xml\`:
|
|
@@ -79,8 +79,8 @@ dependencies {
|
|
|
79
79
|
|
|
80
80
|
Export your BrowserStack credentials as environment variables:
|
|
81
81
|
\`\`\`bash
|
|
82
|
-
export BROWSERSTACK_USERNAME=${
|
|
83
|
-
export BROWSERSTACK_ACCESS_KEY=${
|
|
82
|
+
export BROWSERSTACK_USERNAME=${username}
|
|
83
|
+
export BROWSERSTACK_ACCESS_KEY=${accessKey}
|
|
84
84
|
\`\`\`
|
|
85
85
|
|
|
86
86
|
---STEP---
|
|
@@ -95,10 +95,66 @@ Or for Gradle:
|
|
|
95
95
|
gradle clean test
|
|
96
96
|
\`\`\`
|
|
97
97
|
`;
|
|
98
|
+
const serenityInstructions = (username, accessKey) => `
|
|
99
|
+
---STEP---
|
|
100
|
+
|
|
101
|
+
Set BrowserStack credentials as environment variables:
|
|
102
|
+
For macOS/Linux:
|
|
103
|
+
\`\`\`bash
|
|
104
|
+
export BROWSERSTACK_USERNAME=${username}
|
|
105
|
+
export BROWSERSTACK_ACCESS_KEY=${accessKey}
|
|
106
|
+
\`\`\`
|
|
107
|
+
|
|
108
|
+
For Windows Command Prompt:
|
|
109
|
+
\`\`\`cmd
|
|
110
|
+
set BROWSERSTACK_USERNAME=${username}
|
|
111
|
+
set BROWSERSTACK_ACCESS_KEY=${accessKey}
|
|
112
|
+
\`\`\`
|
|
113
|
+
|
|
114
|
+
---STEP---
|
|
115
|
+
|
|
116
|
+
Add serenity-browserstack dependency in pom.xml:
|
|
117
|
+
Add the following dependency to your pom.xml file and save it:
|
|
118
|
+
\`\`\`xml
|
|
119
|
+
<dependency>
|
|
120
|
+
<groupId>net.serenity-bdd</groupId>
|
|
121
|
+
<artifactId>serenity-browserstack</artifactId>
|
|
122
|
+
<version>3.3.4</version>
|
|
123
|
+
</dependency>
|
|
124
|
+
\`\`\`
|
|
125
|
+
|
|
126
|
+
---STEP---
|
|
127
|
+
|
|
128
|
+
Set up serenity.conf file:
|
|
129
|
+
Create or update your serenity.conf file in the project root with the following configuration:
|
|
130
|
+
\`\`\`
|
|
131
|
+
webdriver {
|
|
132
|
+
driver = remote
|
|
133
|
+
remote.url = "https://hub.browserstack.com/wd/hub"
|
|
134
|
+
}
|
|
135
|
+
browserstack.user="${username}"
|
|
136
|
+
browserstack.key="${accessKey}"
|
|
137
|
+
\`\`\`
|
|
138
|
+
|
|
139
|
+
---STEP---
|
|
140
|
+
|
|
141
|
+
Run your Serenity tests:
|
|
142
|
+
You can continue running your tests as you normally would. For example:
|
|
143
|
+
|
|
144
|
+
Using Maven:
|
|
145
|
+
\`\`\`bash
|
|
146
|
+
mvn clean verify
|
|
147
|
+
\`\`\`
|
|
148
|
+
|
|
149
|
+
Using Gradle:
|
|
150
|
+
\`\`\`bash
|
|
151
|
+
gradle clean test
|
|
152
|
+
\`\`\`
|
|
153
|
+
`;
|
|
98
154
|
/**
|
|
99
155
|
* ---------- CSharp INSTRUCTIONS ----------
|
|
100
156
|
*/
|
|
101
|
-
const csharpCommonInstructions = `
|
|
157
|
+
const csharpCommonInstructions = (username, accessKey) => `
|
|
102
158
|
---STEP---
|
|
103
159
|
|
|
104
160
|
Install BrowserStack TestAdapter NuGet package:
|
|
@@ -117,7 +173,7 @@ dotnet build
|
|
|
117
173
|
|
|
118
174
|
Set up BrowserStack SDK with your credentials:
|
|
119
175
|
\`\`\`bash
|
|
120
|
-
dotnet browserstack-sdk setup --userName ${
|
|
176
|
+
dotnet browserstack-sdk setup --userName ${username} --accessKey ${accessKey}
|
|
121
177
|
\`\`\`
|
|
122
178
|
|
|
123
179
|
---STEP---
|
|
@@ -160,7 +216,7 @@ Run the tests:
|
|
|
160
216
|
dotnet test
|
|
161
217
|
\`\`\`
|
|
162
218
|
`;
|
|
163
|
-
const csharpPlaywrightCommonInstructions = `
|
|
219
|
+
const csharpPlaywrightCommonInstructions = (username, accessKey) => `
|
|
164
220
|
---STEP---
|
|
165
221
|
|
|
166
222
|
Install BrowserStack TestAdapter NuGet package:
|
|
@@ -179,7 +235,7 @@ dotnet build
|
|
|
179
235
|
|
|
180
236
|
Set up BrowserStack SDK with your credentials:
|
|
181
237
|
\`\`\`bash
|
|
182
|
-
dotnet browserstack-sdk setup --userName ${
|
|
238
|
+
dotnet browserstack-sdk setup --userName ${username} --accessKey ${accessKey}
|
|
183
239
|
\`\`\`
|
|
184
240
|
|
|
185
241
|
---STEP---
|
|
@@ -238,7 +294,7 @@ Run the tests:
|
|
|
238
294
|
/**
|
|
239
295
|
* ---------- NODEJS INSTRUCTIONS ----------
|
|
240
296
|
*/
|
|
241
|
-
const nodejsInstructions = `
|
|
297
|
+
const nodejsInstructions = (username, accessKey) => `
|
|
242
298
|
---STEP---
|
|
243
299
|
|
|
244
300
|
Ensure \`browserstack-node-sdk\` is present in package.json with the latest version:
|
|
@@ -259,11 +315,15 @@ Add new scripts to package.json for running tests on BrowserStack:
|
|
|
259
315
|
|
|
260
316
|
Export BrowserStack credentials as environment variables:
|
|
261
317
|
Set the following environment variables before running tests.
|
|
318
|
+
\`\`\`bash
|
|
319
|
+
export BROWSERSTACK_USERNAME=${username}
|
|
320
|
+
export BROWSERSTACK_ACCESS_KEY=${accessKey}
|
|
321
|
+
\`\`\`
|
|
262
322
|
`;
|
|
263
323
|
/**
|
|
264
324
|
* ---------- EXPORT CONFIG ----------
|
|
265
325
|
*/
|
|
266
|
-
const webdriverioInstructions = `
|
|
326
|
+
const webdriverioInstructions = (username, accessKey) => `
|
|
267
327
|
---STEP---
|
|
268
328
|
|
|
269
329
|
Set BrowserStack Credentials:
|
|
@@ -271,14 +331,14 @@ Export your BrowserStack username and access key as environment variables.
|
|
|
271
331
|
|
|
272
332
|
For macOS/Linux:
|
|
273
333
|
\`\`\`bash
|
|
274
|
-
export BROWSERSTACK_USERNAME
|
|
275
|
-
export BROWSERSTACK_ACCESS_KEY
|
|
334
|
+
export BROWSERSTACK_USERNAME=${username}
|
|
335
|
+
export BROWSERSTACK_ACCESS_KEY=${accessKey}
|
|
276
336
|
\`\`\`
|
|
277
337
|
|
|
278
338
|
For Windows PowerShell:
|
|
279
339
|
\`\`\`powershell
|
|
280
|
-
$env:BROWSERSTACK_USERNAME=${
|
|
281
|
-
$env:BROWSERSTACK_ACCESS_KEY=${
|
|
340
|
+
$env:BROWSERSTACK_USERNAME=${username}
|
|
341
|
+
$env:BROWSERSTACK_ACCESS_KEY=${accessKey}
|
|
282
342
|
\`\`\`
|
|
283
343
|
|
|
284
344
|
---STEP---
|
|
@@ -368,7 +428,7 @@ exports.config.capabilities.forEach(function (caps) {
|
|
|
368
428
|
Run your tests:
|
|
369
429
|
You can now run your tests on BrowserStack using your standard WebdriverIO command.
|
|
370
430
|
`;
|
|
371
|
-
const cypressInstructions = `
|
|
431
|
+
const cypressInstructions = (username, accessKey) => `
|
|
372
432
|
---STEP---
|
|
373
433
|
|
|
374
434
|
Install the BrowserStack Cypress CLI:
|
|
@@ -397,8 +457,8 @@ Open the generated \`browserstack.json\` file and update it with your BrowserSta
|
|
|
397
457
|
\`\`\`json
|
|
398
458
|
{
|
|
399
459
|
"auth": {
|
|
400
|
-
"username": "${
|
|
401
|
-
"access_key": "${
|
|
460
|
+
"username": "${username}",
|
|
461
|
+
"access_key": "${accessKey}"
|
|
402
462
|
},
|
|
403
463
|
"browsers": [
|
|
404
464
|
{
|
|
@@ -462,6 +522,7 @@ export const SUPPORTED_CONFIGURATIONS = {
|
|
|
462
522
|
cucumber: { instructions: javaInstructions },
|
|
463
523
|
junit4: { instructions: javaInstructions },
|
|
464
524
|
junit5: { instructions: javaInstructions },
|
|
525
|
+
serenity: { instructions: serenityInstructions },
|
|
465
526
|
},
|
|
466
527
|
},
|
|
467
528
|
csharp: {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { SDKSupportedLanguage } from "./types.js";
|
|
2
|
+
import { SDKSupportedBrowserAutomationFramework } from "./types.js";
|
|
3
|
+
import { SDKSupportedTestingFramework } from "./types.js";
|
|
4
|
+
export declare const getInstructionsForProjectConfiguration: (detectedBrowserAutomationFramework: SDKSupportedBrowserAutomationFramework, detectedTestingFramework: SDKSupportedTestingFramework, detectedLanguage: SDKSupportedLanguage, username: string, accessKey: string) => string;
|
|
5
|
+
export declare function generateBrowserStackYMLInstructions(desiredPlatforms: string[], enablePercy?: boolean): string;
|
|
6
|
+
export declare function formatInstructionsWithNumbers(instructionText: string, separator?: string): string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SUPPORTED_CONFIGURATIONS } from "./constants.js";
|
|
2
2
|
const errorMessageSuffix = "Please open an issue at our Github repo: https://github.com/browserstack/browserstack-mcp-server/issues to request support for your project configuration";
|
|
3
|
-
export const getInstructionsForProjectConfiguration = (detectedBrowserAutomationFramework, detectedTestingFramework, detectedLanguage) => {
|
|
3
|
+
export const getInstructionsForProjectConfiguration = (detectedBrowserAutomationFramework, detectedTestingFramework, detectedLanguage, username, accessKey) => {
|
|
4
4
|
const configuration = SUPPORTED_CONFIGURATIONS[detectedLanguage];
|
|
5
5
|
if (!configuration) {
|
|
6
6
|
throw new Error(`BrowserStack MCP Server currently does not support ${detectedLanguage}, ${errorMessageSuffix}`);
|
|
@@ -11,17 +11,19 @@ export const getInstructionsForProjectConfiguration = (detectedBrowserAutomation
|
|
|
11
11
|
if (!configuration[detectedBrowserAutomationFramework][detectedTestingFramework]) {
|
|
12
12
|
throw new Error(`BrowserStack MCP Server currently does not support ${detectedTestingFramework} for ${detectedBrowserAutomationFramework} on ${detectedLanguage}, ${errorMessageSuffix}`);
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
const instructionFunction = configuration[detectedBrowserAutomationFramework][detectedTestingFramework]
|
|
15
|
+
.instructions;
|
|
16
|
+
return instructionFunction(username, accessKey);
|
|
15
17
|
};
|
|
16
18
|
export function generateBrowserStackYMLInstructions(desiredPlatforms, enablePercy = false) {
|
|
17
19
|
let ymlContent = `
|
|
18
20
|
# ======================
|
|
19
21
|
# BrowserStack Reporting
|
|
20
22
|
# ======================
|
|
21
|
-
#
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
buildName:
|
|
23
|
+
# Project and build names help organize your test runs in BrowserStack dashboard and Percy.
|
|
24
|
+
# TODO: Replace these sample values with your actual project details
|
|
25
|
+
projectName: Sample Project
|
|
26
|
+
buildName: Sample Build
|
|
25
27
|
|
|
26
28
|
# =======================================
|
|
27
29
|
# Platforms (Browsers / Devices to test)
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { PercyConfigMapping } from "./types.js";
|
|
2
|
+
export declare const nodejsSeleniumInstructions = "\nImport the BrowserStack Percy SDK in your test script:\nAdd the Percy import to your test file.\n\n---STEP---\n\nAdd screenshot capture method at required points:\nUse the `percy.snapshot(driver, name)` method at points in your test script where you want to capture screenshots.\n\n```javascript\nconst { percy } = require('browserstack-node-sdk');\ndescribe(\"sample Test\", () => {\n // ... other imports and setup\n \n test(\"my test\", async () => {\n // ....\n await percy.snapshot(driver, \"My Snapshot\")\n // ....\n });\n})\n```\n";
|
|
3
|
+
export declare const PERCY_INSTRUCTIONS: PercyConfigMapping;
|
|
@@ -153,6 +153,7 @@ export const PERCY_INSTRUCTIONS = {
|
|
|
153
153
|
cucumber: { script_updates: javaSeleniumInstructions },
|
|
154
154
|
junit4: { script_updates: javaSeleniumInstructions },
|
|
155
155
|
junit5: { script_updates: javaSeleniumInstructions },
|
|
156
|
+
serenity: { script_updates: javaSeleniumInstructions },
|
|
156
157
|
},
|
|
157
158
|
},
|
|
158
159
|
csharp: {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { SDKSupportedBrowserAutomationFramework, SDKSupportedLanguage, SDKSupportedTestingFramework } from "../types.js";
|
|
2
|
+
import { PercyInstructions } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Retrieves Percy-specific instructions for a given language and framework.
|
|
5
|
+
*/
|
|
6
|
+
export declare function getPercyInstructions(language: SDKSupportedLanguage, automationFramework: SDKSupportedBrowserAutomationFramework, testingFramework: SDKSupportedTestingFramework): PercyInstructions | null;
|
|
7
|
+
/**
|
|
8
|
+
* Formats the retrieved Percy instructions into a user-friendly string.
|
|
9
|
+
*/
|
|
10
|
+
export declare function formatPercyInstructions(instructions: PercyInstructions): string;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { SDKSupportedBrowserAutomationFramework, SDKSupportedLanguage, SDKSupportedTestingFramework } from "../types.js";
|
|
2
|
+
export interface PercyInstructions {
|
|
3
|
+
script_updates: string;
|
|
4
|
+
}
|
|
5
|
+
export type PercyConfigMapping = Partial<Record<SDKSupportedLanguage, Partial<Record<SDKSupportedBrowserAutomationFramework, Partial<Record<SDKSupportedTestingFramework, PercyInstructions>>>>>>;
|