@testomatio/mcp 2.0.0 → 2.0.1-beta.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.
@@ -1,7 +1,9 @@
1
+ import { TESTS_TQL_INPUT_DESCRIPTION, TESTS_TQL_REFERENCE } from './tql-reference.js';
2
+
1
3
  export const TESTS_TOOLS = [
2
4
  {
3
5
  "name": "tests_list",
4
- "description": "List tests (/api/v2/{project_id}/tests)",
6
+ "description": `List tests (/api/v2/{project_id}/tests). ${TESTS_TQL_REFERENCE}`,
5
7
  "inputSchema": {
6
8
  "type": "object",
7
9
  "properties": {
@@ -14,23 +16,9 @@ export const TESTS_TOOLS = [
14
16
  "minimum": 1,
15
17
  "maximum": 100
16
18
  },
17
- "suite_id": {
18
- "type": "string"
19
- },
20
- "search_text": {
21
- "type": "string"
22
- },
23
- "query": {
24
- "type": "string"
25
- },
26
- "assigned_to": {
27
- "type": "string"
28
- },
29
- "priority": {
30
- "type": "string"
31
- },
32
- "state": {
33
- "type": "string"
19
+ "tql": {
20
+ "type": "string",
21
+ "description": TESTS_TQL_INPUT_DESCRIPTION
34
22
  }
35
23
  },
36
24
  "additionalProperties": false
@@ -100,6 +88,7 @@ export const TESTS_TOOLS = [
100
88
  "label",
101
89
  "custom_field",
102
90
  "tag",
91
+ "milestone",
103
92
  "issue",
104
93
  "jira"
105
94
  ]
@@ -178,6 +167,7 @@ export const TESTS_TOOLS = [
178
167
  "label",
179
168
  "custom_field",
180
169
  "tag",
170
+ "milestone",
181
171
  "issue",
182
172
  "jira"
183
173
  ]
@@ -219,16 +209,10 @@ export const TESTS_TOOLS = [
219
209
  },
220
210
  {
221
211
  "name": "tests_search",
222
- "description": "Search tests by text (delegates to tests list with search_text)",
212
+ "description": `Search tests using TQL (delegates to tests_list). ${TESTS_TQL_REFERENCE}`,
223
213
  "inputSchema": {
224
214
  "type": "object",
225
215
  "properties": {
226
- "query": {
227
- "type": "string"
228
- },
229
- "search_text": {
230
- "type": "string"
231
- },
232
216
  "page": {
233
217
  "type": "integer",
234
218
  "minimum": 1
@@ -238,17 +222,9 @@ export const TESTS_TOOLS = [
238
222
  "minimum": 1,
239
223
  "maximum": 100
240
224
  },
241
- "suite_id": {
242
- "type": "string"
243
- },
244
- "assigned_to": {
245
- "type": "string"
246
- },
247
- "priority": {
248
- "type": "string"
249
- },
250
- "state": {
251
- "type": "string"
225
+ "tql": {
226
+ "type": "string",
227
+ "description": TESTS_TQL_INPUT_DESCRIPTION
252
228
  }
253
229
  },
254
230
  "additionalProperties": false
@@ -0,0 +1,133 @@
1
+ const TESTS_TQL_VARIABLES = [
2
+ 'tag',
3
+ 'label',
4
+ 'priority',
5
+ 'issue',
6
+ 'jira',
7
+ 'state',
8
+ 'status',
9
+ 'custom_status',
10
+ 'created_at',
11
+ 'updated_at',
12
+ 'last_run_at',
13
+ 'executed_at',
14
+ 'created_by',
15
+ 'assigned_to',
16
+ 'suite',
17
+ 'test',
18
+ ];
19
+
20
+ const RUNS_TQL_VARIABLES = [
21
+ 'title',
22
+ 'plan',
23
+ 'rungroup',
24
+ 'env',
25
+ 'tag',
26
+ 'label',
27
+ 'jira',
28
+ 'duration',
29
+ 'passed_count',
30
+ 'failed_count',
31
+ 'skipped_count',
32
+ 'automated',
33
+ 'manual',
34
+ 'mixed',
35
+ 'finished',
36
+ 'unfinished',
37
+ 'passed',
38
+ 'failed',
39
+ 'terminated',
40
+ 'published',
41
+ 'private',
42
+ 'archived',
43
+ 'unarchived',
44
+ 'with_defect',
45
+ 'has_defect',
46
+ 'has_test',
47
+ 'has_test_tag',
48
+ 'has_test_label',
49
+ 'has_suite',
50
+ 'has_message',
51
+ 'has_custom_status',
52
+ 'has_assigned_to',
53
+ 'has_retries',
54
+ 'has_test_duration',
55
+ 'has_priority',
56
+ 'created_at',
57
+ 'updated_at',
58
+ 'launched_at',
59
+ 'finished_at',
60
+ ];
61
+
62
+ const TESTS_TQL_EXAMPLES = [
63
+ "priority == 'high'",
64
+ "state == 'automated'",
65
+ "tag in ['smoke', 'stage1'] and status == 'failed'",
66
+ "suite % 'Checkout'",
67
+ "test % 'User login'",
68
+ "created_at < 1.month_ago",
69
+ "jira in ['JST-1', 'JST-2']",
70
+ ];
71
+
72
+ const RUNS_TQL_EXAMPLES = [
73
+ "title % 'Manual tests'",
74
+ "plan == '{PLAN_ID}'",
75
+ "env in ['Windows', 'Linux']",
76
+ "failed and has_test_tag == 'regression'",
77
+ 'finished and with_defect',
78
+ 'has_retries > 2',
79
+ "automated and env == 'Production' and has_message % 'Server Error'",
80
+ "finished_at >= '2025-07-01' and finished_at <= '2025-07-31' and failed",
81
+ ];
82
+
83
+ const COMMON_TQL_SYNTAX =
84
+ "Supported syntax includes `==`, `!=`, `>`, `<`, `>=`, `<=`, `in [...]`, `%` for partial text match, `and`, `or`, `not`, and parentheses for grouping. Use quotes for string values, for example `state == 'automated'`.";
85
+
86
+ export const TESTS_TQL_REFERENCE =
87
+ `TQL (Testomat.io Query Language) is a string expression passed in \`tql\` to filter tests. ${COMMON_TQL_SYNTAX} ` +
88
+ `Documented test variables: ${TESTS_TQL_VARIABLES.map((item) => `\`${item}\``).join(', ')}. ` +
89
+ `Documented examples: ${TESTS_TQL_EXAMPLES.map((item) => `\`${item}\``).join(', ')}. ` +
90
+ 'Do not invent undocumented fields or syntax. If a query fails, simplify it to one documented predicate.';
91
+
92
+ export const TESTS_TQL_INPUT_DESCRIPTION =
93
+ `TQL filter for tests. Documented variables: ${TESTS_TQL_VARIABLES.map((item) => `\`${item}\``).join(', ')}. ` +
94
+ `Examples: ${TESTS_TQL_EXAMPLES.map((item) => `\`${item}\``).join(', ')}.`;
95
+
96
+ export const RUNS_TQL_REFERENCE =
97
+ `TQL (Testomat.io Query Language) is a string expression passed in \`tql\` to filter runs. ${COMMON_TQL_SYNTAX} ` +
98
+ 'Runs also support boolean flags without comparison such as `failed`, `finished`, `automated`, or `with_defect`. ' +
99
+ `Documented run variables: ${RUNS_TQL_VARIABLES.map((item) => `\`${item}\``).join(', ')}. ` +
100
+ `Documented examples: ${RUNS_TQL_EXAMPLES.map((item) => `\`${item}\``).join(', ')}. ` +
101
+ 'Do not invent undocumented fields or syntax. If a query fails, simplify it to one documented predicate.';
102
+
103
+ export const RUNS_TQL_INPUT_DESCRIPTION =
104
+ `TQL filter for runs. Documented variables: ${RUNS_TQL_VARIABLES.map((item) => `\`${item}\``).join(', ')}. ` +
105
+ `Examples: ${RUNS_TQL_EXAMPLES.map((item) => `\`${item}\``).join(', ')}.`;
106
+
107
+ export const ANALYTICS_TESTS_TQL_REFERENCE =
108
+ `TQL (Testomat.io Query Language) is a string expression passed in \`q\` to filter enterprise analytics test reports. ${COMMON_TQL_SYNTAX} ` +
109
+ 'For analytics tools, the API parameter name is `q`, not `tql`. ' +
110
+ `Documented analytics test variables: ${TESTS_TQL_VARIABLES.map((item) => `\`${item}\``).join(', ')}. ` +
111
+ `Documented examples: ${TESTS_TQL_EXAMPLES.map((item) => `\`${item}\``).join(', ')}. ` +
112
+ 'Do not invent undocumented fields or syntax. If a query fails, simplify it to one documented predicate.';
113
+
114
+ export const ANALYTICS_TESTS_TQL_INPUT_DESCRIPTION =
115
+ 'TQL filter for analytics test reports. The API parameter name is `q`, not `tql`. ' +
116
+ `Documented variables: ${TESTS_TQL_VARIABLES.map((item) => `\`${item}\``).join(', ')}. ` +
117
+ `Examples: ${TESTS_TQL_EXAMPLES.map((item) => `\`${item}\``).join(', ')}.`;
118
+
119
+ export const ANALYTICS_STATS_TQL_REFERENCE =
120
+ `TQL (Testomat.io Query Language) is a string expression passed in \`q\` to filter enterprise analytics aggregated reports. ${COMMON_TQL_SYNTAX} ` +
121
+ 'For analytics tools, the API parameter name is `q`, not `tql`. ' +
122
+ 'According to the official Analytics docs, analytics queries are configured using supported query variables for two data sources: `Tests Variables` and `Runs Variables`. ' +
123
+ `Documented Tests Variables: ${TESTS_TQL_VARIABLES.map((item) => `\`${item}\``).join(', ')}. ` +
124
+ `Documented Runs Variables: ${RUNS_TQL_VARIABLES.map((item) => `\`${item}\``).join(', ')}. ` +
125
+ `Documented Tests examples: ${TESTS_TQL_EXAMPLES.map((item) => `\`${item}\``).join(', ')}. ` +
126
+ `Documented Runs examples: ${RUNS_TQL_EXAMPLES.map((item) => `\`${item}\``).join(', ')}. ` +
127
+ 'Use Tests Variables for test-centric filters and Runs Variables for run-centric filters such as `plan`, `rungroup`, `env`, `finished_at`, or `has_test_tag`. Do not invent undocumented fields or syntax. If a query fails, simplify it to one documented predicate.';
128
+
129
+ export const ANALYTICS_STATS_TQL_INPUT_DESCRIPTION =
130
+ 'TQL filter for analytics aggregated reports. The API parameter name is `q`, not `tql`. ' +
131
+ `Documented Tests Variables: ${TESTS_TQL_VARIABLES.map((item) => `\`${item}\``).join(', ')}. ` +
132
+ `Documented Runs Variables: ${RUNS_TQL_VARIABLES.map((item) => `\`${item}\``).join(', ')}. ` +
133
+ `Examples: ${TESTS_TQL_EXAMPLES.map((item) => `\`${item}\``).join(', ')}, ${RUNS_TQL_EXAMPLES.map((item) => `\`${item}\``).join(', ')}.`;
@@ -8,8 +8,10 @@ export const handlerMethods = {
8
8
 
9
9
  handlers[`${toolPrefix}_list`] = async (args = {}) =>
10
10
  this.asText(await this[listMethod](args));
11
- handlers[`${toolPrefix}_search`] = async (args = {}) =>
12
- this.asText(await this[searchMethod](args));
11
+ if (searchMethod) {
12
+ handlers[`${toolPrefix}_search`] = async (args = {}) =>
13
+ this.asText(await this[searchMethod](args));
14
+ }
13
15
  handlers[`${toolPrefix}_get`] = async (args = {}) =>
14
16
  this.asText(await this.apiClient.get(resource, this.pickRequiredArg(args, idArg)));
15
17
  handlers[`${toolPrefix}_create`] = async (args = {}) =>
@@ -57,6 +59,10 @@ export const handlerMethods = {
57
59
  handlers.tags_get = async ({ tag_id: tagId }) => this.asText(await this.getTagByTitle(tagId));
58
60
  handlers.tags_search = async (args = {}) => this.asText(await this.searchTags(args));
59
61
 
62
+ handlers.milestones_list = async (args = {}) => this.asText(await this.listMilestones(args));
63
+ handlers.milestones_get = async ({ milestone_id: milestoneId }) =>
64
+ this.asText(await this.apiClient.get('milestones', milestoneId));
65
+
60
66
  handlers.issues_list = async (args = {}) => this.asText(await this.listIssues(args));
61
67
  handlers.issues_search = async (args = {}) => this.asText(await this.searchIssues(args));
62
68
  handlers.issues_create = async (args = {}) => this.asText(await this.createIssue(args));
@@ -82,6 +88,9 @@ export const handlerMethods = {
82
88
  if (spec.createMode === 'run') {
83
89
  return this.createRunWithFallback(args);
84
90
  }
91
+ if (spec.createMode === 'requirement') {
92
+ return this.createRequirement(args);
93
+ }
85
94
  const payload = this[spec.payloadBuilder](args);
86
95
  return this.createWrapped(spec.resource, spec.wrapperKey, payload);
87
96
  },
@@ -90,7 +99,13 @@ export const handlerMethods = {
90
99
  if (spec.updateMode === 'run') {
91
100
  return this.updateRunWithFallback(id, args);
92
101
  }
102
+ if (spec.updateMode === 'requirement') {
103
+ return this.updateRequirement(id, args);
104
+ }
93
105
  const payload = this[spec.payloadBuilder](args);
106
+ if (spec.updateMethod === 'patch') {
107
+ return this.patchWrapped(spec.resource, id, spec.wrapperKey, payload);
108
+ }
94
109
  return this.updateWrapped(spec.resource, id, spec.wrapperKey, payload);
95
110
  },
96
111
  };
@@ -1,93 +1,151 @@
1
1
  export const listingMethods = {
2
- listTests({ page, per_page: perPage, suite_id: suiteId, search_text: searchText, query, ...filters } = {}) {
2
+ listTests({
3
+ page,
4
+ per_page: perPage,
5
+ tql,
6
+ } = {}) {
3
7
  return this.apiClient.list('tests', {
4
8
  page,
5
9
  per_page: perPage,
6
- suite_id: suiteId,
7
- search_text: searchText || query,
8
- ...filters,
10
+ tql,
9
11
  });
10
12
  },
11
13
 
12
- searchTests({ query, search_text: searchText, ...rest } = {}) {
14
+ searchTests({ page, per_page: perPage, tql } = {}) {
13
15
  return this.listTests({
14
- ...rest,
15
- search_text: searchText || query,
16
+ page,
17
+ per_page: perPage,
18
+ tql,
16
19
  });
17
20
  },
18
21
 
19
- listSuites({ page, per_page: perPage, file_type: fileType, tag, labels, search_text: searchText, query } = {}) {
22
+ listSuites({ page, per_page: perPage, file_type: fileType, tag, labels, search_text: searchText } = {}) {
20
23
  return this.apiClient.list('suites', {
21
24
  page,
22
25
  per_page: perPage,
23
26
  file_type: fileType,
24
27
  tag,
25
28
  labels,
26
- search_text: searchText || query,
29
+ search_text: searchText,
27
30
  });
28
31
  },
29
32
 
30
- searchSuites({ query, search_text: searchText, ...rest } = {}) {
33
+ searchSuites({ search_text: searchText, ...rest } = {}) {
31
34
  return this.listSuites({
32
35
  ...rest,
33
- search_text: searchText || query,
36
+ search_text: searchText,
34
37
  });
35
38
  },
36
39
 
37
- listRuns({ page, per_page: perPage, query } = {}) {
38
- return this.apiClient.list('runs', { page, per_page: perPage, query });
39
- },
40
-
41
- searchRuns({ page, per_page: perPage, query } = {}) {
42
- return this.listRuns({ page, per_page: perPage, query });
43
- },
44
-
45
- listTestruns({ page, per_page: perPage, run_id: runId, query } = {}) {
46
- return this.apiClient.list('testruns', { page, per_page: perPage, run_id: runId, query });
40
+ listRuns({
41
+ page,
42
+ per_page: perPage,
43
+ tql,
44
+ } = {}) {
45
+ return this.apiClient.list('runs', {
46
+ page,
47
+ per_page: perPage,
48
+ tql,
49
+ });
47
50
  },
48
51
 
49
- searchTestruns({ page, per_page: perPage, run_id: runId, query } = {}) {
50
- return this.listTestruns({ page, per_page: perPage, run_id: runId, query });
52
+ searchRuns({ page, per_page: perPage, tql } = {}) {
53
+ return this.listRuns({ page, per_page: perPage, tql });
54
+ },
55
+
56
+ listTestruns({
57
+ page,
58
+ per_page: perPage,
59
+ run_id: runId,
60
+ test_ids: testIds,
61
+ filter_status: filterStatus,
62
+ filter_kind: filterKind,
63
+ filter_user: filterUser,
64
+ filter_priority: filterPriority,
65
+ filter_substatus: filterSubstatus,
66
+ filter_search: filterSearch,
67
+ filter_message: filterMessage,
68
+ filter_link: filterLink,
69
+ filter_finished_at_date_range: filterFinishedAtDateRange,
70
+ tags,
71
+ labels,
72
+ envs,
73
+ rungroups,
74
+ defects,
75
+ } = {}) {
76
+ return this.apiClient.list('testruns', {
77
+ page,
78
+ per_page: perPage,
79
+ run_id: runId,
80
+ test_ids: Array.isArray(testIds) ? testIds.join(',') : testIds,
81
+ 'filter[status]': filterStatus,
82
+ 'filter[kind]': filterKind,
83
+ 'filter[user]': filterUser,
84
+ 'filter[priority]': filterPriority,
85
+ 'filter[substatus]': filterSubstatus,
86
+ 'filter[search]': filterSearch,
87
+ 'filter[message]': filterMessage,
88
+ 'filter[link]': filterLink,
89
+ 'filter[finished_at_date_range]': filterFinishedAtDateRange,
90
+ tags: Array.isArray(tags) ? tags.join(',') : tags,
91
+ labels: Array.isArray(labels) ? labels.join(',') : labels,
92
+ envs: Array.isArray(envs) ? envs.join(',') : envs,
93
+ rungroups: Array.isArray(rungroups) ? rungroups.join(',') : rungroups,
94
+ defects,
95
+ });
51
96
  },
52
97
 
53
- listRungroups({ page, per_page: perPage, query } = {}) {
54
- return this.apiClient.list('rungroups', { page, per_page: perPage, query });
98
+ searchTestruns({ page, per_page: perPage, run_id: runId, filter_search: filterSearch, ...rest } = {}) {
99
+ return this.listTestruns({
100
+ page,
101
+ per_page: perPage,
102
+ run_id: runId,
103
+ filter_search: filterSearch,
104
+ ...rest,
105
+ });
55
106
  },
56
107
 
57
- searchRungroups({ page, per_page: perPage, query } = {}) {
58
- return this.listRungroups({ page, per_page: perPage, query });
108
+ listRungroups({ page, per_page: perPage } = {}) {
109
+ return this.apiClient.list('rungroups', { page, per_page: perPage });
59
110
  },
60
111
 
61
- listSteps({ page, per_page: perPage, query } = {}) {
62
- return this.apiClient.list('steps', { page, per_page: perPage, query });
112
+ listSteps({ page, per_page: perPage } = {}) {
113
+ return this.apiClient.list('steps', { page, per_page: perPage });
63
114
  },
64
115
 
65
- searchSteps({ page, per_page: perPage, query } = {}) {
66
- return this.listSteps({ page, per_page: perPage, query });
116
+ listSnippets({ page, per_page: perPage } = {}) {
117
+ return this.apiClient.list('snippets', { page, per_page: perPage });
67
118
  },
68
119
 
69
- listSnippets({ page, per_page: perPage, query } = {}) {
70
- return this.apiClient.list('snippets', { page, per_page: perPage, query });
120
+ listLabels({ page, per_page: perPage } = {}) {
121
+ return this.apiClient.list('labels', { page, per_page: perPage });
71
122
  },
72
123
 
73
- searchSnippets({ page, per_page: perPage, query } = {}) {
74
- return this.listSnippets({ page, per_page: perPage, query });
124
+ listPlans({ page, per_page: perPage, kind, hidden, labels, search_text: searchText } = {}) {
125
+ return this.apiClient.list('plans', {
126
+ page,
127
+ per_page: perPage,
128
+ kind,
129
+ hidden,
130
+ 'labels[]': labels,
131
+ search_text: searchText,
132
+ });
75
133
  },
76
134
 
77
- listLabels({ page, per_page: perPage, query } = {}) {
78
- return this.apiClient.list('labels', { page, per_page: perPage, query });
135
+ searchPlans({ page, per_page: perPage, search_text: searchText, ...rest } = {}) {
136
+ return this.listPlans({ page, per_page: perPage, search_text: searchText, ...rest });
79
137
  },
80
138
 
81
- searchLabels({ page, per_page: perPage, query } = {}) {
82
- return this.listLabels({ page, per_page: perPage, query });
139
+ listRequirements({ page, per_page: perPage, source, scope } = {}) {
140
+ return this.apiClient.list('requirements', { page, per_page: perPage, source, scope });
83
141
  },
84
142
 
85
- listPlans({ page, per_page: perPage, query } = {}) {
86
- return this.apiClient.list('plans', { page, per_page: perPage, query });
143
+ searchRequirements({ page, per_page: perPage, source, scope } = {}) {
144
+ return this.listRequirements({ page, per_page: perPage, source, scope });
87
145
  },
88
146
 
89
- searchPlans({ page, per_page: perPage, query } = {}) {
90
- return this.listPlans({ page, per_page: perPage, query });
147
+ listMilestones({ page, per_page: perPage, type, status } = {}) {
148
+ return this.apiClient.list('milestones', { page, per_page: perPage, type, status });
91
149
  },
92
150
 
93
151
  listTags() {
@@ -1,3 +1,6 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+
1
4
  export const payloadMethods = {
2
5
  async createWrapped(resource, wrapperKey, payload) {
3
6
  const wrappedBody = { [wrapperKey]: payload };
@@ -23,6 +26,70 @@ export const payloadMethods = {
23
26
  }
24
27
  },
25
28
 
29
+ async patchWrapped(resource, id, wrapperKey, payload) {
30
+ const wrappedBody = { [wrapperKey]: payload };
31
+ try {
32
+ return await this.apiClient.patch(resource, id, payload);
33
+ } catch (error) {
34
+ if (!this.shouldRetryWrappedBody(error, wrapperKey)) {
35
+ throw error;
36
+ }
37
+ return this.apiClient.patch(resource, id, wrappedBody);
38
+ }
39
+ },
40
+
41
+ async createRequirement(args = {}) {
42
+ const { files, ...payloadArgs } = args;
43
+ const payload = this.buildRequirementPayload(payloadArgs);
44
+
45
+ if (this.hasFiles(files)) {
46
+ return this.apiClient.createMultipart(
47
+ 'requirements',
48
+ await this.buildRequirementFormData(payload, files)
49
+ );
50
+ }
51
+
52
+ return this.createWrapped('requirements', 'requirement', payload);
53
+ },
54
+
55
+ async updateRequirement(requirementId, args = {}) {
56
+ const { files, ...payloadArgs } = args;
57
+ const payload = this.buildRequirementPayload(payloadArgs);
58
+
59
+ if (this.hasFiles(files)) {
60
+ return this.apiClient.patchMultipart(
61
+ 'requirements',
62
+ requirementId,
63
+ await this.buildRequirementFormData(payload, files)
64
+ );
65
+ }
66
+
67
+ return this.patchWrapped('requirements', requirementId, 'requirement', payload);
68
+ },
69
+
70
+ hasFiles(files) {
71
+ return Array.isArray(files) && files.length > 0;
72
+ },
73
+
74
+ async buildRequirementFormData(payload, files = []) {
75
+ const formData = new FormData();
76
+
77
+ Object.entries(payload).forEach(([key, value]) => {
78
+ if (value === undefined || value === null) {
79
+ return;
80
+ }
81
+ formData.append(key, typeof value === 'boolean' ? String(value) : value);
82
+ });
83
+
84
+ for (const filePath of files) {
85
+ const resolvedPath = path.resolve(String(filePath));
86
+ const data = await fs.readFile(resolvedPath);
87
+ formData.append('files', new Blob([data]), path.basename(resolvedPath));
88
+ }
89
+
90
+ return formData;
91
+ },
92
+
26
93
  buildTestPayload({
27
94
  title,
28
95
  suite_id: suiteId,
@@ -76,7 +143,7 @@ export const payloadMethods = {
76
143
  buildRunCreatePayload({
77
144
  title,
78
145
  description,
79
- plan_id: planId,
146
+ plan_ids: planIds,
80
147
  kind,
81
148
  rungroup_id: rungroupId,
82
149
  env,
@@ -85,13 +152,12 @@ export const payloadMethods = {
85
152
  test_ids: testIds,
86
153
  suite_ids: suiteIds,
87
154
  envs,
88
- configuration,
89
155
  link,
90
156
  } = {}) {
91
157
  return {
92
158
  title,
93
159
  description,
94
- plan_id: planId,
160
+ plan_ids: planIds,
95
161
  kind,
96
162
  rungroup_id: rungroupId,
97
163
  env,
@@ -100,7 +166,6 @@ export const payloadMethods = {
100
166
  test_ids: testIds,
101
167
  suite_ids: suiteIds,
102
168
  envs,
103
- configuration,
104
169
  link,
105
170
  };
106
171
  },
@@ -108,7 +173,6 @@ export const payloadMethods = {
108
173
  buildRunUpdatePayload({
109
174
  title,
110
175
  description,
111
- plan_id: planId,
112
176
  kind,
113
177
  rungroup_id: rungroupId,
114
178
  env,
@@ -117,13 +181,11 @@ export const payloadMethods = {
117
181
  assign_strategy: assignStrategy,
118
182
  test_ids: testIds,
119
183
  suite_ids: suiteIds,
120
- configuration,
121
184
  link,
122
185
  } = {}) {
123
186
  return {
124
187
  title,
125
188
  description,
126
- plan_id: planId,
127
189
  kind,
128
190
  rungroup_id: rungroupId,
129
191
  env,
@@ -132,7 +194,6 @@ export const payloadMethods = {
132
194
  assign_strategy: assignStrategy,
133
195
  test_ids: testIds,
134
196
  suite_ids: suiteIds,
135
- configuration,
136
197
  link,
137
198
  };
138
199
  },
@@ -268,4 +329,24 @@ export const payloadMethods = {
268
329
  link,
269
330
  };
270
331
  },
332
+
333
+ buildRequirementPayload({
334
+ title,
335
+ source_type: sourceType,
336
+ description,
337
+ details,
338
+ active,
339
+ global,
340
+ confluence_url: confluenceUrl,
341
+ } = {}) {
342
+ return {
343
+ title,
344
+ source_type: sourceType,
345
+ description,
346
+ details,
347
+ active,
348
+ global,
349
+ confluence_url: confluenceUrl,
350
+ };
351
+ },
271
352
  };