@smartbear/mcp 0.9.0 → 0.11.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.
Files changed (64) hide show
  1. package/README.md +38 -11
  2. package/dist/bugsnag/client/api/index.js +2 -0
  3. package/dist/bugsnag/client/filters.js +0 -6
  4. package/dist/bugsnag/client.js +238 -380
  5. package/dist/bugsnag/input-schemas.js +51 -0
  6. package/dist/collaborator/client.js +377 -0
  7. package/dist/common/cache.js +63 -0
  8. package/dist/common/client-registry.js +128 -0
  9. package/dist/common/register-clients.js +31 -0
  10. package/dist/common/server.js +77 -28
  11. package/dist/common/transport-http.js +377 -0
  12. package/dist/common/transport-stdio.js +43 -0
  13. package/dist/index.js +18 -60
  14. package/dist/pactflow/client/tools.js +4 -4
  15. package/dist/pactflow/client.js +39 -19
  16. package/dist/qmetry/client/auto-resolve.js +22 -0
  17. package/dist/qmetry/client/handlers.js +18 -4
  18. package/dist/qmetry/client/issues.js +98 -1
  19. package/dist/qmetry/client/project.js +18 -1
  20. package/dist/qmetry/client/testcase.js +79 -1
  21. package/dist/qmetry/client/testsuite.js +156 -1
  22. package/dist/qmetry/client/tools/index.js +17 -0
  23. package/dist/qmetry/client/tools/issue-tools.js +545 -0
  24. package/dist/qmetry/client/tools/project-tools.js +348 -0
  25. package/dist/qmetry/client/tools/requirement-tools.js +530 -0
  26. package/dist/qmetry/client/tools/testcase-tools.js +526 -0
  27. package/dist/qmetry/client/tools/testsuite-tools.js +772 -0
  28. package/dist/qmetry/client/tools/types.js +1 -0
  29. package/dist/qmetry/client.js +33 -11
  30. package/dist/qmetry/config/constants.js +14 -0
  31. package/dist/qmetry/config/rest-endpoints.js +10 -0
  32. package/dist/qmetry/types/common.js +287 -2
  33. package/dist/qmetry/types/issues.js +11 -1
  34. package/dist/qmetry/types/project.js +7 -0
  35. package/dist/qmetry/types/testcase.js +6 -0
  36. package/dist/qmetry/types/testsuite.js +19 -1
  37. package/dist/reflect/client.js +10 -4
  38. package/dist/{api-hub → swagger}/client/api.js +190 -2
  39. package/dist/{api-hub → swagger}/client/configuration.js +6 -1
  40. package/dist/swagger/client/index.js +6 -0
  41. package/dist/{api-hub → swagger}/client/portal-types.js +126 -0
  42. package/dist/swagger/client/tools.js +161 -0
  43. package/dist/swagger/client/user-management-types.js +24 -0
  44. package/dist/swagger/client.js +141 -0
  45. package/dist/swagger/config-utils.js +18 -0
  46. package/dist/zephyr/client.js +44 -6
  47. package/dist/zephyr/common/api-client.js +8 -0
  48. package/dist/zephyr/common/rest-api-schemas.js +5174 -0
  49. package/dist/zephyr/tool/priority/get-priorities.js +43 -0
  50. package/dist/zephyr/tool/project/get-project.js +39 -0
  51. package/dist/zephyr/tool/project/get-projects.js +7 -13
  52. package/dist/zephyr/tool/status/get-statuses.js +49 -0
  53. package/dist/zephyr/tool/test-case/get-test-case.js +39 -0
  54. package/dist/zephyr/tool/test-case/get-test-cases.js +64 -0
  55. package/dist/zephyr/tool/test-cycle/get-test-cycle.js +39 -0
  56. package/dist/zephyr/tool/test-cycle/get-test-cycles.js +72 -0
  57. package/dist/zephyr/tool/test-execution/get-test-execution.js +39 -0
  58. package/package.json +2 -2
  59. package/dist/api-hub/client/index.js +0 -5
  60. package/dist/api-hub/client/tools.js +0 -104
  61. package/dist/api-hub/client.js +0 -98
  62. package/dist/qmetry/client/tools.js +0 -1673
  63. package/dist/zephyr/common/types.js +0 -35
  64. /package/dist/{api-hub → swagger}/client/registry-types.js +0 -0
package/dist/index.js CHANGED
@@ -1,13 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
- import { ApiHubClient } from "./api-hub/client.js";
4
- import { BugsnagClient } from "./bugsnag/client.js";
5
2
  import Bugsnag from "./common/bugsnag.js";
