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