@browserstack/mcp-server 1.1.0 → 1.1.1
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.js +2 -6
- package/dist/index.js +29 -34
- package/dist/lib/api.js +3 -9
- package/dist/lib/constants.js +3 -6
- package/dist/lib/device-cache.js +14 -21
- package/dist/lib/error.js +3 -6
- package/dist/lib/fuzzy.js +1 -4
- package/dist/lib/inmemory-store.js +1 -4
- package/dist/lib/instrumentation.js +12 -18
- package/dist/lib/local.js +27 -35
- package/dist/lib/utils.js +6 -15
- package/dist/logger.js +4 -6
- package/dist/tools/accessibility.js +13 -16
- package/dist/tools/accessiblity-utils/report-fetcher.js +7 -14
- package/dist/tools/accessiblity-utils/report-parser.js +5 -11
- package/dist/tools/accessiblity-utils/scanner.js +9 -16
- package/dist/tools/appautomate-utils/appautomate.js +17 -27
- package/dist/tools/appautomate.js +29 -35
- package/dist/tools/applive-utils/fuzzy-search.js +3 -6
- package/dist/tools/applive-utils/start-session.js +14 -20
- package/dist/tools/applive-utils/upload-app.js +12 -51
- package/dist/tools/applive.js +18 -25
- package/dist/tools/automate-utils/fetch-screenshots.js +8 -14
- package/dist/tools/automate.js +14 -21
- package/dist/tools/bstack-sdk.js +14 -18
- package/dist/tools/failurelogs-utils/app-automate.js +15 -26
- package/dist/tools/failurelogs-utils/automate.js +13 -23
- package/dist/tools/getFailureLogs.js +42 -49
- package/dist/tools/live-utils/desktop-filter.js +8 -11
- package/dist/tools/live-utils/mobile-filter.js +7 -10
- package/dist/tools/live-utils/start-session.js +17 -23
- package/dist/tools/live-utils/types.js +2 -5
- package/dist/tools/live-utils/version-resolver.js +1 -4
- package/dist/tools/live.js +23 -29
- package/dist/tools/observability.js +12 -19
- package/dist/tools/sdk-utils/constants.js +3 -9
- package/dist/tools/sdk-utils/instructions.js +4 -9
- package/dist/tools/sdk-utils/types.js +1 -2
- package/dist/tools/testmanagement-utils/TCG-utils/api.js +26 -38
- package/dist/tools/testmanagement-utils/TCG-utils/config.js +5 -10
- package/dist/tools/testmanagement-utils/TCG-utils/helpers.js +3 -8
- package/dist/tools/testmanagement-utils/TCG-utils/types.js +5 -8
- package/dist/tools/testmanagement-utils/add-test-result.js +17 -24
- package/dist/tools/testmanagement-utils/create-project-folder.js +21 -28
- package/dist/tools/testmanagement-utils/create-testcase.js +30 -38
- package/dist/tools/testmanagement-utils/create-testrun.js +23 -30
- package/dist/tools/testmanagement-utils/list-testcases.js +15 -22
- package/dist/tools/testmanagement-utils/list-testruns.js +12 -19
- package/dist/tools/testmanagement-utils/testcase-from-file.js +16 -22
- package/dist/tools/testmanagement-utils/update-testrun.js +15 -22
- package/dist/tools/testmanagement-utils/upload-file.js +22 -29
- package/dist/tools/testmanagement.js +61 -76
- package/package.json +1 -1
package/dist/tools/live.js
CHANGED
|
@@ -1,36 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
exports.default = addBrowserLiveTools;
|
|
7
|
-
const zod_1 = require("zod");
|
|
8
|
-
const logger_js_1 = __importDefault(require("../logger.js"));
|
|
9
|
-
const start_session_js_1 = require("./live-utils/start-session.js");
|
|
10
|
-
const types_js_1 = require("./live-utils/types.js");
|
|
11
|
-
const instrumentation_js_1 = require("../lib/instrumentation.js");
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import logger from "../logger.js";
|
|
3
|
+
import { startBrowserSession } from "./live-utils/start-session.js";
|
|
4
|
+
import { PlatformType } from "./live-utils/types.js";
|
|
5
|
+
import { trackMCP } from "../lib/instrumentation.js";
|
|
12
6
|
// Define the schema shape
|
|
13
7
|
const LiveArgsShape = {
|
|
14
|
-
platformType:
|
|
15
|
-
.nativeEnum(
|
|
8
|
+
platformType: z
|
|
9
|
+
.nativeEnum(PlatformType)
|
|
16
10
|
.describe("Must be 'desktop' or 'mobile'"),
|
|
17
|
-
desiredURL:
|
|
18
|
-
desiredOS:
|
|
11
|
+
desiredURL: z.string().url().describe("The URL to test"),
|
|
12
|
+
desiredOS: z
|
|
19
13
|
.enum(["Windows", "OS X", "android", "ios", "winphone"])
|
|
20
14
|
.describe("Desktop OS ('Windows' or 'OS X') or mobile OS ('android','ios','winphone')"),
|
|
21
|
-
desiredOSVersion:
|
|
15
|
+
desiredOSVersion: z
|
|
22
16
|
.string()
|
|
23
17
|
.describe("The OS version must be specified as a version number (e.g., '10', '14.0') or as a keyword such as 'latest' or 'oldest'. Normalize variations like 'newest' or 'most recent' to 'latest', and terms like 'earliest' or 'first' to 'oldest'. For macOS, version names (e.g., 'Sequoia') must be used instead of numeric versions."),
|
|
24
|
-
desiredBrowser:
|
|
18
|
+
desiredBrowser: z
|
|
25
19
|
.enum(["chrome", "firefox", "safari", "edge", "ie"])
|
|
26
20
|
.describe("Browser for desktop (Chrome, IE, Firefox, Safari, Edge)"),
|
|
27
|
-
desiredBrowserVersion:
|
|
21
|
+
desiredBrowserVersion: z
|
|
28
22
|
.string()
|
|
29
23
|
.optional()
|
|
30
24
|
.describe("Browser version for desktop (e.g. '133.2', 'latest'). If the user says 'latest', 'newest', or similar, normalize it to 'latest'. Likewise, convert terms like 'earliest' or 'oldest' to 'oldest'."),
|
|
31
|
-
desiredDevice:
|
|
25
|
+
desiredDevice: z.string().optional().describe("Device name for mobile"),
|
|
32
26
|
};
|
|
33
|
-
const LiveArgsSchema =
|
|
27
|
+
const LiveArgsSchema = z.object(LiveArgsShape);
|
|
34
28
|
/**
|
|
35
29
|
* Launches a desktop browser session
|
|
36
30
|
*/
|
|
@@ -39,8 +33,8 @@ async function launchDesktopSession(args) {
|
|
|
39
33
|
throw new Error("You must provide a desiredBrowser");
|
|
40
34
|
if (!args.desiredBrowserVersion)
|
|
41
35
|
throw new Error("You must provide a desiredBrowserVersion");
|
|
42
|
-
return
|
|
43
|
-
platformType:
|
|
36
|
+
return startBrowserSession({
|
|
37
|
+
platformType: PlatformType.DESKTOP,
|
|
44
38
|
url: args.desiredURL,
|
|
45
39
|
os: args.desiredOS,
|
|
46
40
|
osVersion: args.desiredOSVersion,
|
|
@@ -54,8 +48,8 @@ async function launchDesktopSession(args) {
|
|
|
54
48
|
async function launchMobileSession(args) {
|
|
55
49
|
if (!args.desiredDevice)
|
|
56
50
|
throw new Error("You must provide a desiredDevice");
|
|
57
|
-
return
|
|
58
|
-
platformType:
|
|
51
|
+
return startBrowserSession({
|
|
52
|
+
platformType: PlatformType.MOBILE,
|
|
59
53
|
browser: args.desiredBrowser,
|
|
60
54
|
url: args.desiredURL,
|
|
61
55
|
os: args.desiredOS,
|
|
@@ -70,7 +64,7 @@ async function runBrowserSession(rawArgs) {
|
|
|
70
64
|
// Validate and narrow
|
|
71
65
|
const args = LiveArgsSchema.parse(rawArgs);
|
|
72
66
|
// Branch desktop vs mobile and delegate
|
|
73
|
-
const launchUrl = args.platformType ===
|
|
67
|
+
const launchUrl = args.platformType === PlatformType.DESKTOP
|
|
74
68
|
? await launchDesktopSession(args)
|
|
75
69
|
: await launchMobileSession(args);
|
|
76
70
|
return {
|
|
@@ -82,15 +76,15 @@ async function runBrowserSession(rawArgs) {
|
|
|
82
76
|
],
|
|
83
77
|
};
|
|
84
78
|
}
|
|
85
|
-
function addBrowserLiveTools(server) {
|
|
79
|
+
export default function addBrowserLiveTools(server) {
|
|
86
80
|
server.tool("runBrowserLiveSession", "Launch a BrowserStack Live session (desktop or mobile).", LiveArgsShape, async (args) => {
|
|
87
81
|
try {
|
|
88
|
-
|
|
82
|
+
trackMCP("runBrowserLiveSession", server.server.getClientVersion());
|
|
89
83
|
return await runBrowserSession(args);
|
|
90
84
|
}
|
|
91
85
|
catch (error) {
|
|
92
|
-
|
|
93
|
-
|
|
86
|
+
logger.error("Live session failed: %s", error);
|
|
87
|
+
trackMCP("runBrowserLiveSession", server.server.getClientVersion(), error);
|
|
94
88
|
return {
|
|
95
89
|
content: [
|
|
96
90
|
{
|
|
@@ -1,16 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
exports.default = addObservabilityTools;
|
|
8
|
-
const zod_1 = require("zod");
|
|
9
|
-
const api_js_1 = require("../lib/api.js");
|
|
10
|
-
const instrumentation_js_1 = require("../lib/instrumentation.js");
|
|
11
|
-
const logger_js_1 = __importDefault(require("../logger.js"));
|
|
12
|
-
async function getFailuresInLastRun(buildName, projectName) {
|
|
13
|
-
const buildsData = await (0, api_js_1.getLatestO11YBuildInfo)(buildName, projectName);
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getLatestO11YBuildInfo } from "../lib/api.js";
|
|
3
|
+
import { trackMCP } from "../lib/instrumentation.js";
|
|
4
|
+
import logger from "../logger.js";
|
|
5
|
+
export async function getFailuresInLastRun(buildName, projectName) {
|
|
6
|
+
const buildsData = await getLatestO11YBuildInfo(buildName, projectName);
|
|
14
7
|
const observabilityUrl = buildsData.observability_url;
|
|
15
8
|
if (!observabilityUrl) {
|
|
16
9
|
throw new Error("No observability URL found in build data, this is likely because the build is not yet available on BrowserStack Observability.");
|
|
@@ -35,22 +28,22 @@ async function getFailuresInLastRun(buildName, projectName) {
|
|
|
35
28
|
],
|
|
36
29
|
};
|
|
37
30
|
}
|
|
38
|
-
function addObservabilityTools(server) {
|
|
31
|
+
export default function addObservabilityTools(server) {
|
|
39
32
|
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.", {
|
|
40
|
-
buildName:
|
|
33
|
+
buildName: z
|
|
41
34
|
.string()
|
|
42
35
|
.describe("Name of the build to get failures for. This is the 'build' key in the browserstack.yml file. If not sure, ask the user for the build name."),
|
|
43
|
-
projectName:
|
|
36
|
+
projectName: z
|
|
44
37
|
.string()
|
|
45
38
|
.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."),
|
|
46
39
|
}, async (args) => {
|
|
47
40
|
try {
|
|
48
|
-
|
|
41
|
+
trackMCP("getFailuresInLastRun", server.server.getClientVersion());
|
|
49
42
|
return await getFailuresInLastRun(args.buildName, args.projectName);
|
|
50
43
|
}
|
|
51
44
|
catch (error) {
|
|
52
|
-
|
|
53
|
-
|
|
45
|
+
logger.error("Failed to get failures in the last run: %s", error);
|
|
46
|
+
trackMCP("getFailuresInLastRun", server.server.getClientVersion(), error);
|
|
54
47
|
return {
|
|
55
48
|
content: [
|
|
56
49
|
{
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.SUPPORTED_CONFIGURATIONS = void 0;
|
|
7
|
-
const config_js_1 = __importDefault(require("../../config.js"));
|
|
1
|
+
import config from "../../config.js";
|
|
8
2
|
const nodejsInstructions = `
|
|
9
3
|
- Ensure that \`browserstack-node-sdk\` is present in package.json, use the latest version.
|
|
10
4
|
- Add new scripts to package.json for running tests on BrowserStack (use \`npx\` to trigger the sdk):
|
|
@@ -27,7 +21,7 @@ python3 -m pip install browserstack-sdk
|
|
|
27
21
|
|
|
28
22
|
Run the following command to setup the browserstack-sdk:
|
|
29
23
|
\`\`\`bash
|
|
30
|
-
browserstack-sdk setup --username "${
|
|
24
|
+
browserstack-sdk setup --username "${config.browserstackUsername}" --key "${config.browserstackAccessKey}"
|
|
31
25
|
\`\`\`
|
|
32
26
|
|
|
33
27
|
In order to run tests on BrowserStack, run the following command:
|
|
@@ -35,7 +29,7 @@ In order to run tests on BrowserStack, run the following command:
|
|
|
35
29
|
browserstack-sdk python <path-to-test-file>
|
|
36
30
|
\`\`\`
|
|
37
31
|
`;
|
|
38
|
-
|
|
32
|
+
export const SUPPORTED_CONFIGURATIONS = {
|
|
39
33
|
nodejs: {
|
|
40
34
|
playwright: {
|
|
41
35
|
jest: { instructions: nodejsInstructions },
|
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getInstructionsForProjectConfiguration = void 0;
|
|
4
|
-
exports.generateBrowserStackYMLInstructions = generateBrowserStackYMLInstructions;
|
|
5
|
-
const constants_js_1 = require("./constants.js");
|
|
1
|
+
import { SUPPORTED_CONFIGURATIONS } from "./constants.js";
|
|
6
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";
|
|
7
|
-
const getInstructionsForProjectConfiguration = (detectedBrowserAutomationFramework, detectedTestingFramework, detectedLanguage) => {
|
|
8
|
-
const configuration =
|
|
3
|
+
export const getInstructionsForProjectConfiguration = (detectedBrowserAutomationFramework, detectedTestingFramework, detectedLanguage) => {
|
|
4
|
+
const configuration = SUPPORTED_CONFIGURATIONS[detectedLanguage];
|
|
9
5
|
if (!configuration) {
|
|
10
6
|
throw new Error(`BrowserStack MCP Server currently does not support ${detectedLanguage}, ${errorMessageSuffix}`);
|
|
11
7
|
}
|
|
@@ -17,8 +13,7 @@ const getInstructionsForProjectConfiguration = (detectedBrowserAutomationFramewo
|
|
|
17
13
|
}
|
|
18
14
|
return configuration[detectedBrowserAutomationFramework][detectedTestingFramework].instructions;
|
|
19
15
|
};
|
|
20
|
-
|
|
21
|
-
function generateBrowserStackYMLInstructions(desiredPlatforms) {
|
|
16
|
+
export function generateBrowserStackYMLInstructions(desiredPlatforms) {
|
|
22
17
|
return `
|
|
23
18
|
Create a browserstack.yml file in the project root. The file should be in the following format:
|
|
24
19
|
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
|
+
export {};
|
|
@@ -1,26 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.fetchFormFields = fetchFormFields;
|
|
7
|
-
exports.triggerTestCaseGeneration = triggerTestCaseGeneration;
|
|
8
|
-
exports.fetchTestCaseDetails = fetchTestCaseDetails;
|
|
9
|
-
exports.pollTestCaseDetails = pollTestCaseDetails;
|
|
10
|
-
exports.pollScenariosTestDetails = pollScenariosTestDetails;
|
|
11
|
-
exports.bulkCreateTestCases = bulkCreateTestCases;
|
|
12
|
-
exports.projectIdentifierToId = projectIdentifierToId;
|
|
13
|
-
const axios_1 = __importDefault(require("axios"));
|
|
14
|
-
const config_js_1 = require("./config.js");
|
|
15
|
-
const helpers_js_1 = require("./helpers.js");
|
|
16
|
-
const config_js_2 = __importDefault(require("../../../config.js"));
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { TCG_TRIGGER_URL, TCG_POLL_URL, FETCH_DETAILS_URL, FORM_FIELDS_URL, BULK_CREATE_URL, } from "./config.js";
|
|
3
|
+
import { createTestCasePayload } from "./helpers.js";
|
|
4
|
+
import config from "../../../config.js";
|
|
17
5
|
/**
|
|
18
6
|
* Fetch default and custom form fields for a project.
|
|
19
7
|
*/
|
|
20
|
-
async function fetchFormFields(projectId) {
|
|
21
|
-
const res = await
|
|
8
|
+
export async function fetchFormFields(projectId) {
|
|
9
|
+
const res = await axios.get(FORM_FIELDS_URL(projectId), {
|
|
22
10
|
headers: {
|
|
23
|
-
"API-TOKEN": `${
|
|
11
|
+
"API-TOKEN": `${config.browserstackUsername}:${config.browserstackAccessKey}`,
|
|
24
12
|
},
|
|
25
13
|
});
|
|
26
14
|
return res.data;
|
|
@@ -28,8 +16,8 @@ async function fetchFormFields(projectId) {
|
|
|
28
16
|
/**
|
|
29
17
|
* Trigger AI-based test case generation for a document.
|
|
30
18
|
*/
|
|
31
|
-
async function triggerTestCaseGeneration(document, documentId, folderId, projectId, source) {
|
|
32
|
-
const res = await
|
|
19
|
+
export async function triggerTestCaseGeneration(document, documentId, folderId, projectId, source) {
|
|
20
|
+
const res = await axios.post(TCG_TRIGGER_URL, {
|
|
33
21
|
document,
|
|
34
22
|
documentId,
|
|
35
23
|
folderId,
|
|
@@ -38,7 +26,7 @@ async function triggerTestCaseGeneration(document, documentId, folderId, project
|
|
|
38
26
|
webhookUrl: `https://test-management.browserstack.com/api/v1/projects/${projectId}/folder/${folderId}/webhooks/tcg`,
|
|
39
27
|
}, {
|
|
40
28
|
headers: {
|
|
41
|
-
"API-TOKEN": `${
|
|
29
|
+
"API-TOKEN": `${config.browserstackUsername}:${config.browserstackAccessKey}`,
|
|
42
30
|
"Content-Type": "application/json",
|
|
43
31
|
"request-source": source,
|
|
44
32
|
},
|
|
@@ -51,18 +39,18 @@ async function triggerTestCaseGeneration(document, documentId, folderId, project
|
|
|
51
39
|
/**
|
|
52
40
|
* Initiate a fetch for test-case details; returns the traceRequestId for polling.
|
|
53
41
|
*/
|
|
54
|
-
async function fetchTestCaseDetails(documentId, folderId, projectId, testCaseIds, source) {
|
|
42
|
+
export async function fetchTestCaseDetails(documentId, folderId, projectId, testCaseIds, source) {
|
|
55
43
|
if (testCaseIds.length === 0) {
|
|
56
44
|
throw new Error("No testCaseIds provided to fetchTestCaseDetails");
|
|
57
45
|
}
|
|
58
|
-
const res = await
|
|
46
|
+
const res = await axios.post(FETCH_DETAILS_URL, {
|
|
59
47
|
document_id: documentId,
|
|
60
48
|
folder_id: folderId,
|
|
61
49
|
project_id: projectId,
|
|
62
50
|
test_case_ids: testCaseIds,
|
|
63
51
|
}, {
|
|
64
52
|
headers: {
|
|
65
|
-
"API-TOKEN": `${
|
|
53
|
+
"API-TOKEN": `${config.browserstackUsername}:${config.browserstackAccessKey}`,
|
|
66
54
|
"request-source": source,
|
|
67
55
|
"Content-Type": "application/json",
|
|
68
56
|
},
|
|
@@ -75,15 +63,15 @@ async function fetchTestCaseDetails(documentId, folderId, projectId, testCaseIds
|
|
|
75
63
|
/**
|
|
76
64
|
* Poll for a given traceRequestId until all test-case details are returned.
|
|
77
65
|
*/
|
|
78
|
-
async function pollTestCaseDetails(traceRequestId) {
|
|
66
|
+
export async function pollTestCaseDetails(traceRequestId) {
|
|
79
67
|
const detailMap = {};
|
|
80
68
|
let done = false;
|
|
81
69
|
while (!done) {
|
|
82
70
|
// add a bit of jitter to avoid synchronized polling storms
|
|
83
71
|
await new Promise((r) => setTimeout(r, 10000 + Math.random() * 5000));
|
|
84
|
-
const poll = await
|
|
72
|
+
const poll = await axios.post(`${TCG_POLL_URL}?x-bstack-traceRequestId=${encodeURIComponent(traceRequestId)}`, {}, {
|
|
85
73
|
headers: {
|
|
86
|
-
"API-TOKEN": `${
|
|
74
|
+
"API-TOKEN": `${config.browserstackUsername}:${config.browserstackAccessKey}`,
|
|
87
75
|
},
|
|
88
76
|
});
|
|
89
77
|
if (!poll.data.data.success) {
|
|
@@ -108,7 +96,7 @@ async function pollTestCaseDetails(traceRequestId) {
|
|
|
108
96
|
/**
|
|
109
97
|
* Poll for scenarios & testcases, trigger detail fetches, then poll all details in parallel.
|
|
110
98
|
*/
|
|
111
|
-
async function pollScenariosTestDetails(args, traceId, context, documentId, source) {
|
|
99
|
+
export async function pollScenariosTestDetails(args, traceId, context, documentId, source) {
|
|
112
100
|
const { folderId, projectReferenceId } = args;
|
|
113
101
|
const scenariosMap = {};
|
|
114
102
|
const detailPromises = [];
|
|
@@ -117,9 +105,9 @@ async function pollScenariosTestDetails(args, traceId, context, documentId, sour
|
|
|
117
105
|
await new Promise((resolve, reject) => {
|
|
118
106
|
const intervalId = setInterval(async () => {
|
|
119
107
|
try {
|
|
120
|
-
const poll = await
|
|
108
|
+
const poll = await axios.post(`${TCG_POLL_URL}?x-bstack-traceRequestId=${encodeURIComponent(traceId)}`, {}, {
|
|
121
109
|
headers: {
|
|
122
|
-
"API-TOKEN": `${
|
|
110
|
+
"API-TOKEN": `${config.browserstackUsername}:${config.browserstackAccessKey}`,
|
|
123
111
|
},
|
|
124
112
|
});
|
|
125
113
|
if (poll.status !== 200) {
|
|
@@ -201,7 +189,7 @@ async function pollScenariosTestDetails(args, traceId, context, documentId, sour
|
|
|
201
189
|
/**
|
|
202
190
|
* Bulk-create generated test cases in BrowserStack.
|
|
203
191
|
*/
|
|
204
|
-
async function bulkCreateTestCases(scenariosMap, projectId, folderId, fieldMaps, booleanFieldId, traceId, context, documentId) {
|
|
192
|
+
export async function bulkCreateTestCases(scenariosMap, projectId, folderId, fieldMaps, booleanFieldId, traceId, context, documentId) {
|
|
205
193
|
const results = {};
|
|
206
194
|
const total = Object.keys(scenariosMap).length;
|
|
207
195
|
let doneCount = 0;
|
|
@@ -212,12 +200,12 @@ async function bulkCreateTestCases(scenariosMap, projectId, folderId, fieldMaps,
|
|
|
212
200
|
if (testCaseLength === 0)
|
|
213
201
|
continue;
|
|
214
202
|
const payload = {
|
|
215
|
-
test_cases: testcases.map((tc) =>
|
|
203
|
+
test_cases: testcases.map((tc) => createTestCasePayload(tc, id, folderId, fieldMaps, documentId, booleanFieldId, traceId)),
|
|
216
204
|
};
|
|
217
205
|
try {
|
|
218
|
-
const resp = await
|
|
206
|
+
const resp = await axios.post(BULK_CREATE_URL(projectId, folderId), payload, {
|
|
219
207
|
headers: {
|
|
220
|
-
"API-TOKEN": `${
|
|
208
|
+
"API-TOKEN": `${config.browserstackUsername}:${config.browserstackAccessKey}`,
|
|
221
209
|
"Content-Type": "application/json",
|
|
222
210
|
},
|
|
223
211
|
});
|
|
@@ -251,11 +239,11 @@ async function bulkCreateTestCases(scenariosMap, projectId, folderId, fieldMaps,
|
|
|
251
239
|
const resultString = `Total of ${testCaseCount} test cases created in ${total} scenarios.`;
|
|
252
240
|
return resultString;
|
|
253
241
|
}
|
|
254
|
-
async function projectIdentifierToId(projectId) {
|
|
242
|
+
export async function projectIdentifierToId(projectId) {
|
|
255
243
|
const url = `https://test-management.browserstack.com/api/v1/projects/?q=${projectId}`;
|
|
256
|
-
const response = await
|
|
244
|
+
const response = await axios.get(url, {
|
|
257
245
|
headers: {
|
|
258
|
-
"API-TOKEN": `${
|
|
246
|
+
"API-TOKEN": `${config.browserstackUsername}:${config.browserstackAccessKey}`,
|
|
259
247
|
accept: "application/json, text/plain, */*",
|
|
260
248
|
},
|
|
261
249
|
});
|
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
exports.FETCH_DETAILS_URL = "https://test-management.browserstack.com/api/v1/integration/tcg/test-generation/fetch-test-case-details";
|
|
7
|
-
const FORM_FIELDS_URL = (projectId) => `https://test-management.browserstack.com/api/v1/projects/${projectId}/form-fields-v2`;
|
|
8
|
-
exports.FORM_FIELDS_URL = FORM_FIELDS_URL;
|
|
9
|
-
const BULK_CREATE_URL = (projectId, folderId) => `https://test-management.browserstack.com/api/v1/projects/${projectId}/folder/${folderId}/bulk-test-cases`;
|
|
10
|
-
exports.BULK_CREATE_URL = BULK_CREATE_URL;
|
|
1
|
+
export const TCG_TRIGGER_URL = "https://test-management.browserstack.com/api/v1/integration/tcg/test-generation/suggest-test-cases";
|
|
2
|
+
export const TCG_POLL_URL = "https://test-management.browserstack.com/api/v1/integration/tcg/test-generation/test-cases-polling";
|
|
3
|
+
export const FETCH_DETAILS_URL = "https://test-management.browserstack.com/api/v1/integration/tcg/test-generation/fetch-test-case-details";
|
|
4
|
+
export const FORM_FIELDS_URL = (projectId) => `https://test-management.browserstack.com/api/v1/projects/${projectId}/form-fields-v2`;
|
|
5
|
+
export const BULK_CREATE_URL = (projectId, folderId) => `https://test-management.browserstack.com/api/v1/projects/${projectId}/folder/${folderId}/bulk-test-cases`;
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.buildDefaultFieldMaps = buildDefaultFieldMaps;
|
|
4
|
-
exports.findBooleanFieldId = findBooleanFieldId;
|
|
5
|
-
exports.createTestCasePayload = createTestCasePayload;
|
|
6
1
|
/**
|
|
7
2
|
* Build mappings for default fields for priority, status, and case type.
|
|
8
3
|
*/
|
|
9
|
-
function buildDefaultFieldMaps(defaultFields) {
|
|
4
|
+
export function buildDefaultFieldMaps(defaultFields) {
|
|
10
5
|
const priority = Object.fromEntries(defaultFields.priority.values.map((v) => [
|
|
11
6
|
v.name.toLowerCase(),
|
|
12
7
|
v.value,
|
|
@@ -18,14 +13,14 @@ function buildDefaultFieldMaps(defaultFields) {
|
|
|
18
13
|
/**
|
|
19
14
|
* Find a boolean custom field ID if present.
|
|
20
15
|
*/
|
|
21
|
-
function findBooleanFieldId(customFields) {
|
|
16
|
+
export function findBooleanFieldId(customFields) {
|
|
22
17
|
const boolField = customFields.find((f) => f.field_type === "field_boolean");
|
|
23
18
|
return boolField?.id;
|
|
24
19
|
}
|
|
25
20
|
/**
|
|
26
21
|
* Construct payload for creating a single test case in bulk.
|
|
27
22
|
*/
|
|
28
|
-
function createTestCasePayload(tc, scenarioId, folderId, fieldMaps, documentId, booleanFieldId, traceId) {
|
|
23
|
+
export function createTestCasePayload(tc, scenarioId, folderId, fieldMaps, documentId, booleanFieldId, traceId) {
|
|
29
24
|
const pri = tc.priority ?? "Medium";
|
|
30
25
|
const stat = fieldMaps.status["active"];
|
|
31
26
|
const ct = fieldMaps.caseType["functional"];
|
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
documentId: zod_1.z.string().describe("Internal document identifier"),
|
|
7
|
-
folderId: zod_1.z.string().describe("BrowserStack folder ID"),
|
|
8
|
-
projectReferenceId: zod_1.z
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const CreateTestCasesFromFileSchema = z.object({
|
|
3
|
+
documentId: z.string().describe("Internal document identifier"),
|
|
4
|
+
folderId: z.string().describe("BrowserStack folder ID"),
|
|
5
|
+
projectReferenceId: z
|
|
9
6
|
.string()
|
|
10
7
|
.describe("The BrowserStack project reference ID is a unique identifier found in the project URL within the BrowserStack Test Management Platform. This ID is also returned by the Upload Document tool."),
|
|
11
8
|
});
|
|
@@ -1,50 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.AddTestResultSchema = void 0;
|
|
7
|
-
exports.addTestResult = addTestResult;
|
|
8
|
-
const axios_1 = __importDefault(require("axios"));
|
|
9
|
-
const config_js_1 = __importDefault(require("../../config.js"));
|
|
10
|
-
const zod_1 = require("zod");
|
|
11
|
-
const error_js_1 = require("../../lib/error.js");
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import config from "../../config.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { formatAxiosError } from "../../lib/error.js";
|
|
12
5
|
/**
|
|
13
6
|
* Schema for adding a test result to a test run.
|
|
14
7
|
*/
|
|
15
|
-
|
|
16
|
-
project_identifier:
|
|
8
|
+
export const AddTestResultSchema = z.object({
|
|
9
|
+
project_identifier: z
|
|
17
10
|
.string()
|
|
18
11
|
.describe("Identifier of the project (Starts with 'PR-')"),
|
|
19
|
-
test_run_id:
|
|
20
|
-
test_result:
|
|
21
|
-
status:
|
|
12
|
+
test_run_id: z.string().describe("Identifier of the test run (e.g., TR-678)"),
|
|
13
|
+
test_result: z.object({
|
|
14
|
+
status: z
|
|
22
15
|
.string()
|
|
23
16
|
.describe("Status of the test result, e.g., 'passed', 'failed'."),
|
|
24
|
-
description:
|
|
17
|
+
description: z
|
|
25
18
|
.string()
|
|
26
19
|
.optional()
|
|
27
20
|
.describe("Optional description of the test result."),
|
|
28
21
|
}),
|
|
29
|
-
test_case_id:
|
|
22
|
+
test_case_id: z
|
|
30
23
|
.string()
|
|
31
24
|
.describe("Identifier of the test case, e.g., 'TC-13'."),
|
|
32
25
|
});
|
|
33
26
|
/**
|
|
34
27
|
* Adds a test result to a specific test run via BrowserStack Test Management API.
|
|
35
28
|
*/
|
|
36
|
-
async function addTestResult(rawArgs) {
|
|
29
|
+
export async function addTestResult(rawArgs) {
|
|
37
30
|
try {
|
|
38
|
-
const args =
|
|
31
|
+
const args = AddTestResultSchema.parse(rawArgs);
|
|
39
32
|
const url = `https://test-management.browserstack.com/api/v2/projects/${encodeURIComponent(args.project_identifier)}/test-runs/${encodeURIComponent(args.test_run_id)}/results`;
|
|
40
33
|
const body = {
|
|
41
34
|
test_result: args.test_result,
|
|
42
35
|
test_case_id: args.test_case_id,
|
|
43
36
|
};
|
|
44
|
-
const response = await
|
|
37
|
+
const response = await axios.post(url, body, {
|
|
45
38
|
auth: {
|
|
46
|
-
username:
|
|
47
|
-
password:
|
|
39
|
+
username: config.browserstackUsername,
|
|
40
|
+
password: config.browserstackAccessKey,
|
|
48
41
|
},
|
|
49
42
|
headers: { "Content-Type": "application/json" },
|
|
50
43
|
});
|
|
@@ -63,6 +56,6 @@ async function addTestResult(rawArgs) {
|
|
|
63
56
|
};
|
|
64
57
|
}
|
|
65
58
|
catch (err) {
|
|
66
|
-
return
|
|
59
|
+
return formatAxiosError(err, "Failed to add test result to test run");
|
|
67
60
|
}
|
|
68
61
|
}
|
|
@@ -1,34 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.CreateProjFoldSchema = void 0;
|
|
7
|
-
exports.createProjectOrFolder = createProjectOrFolder;
|
|
8
|
-
const axios_1 = __importDefault(require("axios"));
|
|
9
|
-
const config_js_1 = __importDefault(require("../../config.js"));
|
|
10
|
-
const zod_1 = require("zod");
|
|
11
|
-
const error_js_1 = require("../../lib/error.js"); // or correct path
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import config from "../../config.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { formatAxiosError } from "../../lib/error.js"; // or correct path
|
|
12
5
|
// Schema for combined project/folder creation
|
|
13
|
-
|
|
14
|
-
project_name:
|
|
6
|
+
export const CreateProjFoldSchema = z.object({
|
|
7
|
+
project_name: z
|
|
15
8
|
.string()
|
|
16
9
|
.optional()
|
|
17
10
|
.describe("Name of the project to create."),
|
|
18
|
-
project_description:
|
|
11
|
+
project_description: z
|
|
19
12
|
.string()
|
|
20
13
|
.optional()
|
|
21
14
|
.describe("Description for the new project."),
|
|
22
|
-
project_identifier:
|
|
15
|
+
project_identifier: z
|
|
23
16
|
.string()
|
|
24
17
|
.optional()
|
|
25
18
|
.describe("Existing project identifier to use for folder creation."),
|
|
26
|
-
folder_name:
|
|
27
|
-
folder_description:
|
|
19
|
+
folder_name: z.string().optional().describe("Name of the folder to create."),
|
|
20
|
+
folder_description: z
|
|
28
21
|
.string()
|
|
29
22
|
.optional()
|
|
30
23
|
.describe("Description for the new folder."),
|
|
31
|
-
parent_id:
|
|
24
|
+
parent_id: z
|
|
32
25
|
.number()
|
|
33
26
|
.optional()
|
|
34
27
|
.describe("Parent folder ID; if omitted, folder is created at root."),
|
|
@@ -36,8 +29,8 @@ exports.CreateProjFoldSchema = zod_1.z.object({
|
|
|
36
29
|
/**
|
|
37
30
|
* Creates a project and/or folder in BrowserStack Test Management.
|
|
38
31
|
*/
|
|
39
|
-
async function createProjectOrFolder(args) {
|
|
40
|
-
const { project_name, project_description, project_identifier, folder_name, folder_description, parent_id, } =
|
|
32
|
+
export async function createProjectOrFolder(args) {
|
|
33
|
+
const { project_name, project_description, project_identifier, folder_name, folder_description, parent_id, } = CreateProjFoldSchema.parse(args);
|
|
41
34
|
if (!project_name && !project_identifier && !folder_name) {
|
|
42
35
|
throw new Error("Provide project_name (to create project), or project_identifier and folder_name (to create folder).");
|
|
43
36
|
}
|
|
@@ -45,10 +38,10 @@ async function createProjectOrFolder(args) {
|
|
|
45
38
|
// Step 1: Create project if project_name provided
|
|
46
39
|
if (project_name) {
|
|
47
40
|
try {
|
|
48
|
-
const res = await
|
|
41
|
+
const res = await axios.post("https://test-management.browserstack.com/api/v2/projects", { project: { name: project_name, description: project_description } }, {
|
|
49
42
|
auth: {
|
|
50
|
-
username:
|
|
51
|
-
password:
|
|
43
|
+
username: config.browserstackUsername,
|
|
44
|
+
password: config.browserstackAccessKey,
|
|
52
45
|
},
|
|
53
46
|
headers: { "Content-Type": "application/json" },
|
|
54
47
|
});
|
|
@@ -59,7 +52,7 @@ async function createProjectOrFolder(args) {
|
|
|
59
52
|
projId = res.data.project.identifier;
|
|
60
53
|
}
|
|
61
54
|
catch (err) {
|
|
62
|
-
return
|
|
55
|
+
return formatAxiosError(err, "Failed to create project..");
|
|
63
56
|
}
|
|
64
57
|
}
|
|
65
58
|
// Step 2: Create folder if folder_name provided
|
|
@@ -67,7 +60,7 @@ async function createProjectOrFolder(args) {
|
|
|
67
60
|
if (!projId)
|
|
68
61
|
throw new Error("Cannot create folder without project_identifier.");
|
|
69
62
|
try {
|
|
70
|
-
const res = await
|
|
63
|
+
const res = await axios.post(`https://test-management.browserstack.com/api/v2/projects/${encodeURIComponent(projId)}/folders`, {
|
|
71
64
|
folder: {
|
|
72
65
|
name: folder_name,
|
|
73
66
|
description: folder_description,
|
|
@@ -75,8 +68,8 @@ async function createProjectOrFolder(args) {
|
|
|
75
68
|
},
|
|
76
69
|
}, {
|
|
77
70
|
auth: {
|
|
78
|
-
username:
|
|
79
|
-
password:
|
|
71
|
+
username: config.browserstackUsername,
|
|
72
|
+
password: config.browserstackAccessKey,
|
|
80
73
|
},
|
|
81
74
|
headers: { "Content-Type": "application/json" },
|
|
82
75
|
});
|
|
@@ -95,7 +88,7 @@ async function createProjectOrFolder(args) {
|
|
|
95
88
|
};
|
|
96
89
|
}
|
|
97
90
|
catch (err) {
|
|
98
|
-
return
|
|
91
|
+
return formatAxiosError(err, "Failed to create folder.");
|
|
99
92
|
}
|
|
100
93
|
}
|
|
101
94
|
// Only project was created
|