6
- import { SmartBearMcpServer } from "./common/server.js";
7
- import { PactflowClient } from "./pactflow/client.js";
8
- import { QmetryClient } from "./qmetry/client.js";
9
- import { ReflectClient } from "./reflect/client.js";
10
- import { ZephyrClient } from "./zephyr/client.js";
3
+ import "./common/register-clients.js"; // Register all available clients
4
+ import { runHttpMode } from "./common/transport-http.js";
5
+ import { runStdioMode } from "./common/transport-stdio.js";
11
6
  // This is used to report errors in the MCP server itself
12
7
  // If you want to use your own BugSnag API key, set the MCP_SERVER_BUGSNAG_API_KEY environment variable
13
8
  const McpServerBugsnagAPIKey = process.env.MCP_SERVER_BUGSNAG_API_KEY;
@@ -15,62 +10,25 @@ if (McpServerBugsnagAPIKey) {
15
10
  Bugsnag.start(McpServerBugsnagAPIKey);
16
11
  }
17
12
  async function main() {
18
- const server = new SmartBearMcpServer();
19
- const reflectToken = process.env.REFLECT_API_TOKEN;
20
- const bugsnagToken = process.env.BUGSNAG_AUTH_TOKEN;
21
- const apiHubToken = process.env.API_HUB_API_KEY;
22
- const pactBrokerToken = process.env.PACT_BROKER_TOKEN;
23
- const pactBrokerUrl = process.env.PACT_BROKER_BASE_URL;
24
- const pactBrokerUsername = process.env.PACT_BROKER_USERNAME;
25
- const pactBrokerPassword = process.env.PACT_BROKER_PASSWORD;
26
- const qmetryToken = process.env.QMETRY_API_KEY;
27
- const qmetryBaseUrl = process.env.QMETRY_BASE_URL;
28
- const zephyrToken = process.env.ZEPHYR_API_TOKEN;
29
- const zephyrBaseUrl = process.env.ZEPHYR_BASE_URL;
30
- let client_defined = false;
31
- if (reflectToken) {
32
- server.addClient(new ReflectClient(reflectToken));
33
- client_defined = true;
13
+ // Determine transport mode from environment variable
14
+ // MCP_TRANSPORT can be "stdio" (default) or "http"
15
+ const transportMode = process.env.MCP_TRANSPORT?.toLowerCase() || "stdio";
16
+ if (transportMode === "http") {
17
+ console.log("[MCP] Starting in HTTP mode...");
18
+ await runHttpMode();
34
19
  }
35
- if (bugsnagToken) {
36
- const bugsnagClient = new BugsnagClient(bugsnagToken, process.env.BUGSNAG_PROJECT_API_KEY, process.env.BUGSNAG_ENDPOINT);
37
- await bugsnagClient.initialize();
38
- server.addClient(bugsnagClient);
39
- client_defined = true;
20
+ else if (transportMode === "stdio") {
21
+ await runStdioMode();
40
22
  }
41
- if (apiHubToken) {
42
- server.addClient(new ApiHubClient(apiHubToken));
43
- client_defined = true;
44
- }
45
- if (pactBrokerUrl) {
46
- if (pactBrokerToken) {
47
- server.addClient(new PactflowClient(pactBrokerToken, pactBrokerUrl, "pactflow", server.server));
48
- client_defined = true;
49
- }
50
- else if (pactBrokerUsername && pactBrokerPassword) {
51
- server.addClient(new PactflowClient({ username: pactBrokerUsername, password: pactBrokerPassword }, pactBrokerUrl, "pact_broker", server.server));
52
- client_defined = true;
53
- }
54
- else {
55
- console.error("If the Pact Broker base URL is specified, you must specify either (a) a PactFlow token, or (b) a Pact Broker username and password pair.");
56
- }
57
- }
58
- if (qmetryToken) {
59
- server.addClient(new QmetryClient(qmetryToken, qmetryBaseUrl));
60
- client_defined = true;
61
- }
62
- if (zephyrToken) {
63
- server.addClient(new ZephyrClient(zephyrToken, zephyrBaseUrl));
64
- client_defined = true;
65
- }
66
- if (!client_defined) {
67
- console.error("Please set one of REFLECT_API_TOKEN, BUGSNAG_AUTH_TOKEN, API_HUB_API_KEY, QMETRY_API_KEY, ZEPHYR_API_TOKEN, or PACT_BROKER_BASE_URL / (and relevant Pact auth) environment variables");
23
+ else {
24
+ console.error(`[MCP] Invalid transport mode: ${transportMode}. Use "stdio" or "http".`);
68
25
  process.exit(1);
69
26
  }
70
- const transport = new StdioServerTransport();
71
- await server.connect(transport);
72
27
  }
73
- main().catch((error) => {
28
+ try {
29
+ await main();
30
+ }
31
+ catch (error) {
74
32
  console.error("Fatal error in main():", error);
75
33
  process.exit(1);
76
- });
34
+ }
@@ -17,7 +17,7 @@ export const TOOLS = [
17
17
  title: "Generate Pact Tests",
18
18
  summary: "Generate Pact tests using PactFlow AI. You can provide one or more of the following input types: (1) request/response pairs for specific interactions, (2) code files to analyze and extract interactions from, and/or (3) OpenAPI document to generate tests for specific endpoints. When providing an OpenAPI document, a matcher is required to specify which endpoints to generate tests for.",
19
19
  purpose: "Generate Pact tests for API interactions",
20
- zodSchema: GenerationInputSchema,
20
+ inputSchema: GenerationInputSchema,
21
21
  handler: "generate",
22
22
  clients: ["pactflow"], // ONLY pactflow
23
23
  enableElicitation: true,
@@ -26,7 +26,7 @@ export const TOOLS = [
26
26
  title: "Review Pact Tests",
27
27
  summary: "Review Pact tests using PactFlow AI. You can provide the following inputs: (1) Pact tests to be reviewed along with metadata",
28
28
  purpose: "Review Pact tests for API interactions",
29
- zodSchema: RefineInputSchema,
29
+ inputSchema: RefineInputSchema,
30
30
  handler: "review",
31
31
  clients: ["pactflow"],
32
32
  enableElicitation: true,
@@ -50,7 +50,7 @@ export const TOOLS = [
50
50
  title: "Can I Deploy",
51
51
  summary: "Performs a comprehensive compatibility check to determine whether a specific version of a service (pacticipant) can be safely deployed into a given environment. It analyzes the complete contract matrix of consumer-provider relationships to confirm that all required integrations are verified and compatible.",
52
52
  purpose: "To serve as a deployment safety check within the PactBroker and PactFlow ecosystem, leveraging contract testing results to validate whether a specific service / pacticipant version is compatible with all integrated services. This feature prevents unsafe releases, reduces integration risks, and enables teams to confidently automate deployments across environments with a clear, auditable record of verification results.",
53
- zodSchema: CanIDeploySchema,
53
+ inputSchema: CanIDeploySchema,
54
54
  handler: "canIDeploy",
55
55
  clients: ["pactflow", "pact_broker"],
56
56
  },
@@ -66,7 +66,7 @@ export const TOOLS = [
66
66
  "Support informed deployment decisions by answering 'can I deploy version X of this service to production?'",
67
67
  "Expose contract verification details to non-frequent API users in a more accessible format.",
68
68
  ],
69
- zodSchema: MatrixSchema,
69
+ inputSchema: MatrixSchema,
70
70
  handler: "getMatrix",
71
71
  clients: ["pactflow", "pact_broker"],
72
72
  },
@@ -1,46 +1,66 @@
1
+ import z from "zod";
1
2
  import { MCP_SERVER_NAME, MCP_SERVER_VERSION } from "../common/info.js";
2
3
  import { ToolError, } from "../common/types.js";
3
4
  import { getOADMatcherRecommendations, getUserMatcherSelection, } from "./client/prompt-utils.js";
4
5
  import { PROMPTS } from "./client/prompts.js";
5
6
  import { TOOLS } from "./client/tools.js";
7
+ const ConfigurationSchema = z.object({
8
+ base_url: z.string().url().describe("Pact Broker or PactFlow base URL"),
9
+ token: z
10
+ .string()
11
+ .optional()
12
+ .describe("Bearer token for PactFlow authentication (use this OR username/password)"),
13
+ username: z.string().optional().describe("Username for Pact Broker"),
14
+ password: z.string().optional().describe("Password for Pact Broker"),
15
+ });
6
16
  // Tool definitions for PactFlow AI API client
7
17
  export class PactflowClient {
8
18
  name = "Contract Testing";
9
- prefix = "contract-testing";
19
+ toolPrefix = "contract-testing";
20
+ configPrefix = "Pact-Broker";
21
+ config = ConfigurationSchema;
10
22
  headers;
11
23
  aiBaseUrl;
12
24
  baseUrl;
13
- clientType;
14
- server;
15
- /**
16
- * Creates an instance of the PactflowClient.
17
- *
18
- * @param auth The authentication token or credentials.
19
- * @param baseUrl The base URL for the API.
20
- * @param clientType The type of client (e.g., PactFlow, Pact Broker).
21
- * @param server The SmartBear MCP server instance.
22
- */
23
- constructor(auth, baseUrl, clientType, server) {
25
+ _clientType;
26
+ _server;
27
+ get server() {
28
+ if (!this._server)
29
+ throw new Error("Server not configured");
30
+ return this._server;
31
+ }
32
+ get clientType() {
33
+ if (!this._clientType)
34
+ throw new Error("Client not configured");
35
+ return this._clientType;
36
+ }
37
+ async configure(server, config) {
24
38
  // Set headers based on the type of auth provided
25
- if (typeof auth === "string") {
39
+ if (typeof config.token === "string") {
26
40
  this.headers = {
27
- Authorization: `Bearer ${auth}`,
41
+ Authorization: `Bearer ${config.token}`,
28
42
  "Content-Type": "application/json",
29
43
  "User-Agent": `${MCP_SERVER_NAME}/${MCP_SERVER_VERSION}`,
30
44
  };
45
+ this._clientType = "pactflow";
31
46
  }
32
- else {
33
- const authString = `${auth.username}:${auth.password}`;
47
+ else if (typeof config.username === "string" &&
48
+ typeof config.password === "string") {
49
+ const authString = `${config.username}:${config.password}`;
34
50
  this.headers = {
35
51
  Authorization: `Basic ${Buffer.from(authString).toString("base64")}`,
36
52
  "Content-Type": "application/json",
37
53
  "User-Agent": `${MCP_SERVER_NAME}/${MCP_SERVER_VERSION}`,
38
54
  };
55
+ this._clientType = "pact_broker";
56
+ }
57
+ else {
58
+ return false; // Don't configure the client if no auth is provided
39
59
  }
40
- this.baseUrl = baseUrl;
60
+ this.baseUrl = config.base_url;
41
61
  this.aiBaseUrl = `${this.baseUrl}/api/ai`;
42
- this.clientType = clientType;
43
- this.server = server;
62
+ this._server = server.server;
63
+ return true;
44
64
  }
45
65
  // PactFlow AI client methods
46
66
  /**
@@ -9,11 +9,22 @@ export const AUTO_RESOLVE_MODULES = [
9
9
  viewIdPath: "latestViews.TC.viewId",
10
10
  moduleName: "Test Cases",
11
11
  },
12
+ {
13
+ handler: QMetryToolsHandlers.CREATE_TEST_CASE,
14
+ folderIdPath: "rootFolders.TC.id",
15
+ folderIdField: "tcFolderID",
16
+ moduleName: "Test Cases",
17
+ },
12
18
  {
13
19
  handler: QMetryToolsHandlers.FETCH_REQUIREMENTS,
14
20
  viewIdPath: "latestViews.RQ.viewId",
15
21
  moduleName: "Requirements",
16
22
  },
23
+ {
24
+ handler: QMetryToolsHandlers.FETCH_TEST_SUITES,
25
+ viewIdPath: "latestViews.TS.viewId",
26
+ moduleName: "Test Suites",
27
+ },
17
28
  {
18
29
  handler: QMetryToolsHandlers.FETCH_TESTSUITES_FOR_TESTCASE,
19
30
  viewIdPath: "latestViews.TSFS.viewId",
@@ -21,6 +32,17 @@ export const AUTO_RESOLVE_MODULES = [
21
32
  folderIdField: "tsFolderID",
22
33
  moduleName: "Test Suites",
23
34
  },
35
+ {
36
+ handler: QMetryToolsHandlers.CREATE_TEST_SUITE,
37
+ folderIdPath: "rootFolders.TS.id",
38
+ folderIdField: "parentFolderId",
39
+ moduleName: "Test Suites",
40
+ },
41
+ {
42
+ handler: QMetryToolsHandlers.FETCH_ISSUES,
43
+ viewIdPath: "latestViews.IS.viewId",
44
+ moduleName: "Issues",
45
+ },
24
46
  ];
25
47
  /**
26
48
  * Helper function to safely get nested property value using dot notation
@@ -1,28 +1,42 @@
1
1
  import { QMetryToolsHandlers } from "../config/constants.js";
2
- import { fetchIssuesLinkedToTestCase } from "./issues.js";
3
- import { getBuilds, getPlatforms, getProjectInfo, getReleasesCycles, } from "./project.js";
2
+ import { createIssue, fetchIssues, fetchIssuesLinkedToTestCase, linkIssuesToTestcaseRun, updateIssue, } from "./issues.js";
3
+ import { getBuilds, getPlatforms, getProjectInfo, getProjects, getReleasesCycles, } from "./project.js";
4
4
  import { fetchRequirementDetails, fetchRequirements, fetchRequirementsLinkedToTestCase, } from "./requirement.js";
5
- import { fetchTestCaseDetails, fetchTestCaseExecutions, fetchTestCaseSteps, fetchTestCases, fetchTestCasesLinkedToRequirement, fetchTestCaseVersionDetails, } from "./testcase.js";
6
- import { fetchExecutionsByTestSuite, fetchLinkedIssuesByTestCaseRun, fetchTestCaseRunsByTestSuiteRun, fetchTestCasesByTestSuite, fetchTestSuitesForTestCase, } from "./testsuite.js";
5
+ import { createTestCases, fetchTestCaseDetails, fetchTestCaseExecutions, fetchTestCaseSteps, fetchTestCases, fetchTestCasesLinkedToRequirement, fetchTestCaseVersionDetails, linkRequirementToTestCase, updateTestCase, } from "./testcase.js";
6
+ import { createTestSuites, fetchExecutionsByTestSuite, fetchLinkedIssuesByTestCaseRun, fetchTestCaseRunsByTestSuiteRun, fetchTestCasesByTestSuite, fetchTestSuites, fetchTestSuitesForTestCase, linkPlatformsToTestSuite, linkTestCasesToTestSuite, reqLinkedTestCasesToTestSuite, updateTestSuite, } from "./testsuite.js";
7
7
  export const QMETRY_HANDLER_MAP = {
8
+ [QMetryToolsHandlers.FETCH_PROJECTS]: getProjects,
8
9
  [QMetryToolsHandlers.SET_PROJECT_INFO]: getProjectInfo,
9
10
  [QMetryToolsHandlers.FETCH_PROJECT_INFO]: getProjectInfo,
10
11
  [QMetryToolsHandlers.FETCH_RELEASES_CYCLES]: getReleasesCycles,
11
12
  [QMetryToolsHandlers.FETCH_BUILDS]: getBuilds,
12
13
  [QMetryToolsHandlers.FETCH_PLATFORMS]: getPlatforms,
14
+ [QMetryToolsHandlers.CREATE_TEST_CASE]: createTestCases,
15
+ [QMetryToolsHandlers.UPDATE_TEST_CASE]: updateTestCase,
13
16
  [QMetryToolsHandlers.FETCH_TEST_CASES]: fetchTestCases,
14
17
  [QMetryToolsHandlers.FETCH_TEST_CASE_DETAILS]: fetchTestCaseDetails,
15
18
  [QMetryToolsHandlers.FETCH_TEST_CASE_VERSION_DETAILS]: fetchTestCaseVersionDetails,
16
19
  [QMetryToolsHandlers.FETCH_TEST_CASE_STEPS]: fetchTestCaseSteps,
17
20
  [QMetryToolsHandlers.FETCH_TEST_CASE_EXECUTIONS]: fetchTestCaseExecutions,
21
+ [QMetryToolsHandlers.LINK_REQUIREMENT_TO_TESTCASE]: linkRequirementToTestCase,
18
22
  [QMetryToolsHandlers.FETCH_REQUIREMENTS]: fetchRequirements,
19
23
  [QMetryToolsHandlers.FETCH_REQUIREMENT_DETAILS]: fetchRequirementDetails,
20
24
  [QMetryToolsHandlers.FETCH_TESTCASES_LINKED_TO_REQUIREMENT]: fetchTestCasesLinkedToRequirement,
21
25
  [QMetryToolsHandlers.FETCH_REQUIREMENTS_LINKED_TO_TESTCASE]: fetchRequirementsLinkedToTestCase,
26
+ [QMetryToolsHandlers.CREATE_TEST_SUITE]: createTestSuites,
27
+ [QMetryToolsHandlers.UPDATE_TEST_SUITE]: updateTestSuite,
28
+ [QMetryToolsHandlers.FETCH_TEST_SUITES]: fetchTestSuites,
22
29
  [QMetryToolsHandlers.FETCH_TESTSUITES_FOR_TESTCASE]: fetchTestSuitesForTestCase,
30
+ [QMetryToolsHandlers.LINK_TESTCASES_TO_TESTSUITE]: linkTestCasesToTestSuite,
31
+ [QMetryToolsHandlers.REQUIREMENTS_LINKED_TESTCASES_TO_TESTSUITE]: reqLinkedTestCasesToTestSuite,
23
32
  [QMetryToolsHandlers.FETCH_TESTCASES_BY_TESTSUITE]: fetchTestCasesByTestSuite,
24
33
  [QMetryToolsHandlers.FETCH_EXECUTIONS_BY_TESTSUITE]: fetchExecutionsByTestSuite,
25
34
  [QMetryToolsHandlers.FETCH_TESTCASE_RUNS_BY_TESTSUITE_RUN]: fetchTestCaseRunsByTestSuiteRun,
26
35
  [QMetryToolsHandlers.FETCH_LINKED_ISSUES_BY_TESTCASE_RUN]: fetchLinkedIssuesByTestCaseRun,
27
36
  [QMetryToolsHandlers.FETCH_ISSUES_LINKED_TO_TESTCASE]: fetchIssuesLinkedToTestCase,
37
+ [QMetryToolsHandlers.CREATE_ISSUE]: createIssue,
38
+ [QMetryToolsHandlers.UPDATE_ISSUE]: updateIssue,
39
+ [QMetryToolsHandlers.FETCH_ISSUES]: fetchIssues,
40
+ [QMetryToolsHandlers.LINK_ISSUES_TO_TESTCASE_RUN]: linkIssuesToTestcaseRun,
41
+ [QMetryToolsHandlers.LINK_PLATFORMS_TO_TESTSUITE]: linkPlatformsToTestSuite,
28
42
  };
@@ -1,7 +1,79 @@
1
1
  import { QMETRY_PATHS } from "../config/rest-endpoints.js";
2
- import { DEFAULT_FETCH_ISSUES_LINKED_TO_TESTCASE_PAYLOAD, } from "../types/issues.js";
2
+ import { DEFAULT_CREATE_ISSUE_PAYLOAD, DEFAULT_FETCH_ISSUES_LINKED_TO_TESTCASE_PAYLOAD, DEFAULT_FETCH_ISSUES_PAYLOAD, DEFAULT_LINK_ISSUES_TO_TESTCASE_RUN_PAYLOAD, DEFAULT_UPDATE_ISSUE_PAYLOAD, } from "../types/issues.js";
3
3
  import { qmetryRequest } from "./api/client-api.js";
4
4
  import { resolveDefaults } from "./utils.js";
5
+ /**
6
+ * Create Defect/Issue.
7
+ * @throws If `issueType` or `issuePriority` or `summary` are missing/invalid.
8
+ */
9
+ export async function createIssue(token, baseUrl, project, payload) {
10
+ const { resolvedBaseUrl, resolvedProject } = resolveDefaults(baseUrl, project);
11
+ const body = {
12
+ ...DEFAULT_CREATE_ISSUE_PAYLOAD,
13
+ ...payload,
14
+ };
15
+ if (typeof body.issueType !== "number") {
16
+ throw new Error("[createIssue] Missing or invalid required parameter: 'issueType'.");
17
+ }
18
+ if (typeof body.issuePriority !== "number") {
19
+ throw new Error("[createIssue] Missing or invalid required parameter: 'issuePriority'.");
20
+ }
21
+ if (typeof body.summary !== "string") {
22
+ throw new Error("[createIssue] Missing or invalid required parameter: 'summary'.");
23
+ }
24
+ return qmetryRequest({
25
+ method: "POST",
26
+ path: QMETRY_PATHS.ISSUES.CREATE_UPDATE_ISSUE,
27
+ token,
28
+ project: resolvedProject,
29
+ baseUrl: resolvedBaseUrl,
30
+ body,
31
+ });
32
+ }
33
+ /**
34
+ * Update Defect/Issue.
35
+ * @throws If `DefectId` is missing/invalid.
36
+ */
37
+ export async function updateIssue(token, baseUrl, project, payload) {
38
+ const { resolvedBaseUrl, resolvedProject } = resolveDefaults(baseUrl, project);
39
+ const body = {
40
+ ...DEFAULT_UPDATE_ISSUE_PAYLOAD,
41
+ ...payload,
42
+ };
43
+ if (typeof body.DefectId !== "number") {
44
+ throw new Error("[updateIssue] Missing or invalid required parameter: 'DefectId'.");
45
+ }
46
+ return qmetryRequest({
47
+ method: "PUT",
48
+ path: QMETRY_PATHS.ISSUES.CREATE_UPDATE_ISSUE,
49
+ token,
50
+ project: resolvedProject,
51
+ baseUrl: resolvedBaseUrl,
52
+ body,
53
+ });
54
+ }
55
+ /**
56
+ * Fetches a list of test suites.
57
+ * @throws If `viewId` or `folderPath` are missing/invalid.
58
+ */
59
+ export async function fetchIssues(token, baseUrl, project, payload) {
60
+ const { resolvedBaseUrl, resolvedProject } = resolveDefaults(baseUrl, project);
61
+ const body = {
62
+ ...DEFAULT_FETCH_ISSUES_PAYLOAD,
63
+ ...payload,
64
+ };
65
+ if (typeof body.viewId !== "number") {
66
+ throw new Error("[fetchIssues] Missing or invalid required parameter: 'viewId'.");
67
+ }
68
+ return qmetryRequest({
69
+ method: "POST",
70
+ path: QMETRY_PATHS.ISSUES.GET_ISSUES_LIST,
71
+ token,
72
+ project: resolvedProject,
73
+ baseUrl: resolvedBaseUrl,
74
+ body,
75
+ });
76
+ }
5
77
  /**
6
78
  * Fetches issues linked to a specific test case.
7
79
  * @throws If `tcID` is missing/invalid.
@@ -24,3 +96,28 @@ export async function fetchIssuesLinkedToTestCase(token, baseUrl, project, paylo
24
96
  body,
25
97
  });
26
98
  }
99
+ /**
100
+ * Link Issues to Testcase Run.
101
+ * @throws If issueIds or tcrId are missing/invalid.
102
+ */
103
+ export async function linkIssuesToTestcaseRun(token, baseUrl, project, payload) {
104
+ const { resolvedBaseUrl, resolvedProject } = resolveDefaults(baseUrl, project);
105
+ const body = {
106
+ ...DEFAULT_LINK_ISSUES_TO_TESTCASE_RUN_PAYLOAD,
107
+ ...payload,
108
+ };
109
+ if (!Array.isArray(body.issueIds) || body.issueIds.length === 0) {
110
+ throw new Error("[linkIssuesToTestcaseRun] Missing or invalid required parameter: 'issueIds'.");
111
+ }
112
+ if (typeof body.tcrId !== "number") {
113
+ throw new Error("[linkIssuesToTestcaseRun] Missing or invalid required parameter: 'tcrId'.");
114
+ }
115
+ return qmetryRequest({
116
+ method: "PUT",
117
+ path: QMETRY_PATHS.ISSUES.LINK_ISSUES_TO_TESTCASE_RUN,
118
+ token,
119
+ project: resolvedProject,
120
+ baseUrl: resolvedBaseUrl,
121
+ body,
122
+ });
123
+ }
@@ -1,6 +1,6 @@
1
1
  import { QMETRY_DEFAULTS } from "../config/constants.js";
2
2
  import { QMETRY_PATHS } from "../config/rest-endpoints.js";
3
- import { DEFAULT_FETCH_BUILD_PAYLOAD, DEFAULT_FETCH_PLATFORMS_PAYLOAD, } from "../types/project.js";
3
+ import { DEFAULT_FETCH_BUILD_PAYLOAD, DEFAULT_FETCH_PLATFORMS_PAYLOAD, DEFAULT_FETCH_PROJECTS_PAYLOAD, } from "../types/project.js";
4
4
  import { qmetryRequest } from "./api/client-api.js";
5
5
  /**
6
6
  * Retrieves project information from QMetry
@@ -26,6 +26,23 @@ export async function getProjectInfo(token, baseUrl, project) {
26
26
  project: project || QMETRY_DEFAULTS.PROJECT_KEY,
27
27
  });
28
28
  }
29
+ /**
30
+ * Fetches a List of projects.
31
+ */
32
+ export async function getProjects(token, baseUrl, project, payload) {
33
+ const body = {
34
+ ...DEFAULT_FETCH_PROJECTS_PAYLOAD,
35
+ ...payload,
36
+ };
37
+ return qmetryRequest({
38
+ method: "POST",
39
+ path: QMETRY_PATHS.PROJECT.GET_PROJECTS,
40
+ token,
41
+ baseUrl: baseUrl || QMETRY_DEFAULTS.BASE_URL,
42
+ project: project || QMETRY_DEFAULTS.PROJECT_KEY,
43
+ body,
44
+ });
45
+ }
29
46
  export async function getReleasesCycles(token, baseUrl, project, payload = {}) {
30
47
  let showArchiveValue;
31
48
  if (payload.showArchive !== undefined) {
@@ -1,7 +1,57 @@
1
1
  import { QMETRY_PATHS } from "../config/rest-endpoints.js";
2
- import { DEFAULT_FETCH_TESTCASE_DETAILS_PAYLOAD, DEFAULT_FETCH_TESTCASE_EXECUTIONS_PAYLOAD, DEFAULT_FETCH_TESTCASE_STEPS_PAYLOAD, DEFAULT_FETCH_TESTCASE_VERSION_DETAILS_PAYLOAD, DEFAULT_FETCH_TESTCASES_LINKED_TO_REQUIREMENT_PAYLOAD, DEFAULT_FETCH_TESTCASES_PAYLOAD, } from "../types/testcase.js";
2
+ import { DEFAULT_CREATE_TESTCASES_PAYLOAD, DEFAULT_FETCH_TESTCASE_DETAILS_PAYLOAD, DEFAULT_FETCH_TESTCASE_EXECUTIONS_PAYLOAD, DEFAULT_FETCH_TESTCASE_STEPS_PAYLOAD, DEFAULT_FETCH_TESTCASE_VERSION_DETAILS_PAYLOAD, DEFAULT_FETCH_TESTCASES_LINKED_TO_REQUIREMENT_PAYLOAD, DEFAULT_FETCH_TESTCASES_PAYLOAD, DEFAULT_LINKED_REQUIREMENT_TO_TESTCASE_PAYLOAD, DEFAULT_UPDATE_TESTCASES_PAYLOAD, } from "../types/testcase.js";
3
3
  import { qmetryRequest } from "./api/client-api.js";
4
4
  import { resolveDefaults } from "./utils.js";
5
+ /**
6
+ * Create test cases.
7
+ * @throws If `tcFolderID` or `name` are missing/invalid.
8
+ */
9
+ export async function createTestCases(token, baseUrl, project, payload) {
10
+ const { resolvedBaseUrl, resolvedProject } = resolveDefaults(baseUrl, project);
11
+ const body = {
12
+ ...DEFAULT_CREATE_TESTCASES_PAYLOAD,
13
+ ...payload,
14
+ };
15
+ if (typeof body.tcFolderID !== "string") {
16
+ throw new Error("[createTestCases] Missing or invalid required parameter: 'tcFolderID'.");
17
+ }
18
+ if (typeof body.name !== "string") {
19
+ throw new Error("[createTestCases] Missing or invalid required parameter: 'name'.");
20
+ }
21
+ return qmetryRequest({
22
+ method: "POST",
23
+ path: QMETRY_PATHS.TESTCASE.CREATE_UPDATE_TC,
24
+ token,
25
+ project: resolvedProject,
26
+ baseUrl: resolvedBaseUrl,
27
+ body,
28
+ });
29
+ }
30
+ /**
31
+ * Update test cases.
32
+ * @throws If `tcID` or `tcVersionID` are missing/invalid.
33
+ */
34
+ export async function updateTestCase(token, baseUrl, project, payload) {
35
+ const { resolvedBaseUrl, resolvedProject } = resolveDefaults(baseUrl, project);
36
+ const body = {
37
+ ...DEFAULT_UPDATE_TESTCASES_PAYLOAD,
38
+ ...payload,
39
+ };
40
+ if (typeof body.tcID !== "number") {
41
+ throw new Error("[updateTestCase] Missing or invalid required parameter: 'tcID'.");
42
+ }
43
+ if (typeof body.tcVersionID !== "number") {
44
+ throw new Error("[updateTestCase] Missing or invalid required parameter: 'tcVersionID'.");
45
+ }
46
+ return qmetryRequest({
47
+ method: "PUT",
48
+ path: QMETRY_PATHS.TESTCASE.CREATE_UPDATE_TC,
49
+ token,
50
+ project: resolvedProject,
51
+ baseUrl: resolvedBaseUrl,
52
+ body,
53
+ });
54
+ }
5
55
  /**
6
56
  * Fetches a list of test cases.
7
57
  * @throws If `viewId` or `folderPath` are missing/invalid.
@@ -140,3 +190,31 @@ export async function fetchTestCaseExecutions(token, baseUrl, project, payload)
140
190
  body,
141
191
  });
142
192
  }
193
+ /**
194
+ * Links a requirement to a test case.
195
+ * @throws If `tcID` or `tcVersionID` or `rqVersionIds` are missing/invalid.
196
+ */
197
+ export async function linkRequirementToTestCase(token, baseUrl, project, payload) {
198
+ const { resolvedBaseUrl, resolvedProject } = resolveDefaults(baseUrl, project);
199
+ const body = {
200
+ ...DEFAULT_LINKED_REQUIREMENT_TO_TESTCASE_PAYLOAD,
201
+ ...payload,
202
+ };
203
+ if (typeof body.tcID !== "string") {
204
+ throw new Error("[linkRequirementToTestCase] Missing or invalid required parameter: 'tcID'.");
205
+ }
206
+ if (typeof body.tcVersionId !== "number") {
207
+ throw new Error("[linkRequirementToTestCase] Missing or invalid required parameter: 'tcVersionId'.");
208
+ }
209
+ if (typeof body.rqVersionIds !== "string") {
210
+ throw new Error("[linkRequirementToTestCase] Missing or invalid required parameter: 'rqVersionIds'.");
211
+ }
212
+ return qmetryRequest({
213
+ method: "PUT",
214
+ path: QMETRY_PATHS.TESTCASE.LINKED_RQ_TO_TC,
215
+ token,
216
+ project: resolvedProject,
217
+ baseUrl: resolvedBaseUrl,
218
+ body,
219
+ });
220
+ }