@dichovsky/testrail-api-client 1.0.0 → 2.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.
Files changed (137) hide show
  1. package/README.md +22 -0
  2. package/dist/cli/auth.d.ts +21 -0
  3. package/dist/cli/auth.js +16 -0
  4. package/dist/cli/body.d.ts +42 -0
  5. package/dist/cli/body.js +89 -0
  6. package/dist/cli/dispatch.d.ts +16 -0
  7. package/dist/cli/dispatch.js +87 -0
  8. package/dist/cli/handler-context.d.ts +43 -0
  9. package/dist/cli/handler-context.js +2 -0
  10. package/dist/cli/handlers/case-write.d.ts +4 -0
  11. package/dist/cli/handlers/case-write.js +26 -0
  12. package/dist/cli/handlers/case.d.ts +4 -0
  13. package/dist/cli/handlers/case.js +11 -0
  14. package/dist/cli/handlers/milestone.d.ts +4 -0
  15. package/dist/cli/handlers/milestone.js +15 -0
  16. package/dist/cli/handlers/project.d.ts +4 -0
  17. package/dist/cli/handlers/project.js +11 -0
  18. package/dist/cli/handlers/result-write.d.ts +4 -0
  19. package/dist/cli/handlers/result-write.js +40 -0
  20. package/dist/cli/handlers/result.d.ts +3 -0
  21. package/dist/cli/handlers/result.js +11 -0
  22. package/dist/cli/handlers/run-write.d.ts +10 -0
  23. package/dist/cli/handlers/run-write.js +29 -0
  24. package/dist/cli/handlers/run.d.ts +4 -0
  25. package/dist/cli/handlers/run.js +15 -0
  26. package/dist/cli/handlers/suite.d.ts +4 -0
  27. package/dist/cli/handlers/suite.js +10 -0
  28. package/dist/cli/handlers/user.d.ts +4 -0
  29. package/dist/cli/handlers/user.js +11 -0
  30. package/dist/cli/ids.d.ts +6 -0
  31. package/dist/cli/ids.js +20 -0
  32. package/dist/cli/index.d.ts +3 -0
  33. package/dist/cli/index.js +198 -0
  34. package/dist/cli/install-skill.d.ts +35 -0
  35. package/dist/cli/install-skill.js +71 -0
  36. package/dist/cli/metadata.d.ts +37 -0
  37. package/dist/cli/metadata.js +151 -0
  38. package/dist/cli/output.d.ts +28 -0
  39. package/dist/cli/output.js +84 -0
  40. package/dist/cli.d.ts +1 -1
  41. package/dist/cli.js +1 -266
  42. package/dist/client-core.d.ts +16 -7
  43. package/dist/client-core.js +153 -27
  44. package/dist/client.d.ts +274 -118
  45. package/dist/client.js +404 -463
  46. package/dist/constants.d.ts +1 -0
  47. package/dist/constants.js +1 -0
  48. package/dist/errors.d.ts +11 -9
  49. package/dist/errors.js +12 -8
  50. package/dist/index.d.ts +4 -2
  51. package/dist/index.js +2 -1
  52. package/dist/modules/attachments.d.ts +19 -0
  53. package/dist/modules/attachments.js +64 -0
  54. package/dist/modules/cases.d.ts +13 -0
  55. package/dist/modules/cases.js +58 -0
  56. package/dist/modules/configurations.d.ts +14 -0
  57. package/dist/modules/configurations.js +37 -0
  58. package/dist/modules/datasets.d.ts +12 -0
  59. package/dist/modules/datasets.js +28 -0
  60. package/dist/modules/metadata.d.ts +14 -0
  61. package/dist/modules/metadata.js +31 -0
  62. package/dist/modules/milestones.d.ts +12 -0
  63. package/dist/modules/milestones.js +36 -0
  64. package/dist/modules/plans.d.ts +16 -0
  65. package/dist/modules/plans.js +59 -0
  66. package/dist/modules/projects.d.ts +36 -0
  67. package/dist/modules/projects.js +55 -0
  68. package/dist/modules/reports.d.ts +9 -0
  69. package/dist/modules/reports.js +16 -0
  70. package/dist/modules/results.d.ts +14 -0
  71. package/dist/modules/results.js +69 -0
  72. package/dist/modules/runs.d.ts +14 -0
  73. package/dist/modules/runs.js +57 -0
  74. package/dist/modules/sections.d.ts +16 -0
  75. package/dist/modules/sections.js +37 -0
  76. package/dist/modules/sharedSteps.d.ts +12 -0
  77. package/dist/modules/sharedSteps.js +28 -0
  78. package/dist/modules/suites.d.ts +37 -0
  79. package/dist/modules/suites.js +54 -0
  80. package/dist/modules/tests.d.ts +9 -0
  81. package/dist/modules/tests.js +25 -0
  82. package/dist/modules/users.d.ts +18 -0
  83. package/dist/modules/users.js +62 -0
  84. package/dist/modules/variables.d.ts +11 -0
  85. package/dist/modules/variables.js +24 -0
  86. package/dist/schemas.d.ts +544 -0
  87. package/dist/schemas.js +419 -0
  88. package/dist/types.d.ts +1 -55
  89. package/dist/utils.d.ts +2 -0
  90. package/dist/utils.js +4 -0
  91. package/package.json +23 -15
  92. package/skill/SKILL.md +395 -0
  93. package/src/cli/auth.ts +37 -0
  94. package/src/cli/body.ts +100 -0
  95. package/src/cli/dispatch.ts +91 -0
  96. package/src/cli/handler-context.ts +46 -0
  97. package/src/cli/handlers/case-write.ts +26 -0
  98. package/src/cli/handlers/case.ts +13 -0
  99. package/src/cli/handlers/milestone.ts +19 -0
  100. package/src/cli/handlers/project.ts +13 -0
  101. package/src/cli/handlers/result-write.ts +40 -0
  102. package/src/cli/handlers/result.ts +14 -0
  103. package/src/cli/handlers/run-write.ts +30 -0
  104. package/src/cli/handlers/run.ts +19 -0
  105. package/src/cli/handlers/suite.ts +12 -0
  106. package/src/cli/handlers/user.ts +13 -0
  107. package/src/cli/ids.ts +20 -0
  108. package/src/cli/index.ts +224 -0
  109. package/src/cli/install-skill.ts +89 -0
  110. package/src/cli/metadata.ts +194 -0
  111. package/src/cli/output.ts +96 -0
  112. package/src/cli.ts +1 -286
  113. package/src/client-core.ts +183 -67
  114. package/src/client.ts +414 -483
  115. package/src/constants.ts +1 -0
  116. package/src/errors.ts +18 -11
  117. package/src/index.ts +50 -8
  118. package/src/modules/attachments.ts +125 -0
  119. package/src/modules/cases.ts +78 -0
  120. package/src/modules/configurations.ts +68 -0
  121. package/src/modules/datasets.ts +44 -0
  122. package/src/modules/metadata.ts +63 -0
  123. package/src/modules/milestones.ts +54 -0
  124. package/src/modules/plans.ts +89 -0
  125. package/src/modules/projects.ts +67 -0
  126. package/src/modules/reports.ts +23 -0
  127. package/src/modules/results.ts +90 -0
  128. package/src/modules/runs.ts +70 -0
  129. package/src/modules/sections.ts +55 -0
  130. package/src/modules/sharedSteps.ts +44 -0
  131. package/src/modules/suites.ts +67 -0
  132. package/src/modules/tests.ts +28 -0
  133. package/src/modules/users.ts +87 -0
  134. package/src/modules/variables.ts +36 -0
  135. package/src/schemas.ts +551 -0
  136. package/src/types.ts +11 -60
  137. package/src/utils.ts +5 -0
package/dist/client.js CHANGED
@@ -1,5 +1,21 @@
1
1
  import { TestRailClientCore } from './client-core.js';
2
- import { TestRailValidationError } from './errors.js';
2
+ import { ProjectModule } from './modules/projects.js';
3
+ import { SuiteModule } from './modules/suites.js';
4
+ import { SectionModule } from './modules/sections.js';
5
+ import { CaseModule } from './modules/cases.js';
6
+ import { PlanModule } from './modules/plans.js';
7
+ import { RunModule } from './modules/runs.js';
8
+ import { TestModule } from './modules/tests.js';
9
+ import { ResultModule } from './modules/results.js';
10
+ import { MilestoneModule } from './modules/milestones.js';
11
+ import { UsersModule } from './modules/users.js';
12
+ import { MetadataModule } from './modules/metadata.js';
13
+ import { ConfigurationModule } from './modules/configurations.js';
14
+ import { AttachmentModule } from './modules/attachments.js';
15
+ import { SharedStepModule } from './modules/sharedSteps.js';
16
+ import { VariableModule } from './modules/variables.js';
17
+ import { DatasetModule } from './modules/datasets.js';
18
+ import { ReportModule } from './modules/reports.js';
3
19
  export { TestRailApiError, TestRailValidationError } from './errors.js';
4
20
  /**
5
21
  * TestRail API Client
@@ -9,6 +25,44 @@ export { TestRailApiError, TestRailValidationError } from './errors.js';
9
25
  * Extends {@link TestRailClientCore} for HTTP pipeline, caching, rate limiting, and retry.
10
26
  */
11
27
  export class TestRailClient extends TestRailClientCore {
28
+ // ── Domain modules ────────────────────────────────────────────────────────
29
+ projects;
30
+ suites;
31
+ sections;
32
+ cases;
33
+ plans;
34
+ runs;
35
+ tests;
36
+ results;
37
+ milestones;
38
+ users;
39
+ metadata;
40
+ configurations;
41
+ attachments;
42
+ sharedSteps;
43
+ variables;
44
+ datasets;
45
+ reports;
46
+ constructor(...args) {
47
+ super(...args);
48
+ this.projects = new ProjectModule(this);
49
+ this.suites = new SuiteModule(this);
50
+ this.sections = new SectionModule(this);
51
+ this.cases = new CaseModule(this);
52
+ this.plans = new PlanModule(this);
53
+ this.runs = new RunModule(this);
54
+ this.tests = new TestModule(this);
55
+ this.results = new ResultModule(this);
56
+ this.milestones = new MilestoneModule(this);
57
+ this.users = new UsersModule(this);
58
+ this.metadata = new MetadataModule(this);
59
+ this.configurations = new ConfigurationModule(this);
60
+ this.attachments = new AttachmentModule(this);
61
+ this.sharedSteps = new SharedStepModule(this);
62
+ this.variables = new VariableModule(this);
63
+ this.datasets = new DatasetModule(this);
64
+ this.reports = new ReportModule(this);
65
+ }
12
66
  // ── Projects ──────────────────────────────────────────────────────────────
13
67
  /**
14
68
  * Get a project by ID.
@@ -16,8 +70,7 @@ export class TestRailClient extends TestRailClientCore {
16
70
  * @throws {TestRailApiError} When the API request fails
17
71
  */
18
72
  async getProject(projectId) {
19
- this.validateId(projectId, 'projectId');
20
- return this.request('GET', `get_project/${projectId}`);
73
+ return this.projects.getProject(projectId);
21
74
  }
22
75
  /**
23
76
  * Get all projects.
@@ -25,17 +78,14 @@ export class TestRailClient extends TestRailClientCore {
25
78
  * @throws {TestRailApiError} When the API request fails
26
79
  */
27
80
  async getProjects(limit, offset) {
28
- this.validatePaginationParams(limit, offset);
29
- const endpoint = this.buildEndpoint('get_projects', { limit, offset });
30
- const response = await this.request('GET', endpoint);
31
- return response.projects ?? [];
81
+ return this.projects.getProjects(limit, offset);
32
82
  }
33
83
  /**
34
84
  * Add a new project.
35
85
  * @throws {TestRailApiError} When the API request fails
36
86
  */
37
87
  async addProject(payload) {
38
- return this.request('POST', 'add_project', payload);
88
+ return this.projects.addProject(payload);
39
89
  }
40
90
  /**
41
91
  * Update an existing project.
@@ -43,8 +93,7 @@ export class TestRailClient extends TestRailClientCore {
43
93
  * @throws {TestRailApiError} When the API request fails
44
94
  */
45
95
  async updateProject(projectId, payload) {
46
- this.validateId(projectId, 'projectId');
47
- return this.request('POST', `update_project/${projectId}`, payload);
96
+ return this.projects.updateProject(projectId, payload);
48
97
  }
49
98
  /**
50
99
  * Delete a project.
@@ -52,8 +101,7 @@ export class TestRailClient extends TestRailClientCore {
52
101
  * @throws {TestRailApiError} When the API request fails
53
102
  */
54
103
  async deleteProject(projectId) {
55
- this.validateId(projectId, 'projectId');
56
- await this.request('POST', `delete_project/${projectId}`);
104
+ return this.projects.deleteProject(projectId);
57
105
  }
58
106
  // ── Suites ────────────────────────────────────────────────────────────────
59
107
  /**
@@ -62,8 +110,7 @@ export class TestRailClient extends TestRailClientCore {
62
110
  * @throws {TestRailApiError} When the API request fails
63
111
  */
64
112
  async getSuite(suiteId) {
65
- this.validateId(suiteId, 'suiteId');
66
- return this.request('GET', `get_suite/${suiteId}`);
113
+ return this.suites.getSuite(suiteId);
67
114
  }
68
115
  /**
69
116
  * Get all suites for a project.
@@ -71,8 +118,7 @@ export class TestRailClient extends TestRailClientCore {
71
118
  * @throws {TestRailApiError} When the API request fails
72
119
  */
73
120
  async getSuites(projectId) {
74
- this.validateId(projectId, 'projectId');
75
- return this.request('GET', `get_suites/${projectId}`);
121
+ return this.suites.getSuites(projectId);
76
122
  }
77
123
  /**
78
124
  * Add a suite to a project.
@@ -80,8 +126,7 @@ export class TestRailClient extends TestRailClientCore {
80
126
  * @throws {TestRailApiError} When the API request fails
81
127
  */
82
128
  async addSuite(projectId, payload) {
83
- this.validateId(projectId, 'projectId');
84
- return this.request('POST', `add_suite/${projectId}`, payload);
129
+ return this.suites.addSuite(projectId, payload);
85
130
  }
86
131
  /**
87
132
  * Update a suite.
@@ -89,8 +134,7 @@ export class TestRailClient extends TestRailClientCore {
89
134
  * @throws {TestRailApiError} When the API request fails
90
135
  */
91
136
  async updateSuite(suiteId, payload) {
92
- this.validateId(suiteId, 'suiteId');
93
- return this.request('POST', `update_suite/${suiteId}`, payload);
137
+ return this.suites.updateSuite(suiteId, payload);
94
138
  }
95
139
  /**
96
140
  * Delete a suite.
@@ -98,8 +142,7 @@ export class TestRailClient extends TestRailClientCore {
98
142
  * @throws {TestRailApiError} When the API request fails
99
143
  */
100
144
  async deleteSuite(suiteId) {
101
- this.validateId(suiteId, 'suiteId');
102
- await this.request('POST', `delete_suite/${suiteId}`);
145
+ return this.suites.deleteSuite(suiteId);
103
146
  }
104
147
  // ── Sections ──────────────────────────────────────────────────────────────
105
148
  /**
@@ -108,8 +151,7 @@ export class TestRailClient extends TestRailClientCore {
108
151
  * @throws {TestRailApiError} When the API request fails
109
152
  */
110
153
  async getSection(sectionId) {
111
- this.validateId(sectionId, 'sectionId');
112
- return this.request('GET', `get_section/${sectionId}`);
154
+ return this.sections.getSection(sectionId);
113
155
  }
114
156
  /**
115
157
  * Get all sections for a project, optionally filtered by suite.
@@ -120,15 +162,7 @@ export class TestRailClient extends TestRailClientCore {
120
162
  * @throws {TestRailApiError} When the API request fails
121
163
  */
122
164
  async getSections(projectId, options) {
123
- this.validateId(projectId, 'projectId');
124
- const { suiteId, limit, offset } = options ?? {};
125
- if (suiteId !== undefined) {
126
- this.validateId(suiteId, 'suiteId');
127
- }
128
- this.validatePaginationParams(limit, offset);
129
- const endpoint = this.buildEndpoint(`get_sections/${projectId}`, { suite_id: suiteId, limit, offset });
130
- const response = await this.request('GET', endpoint);
131
- return response.sections ?? [];
165
+ return this.sections.getSections(projectId, options);
132
166
  }
133
167
  /**
134
168
  * Add a new section to a project.
@@ -136,8 +170,7 @@ export class TestRailClient extends TestRailClientCore {
136
170
  * @throws {TestRailApiError} When the API request fails
137
171
  */
138
172
  async addSection(projectId, payload) {
139
- this.validateId(projectId, 'projectId');
140
- return this.request('POST', `add_section/${projectId}`, payload);
173
+ return this.sections.addSection(projectId, payload);
141
174
  }
142
175
  /**
143
176
  * Update an existing section.
@@ -145,8 +178,7 @@ export class TestRailClient extends TestRailClientCore {
145
178
  * @throws {TestRailApiError} When the API request fails
146
179
  */
147
180
  async updateSection(sectionId, payload) {
148
- this.validateId(sectionId, 'sectionId');
149
- return this.request('POST', `update_section/${sectionId}`, payload);
181
+ return this.sections.updateSection(sectionId, payload);
150
182
  }
151
183
  /**
152
184
  * Delete a section.
@@ -154,8 +186,7 @@ export class TestRailClient extends TestRailClientCore {
154
186
  * @throws {TestRailApiError} When the API request fails
155
187
  */
156
188
  async deleteSection(sectionId) {
157
- this.validateId(sectionId, 'sectionId');
158
- await this.request('POST', `delete_section/${sectionId}`);
189
+ return this.sections.deleteSection(sectionId);
159
190
  }
160
191
  // ── Cases ─────────────────────────────────────────────────────────────────
161
192
  /**
@@ -164,8 +195,7 @@ export class TestRailClient extends TestRailClientCore {
164
195
  * @throws {TestRailApiError} When the API request fails
165
196
  */
166
197
  async getCase(caseId) {
167
- this.validateId(caseId, 'caseId');
168
- return this.request('GET', `get_case/${caseId}`);
198
+ return this.cases.getCase(caseId);
169
199
  }
170
200
  /**
171
201
  * Get all cases for a project with optional filters.
@@ -185,37 +215,7 @@ export class TestRailClient extends TestRailClientCore {
185
215
  * @throws {TestRailApiError} When the API request fails
186
216
  */
187
217
  async getCases(projectId, options) {
188
- this.validateId(projectId, 'projectId');
189
- const { suiteId, sectionId, typeId, priorityId, templateId, milestoneId, createdAfter, createdBefore, updatedAfter, updatedBefore, limit, offset, } = options ?? {};
190
- if (suiteId !== undefined)
191
- this.validateId(suiteId, 'suiteId');
192
- if (sectionId !== undefined)
193
- this.validateId(sectionId, 'sectionId');
194
- if (typeId !== undefined)
195
- this.validateId(typeId, 'typeId');
196
- if (priorityId !== undefined)
197
- this.validateId(priorityId, 'priorityId');
198
- if (templateId !== undefined)
199
- this.validateId(templateId, 'templateId');
200
- if (milestoneId !== undefined)
201
- this.validateId(milestoneId, 'milestoneId');
202
- this.validatePaginationParams(limit, offset);
203
- const endpoint = this.buildEndpoint(`get_cases/${projectId}`, {
204
- suite_id: suiteId,
205
- section_id: sectionId,
206
- type_id: typeId,
207
- priority_id: priorityId,
208
- template_id: templateId,
209
- milestone_id: milestoneId,
210
- created_after: createdAfter,
211
- created_before: createdBefore,
212
- updated_after: updatedAfter,
213
- updated_before: updatedBefore,
214
- limit,
215
- offset,
216
- });
217
- const response = await this.request('GET', endpoint);
218
- return response.cases ?? [];
218
+ return this.cases.getCases(projectId, options);
219
219
  }
220
220
  /**
221
221
  * Add a new case to a section.
@@ -223,8 +223,7 @@ export class TestRailClient extends TestRailClientCore {
223
223
  * @throws {TestRailApiError} When the API request fails
224
224
  */
225
225
  async addCase(sectionId, payload) {
226
- this.validateId(sectionId, 'sectionId');
227
- return this.request('POST', `add_case/${sectionId}`, payload);
226
+ return this.cases.addCase(sectionId, payload);
228
227
  }
229
228
  /**
230
229
  * Update an existing case.
@@ -232,8 +231,7 @@ export class TestRailClient extends TestRailClientCore {
232
231
  * @throws {TestRailApiError} When the API request fails
233
232
  */
234
233
  async updateCase(caseId, payload) {
235
- this.validateId(caseId, 'caseId');
236
- return this.request('POST', `update_case/${caseId}`, payload);
234
+ return this.cases.updateCase(caseId, payload);
237
235
  }
238
236
  /**
239
237
  * Delete a case.
@@ -241,8 +239,7 @@ export class TestRailClient extends TestRailClientCore {
241
239
  * @throws {TestRailApiError} When the API request fails
242
240
  */
243
241
  async deleteCase(caseId) {
244
- this.validateId(caseId, 'caseId');
245
- await this.request('POST', `delete_case/${caseId}`);
242
+ return this.cases.deleteCase(caseId);
246
243
  }
247
244
  // ── Plans ─────────────────────────────────────────────────────────────────
248
245
  /**
@@ -251,8 +248,7 @@ export class TestRailClient extends TestRailClientCore {
251
248
  * @throws {TestRailApiError} When the API request fails
252
249
  */
253
250
  async getPlan(planId) {
254
- this.validateId(planId, 'planId');
255
- return this.request('GET', `get_plan/${planId}`);
251
+ return this.plans.getPlan(planId);
256
252
  }
257
253
  /**
258
254
  * Get all plans for a project with optional filters.
@@ -263,19 +259,7 @@ export class TestRailClient extends TestRailClientCore {
263
259
  * @throws {TestRailApiError} When the API request fails
264
260
  */
265
261
  async getPlans(projectId, options) {
266
- this.validateId(projectId, 'projectId');
267
- this.validatePaginationParams(options?.limit, options?.offset);
268
- const endpoint = this.buildEndpoint(`get_plans/${projectId}`, {
269
- created_after: options?.created_after,
270
- created_before: options?.created_before,
271
- created_by: this.serializeIdList(options?.created_by),
272
- is_completed: options?.is_completed,
273
- milestone_id: this.serializeIdList(options?.milestone_id),
274
- limit: options?.limit,
275
- offset: options?.offset,
276
- });
277
- const response = await this.request('GET', endpoint);
278
- return response.plans ?? [];
262
+ return this.plans.getPlans(projectId, options);
279
263
  }
280
264
  /**
281
265
  * Add a new plan to a project.
@@ -283,8 +267,7 @@ export class TestRailClient extends TestRailClientCore {
283
267
  * @throws {TestRailApiError} When the API request fails
284
268
  */
285
269
  async addPlan(projectId, payload) {
286
- this.validateId(projectId, 'projectId');
287
- return this.request('POST', `add_plan/${projectId}`, payload);
270
+ return this.plans.addPlan(projectId, payload);
288
271
  }
289
272
  /**
290
273
  * Update a plan.
@@ -292,8 +275,7 @@ export class TestRailClient extends TestRailClientCore {
292
275
  * @throws {TestRailApiError} When the API request fails
293
276
  */
294
277
  async updatePlan(planId, payload) {
295
- this.validateId(planId, 'planId');
296
- return this.request('POST', `update_plan/${planId}`, payload);
278
+ return this.plans.updatePlan(planId, payload);
297
279
  }
298
280
  /**
299
281
  * Close a plan.
@@ -301,8 +283,7 @@ export class TestRailClient extends TestRailClientCore {
301
283
  * @throws {TestRailApiError} When the API request fails
302
284
  */
303
285
  async closePlan(planId) {
304
- this.validateId(planId, 'planId');
305
- return this.request('POST', `close_plan/${planId}`);
286
+ return this.plans.closePlan(planId);
306
287
  }
307
288
  /**
308
289
  * Delete a plan.
@@ -310,8 +291,7 @@ export class TestRailClient extends TestRailClientCore {
310
291
  * @throws {TestRailApiError} When the API request fails
311
292
  */
312
293
  async deletePlan(planId) {
313
- this.validateId(planId, 'planId');
314
- await this.request('POST', `delete_plan/${planId}`);
294
+ return this.plans.deletePlan(planId);
315
295
  }
316
296
  /**
317
297
  * Add a plan entry (run) to a plan.
@@ -319,8 +299,7 @@ export class TestRailClient extends TestRailClientCore {
319
299
  * @throws {TestRailApiError} When the API request fails
320
300
  */
321
301
  async addPlanEntry(planId, payload) {
322
- this.validateId(planId, 'planId');
323
- return this.request('POST', `add_plan_entry/${planId}`, payload);
302
+ return this.plans.addPlanEntry(planId, payload);
324
303
  }
325
304
  /**
326
305
  * Update an existing plan entry.
@@ -328,9 +307,7 @@ export class TestRailClient extends TestRailClientCore {
328
307
  * @throws {TestRailApiError} When the API request fails
329
308
  */
330
309
  async updatePlanEntry(planId, entryId, payload) {
331
- this.validateId(planId, 'planId');
332
- this.validateEntryId(entryId);
333
- return this.request('POST', `update_plan_entry/${planId}/${entryId}`, payload);
310
+ return this.plans.updatePlanEntry(planId, entryId, payload);
334
311
  }
335
312
  /**
336
313
  * Delete a plan entry.
@@ -338,9 +315,7 @@ export class TestRailClient extends TestRailClientCore {
338
315
  * @throws {TestRailApiError} When the API request fails
339
316
  */
340
317
  async deletePlanEntry(planId, entryId) {
341
- this.validateId(planId, 'planId');
342
- this.validateEntryId(entryId);
343
- await this.request('POST', `delete_plan_entry/${planId}/${entryId}`);
318
+ return this.plans.deletePlanEntry(planId, entryId);
344
319
  }
345
320
  // ── Runs ──────────────────────────────────────────────────────────────────
346
321
  /**
@@ -349,8 +324,7 @@ export class TestRailClient extends TestRailClientCore {
349
324
  * @throws {TestRailApiError} When the API request fails
350
325
  */
351
326
  async getRun(runId) {
352
- this.validateId(runId, 'runId');
353
- return this.request('GET', `get_run/${runId}`);
327
+ return this.runs.getRun(runId);
354
328
  }
355
329
  /**
356
330
  * Get all runs for a project, with optional filters.
@@ -361,32 +335,7 @@ export class TestRailClient extends TestRailClientCore {
361
335
  * @throws {TestRailApiError} When the API request fails
362
336
  */
363
337
  async getRuns(projectId, options) {
364
- this.validateId(projectId, 'projectId');
365
- const { createdAfter, createdBefore, createdBy, isCompleted, milestoneId, refsFilter, suiteId, limit, offset } = options ?? {};
366
- this.validatePaginationParams(limit, offset);
367
- if (milestoneId !== undefined) {
368
- this.validateId(milestoneId, 'milestoneId');
369
- }
370
- if (suiteId !== undefined) {
371
- this.validateId(suiteId, 'suiteId');
372
- }
373
- if (createdBy !== undefined) {
374
- createdBy.forEach((userId) => this.validateId(userId, 'createdBy'));
375
- }
376
- const createdByFilter = createdBy && createdBy.length > 0 ? createdBy.join(',') : undefined;
377
- const endpoint = this.buildEndpoint(`get_runs/${projectId}`, {
378
- created_after: createdAfter,
379
- created_before: createdBefore,
380
- created_by: createdByFilter,
381
- is_completed: isCompleted !== undefined ? (isCompleted ? 1 : 0) : undefined,
382
- milestone_id: milestoneId,
383
- refs_filter: refsFilter,
384
- suite_id: suiteId,
385
- limit,
386
- offset,
387
- });
388
- const response = await this.request('GET', endpoint);
389
- return response.runs ?? [];
338
+ return this.runs.getRuns(projectId, options);
390
339
  }
391
340
  /**
392
341
  * Add a new run to a project.
@@ -394,8 +343,7 @@ export class TestRailClient extends TestRailClientCore {
394
343
  * @throws {TestRailApiError} When the API request fails
395
344
  */
396
345
  async addRun(projectId, payload) {
397
- this.validateId(projectId, 'projectId');
398
- return this.request('POST', `add_run/${projectId}`, payload);
346
+ return this.runs.addRun(projectId, payload);
399
347
  }
400
348
  /**
401
349
  * Update a run.
@@ -403,8 +351,7 @@ export class TestRailClient extends TestRailClientCore {
403
351
  * @throws {TestRailApiError} When the API request fails
404
352
  */
405
353
  async updateRun(runId, payload) {
406
- this.validateId(runId, 'runId');
407
- return this.request('POST', `update_run/${runId}`, payload);
354
+ return this.runs.updateRun(runId, payload);
408
355
  }
409
356
  /**
410
357
  * Close a run.
@@ -412,8 +359,7 @@ export class TestRailClient extends TestRailClientCore {
412
359
  * @throws {TestRailApiError} When the API request fails
413
360
  */
414
361
  async closeRun(runId) {
415
- this.validateId(runId, 'runId');
416
- return this.request('POST', `close_run/${runId}`);
362
+ return this.runs.closeRun(runId);
417
363
  }
418
364
  /**
419
365
  * Delete a run.
@@ -421,8 +367,7 @@ export class TestRailClient extends TestRailClientCore {
421
367
  * @throws {TestRailApiError} When the API request fails
422
368
  */
423
369
  async deleteRun(runId) {
424
- this.validateId(runId, 'runId');
425
- await this.request('POST', `delete_run/${runId}`);
370
+ return this.runs.deleteRun(runId);
426
371
  }
427
372
  // ── Tests ─────────────────────────────────────────────────────────────────
428
373
  /**
@@ -431,8 +376,7 @@ export class TestRailClient extends TestRailClientCore {
431
376
  * @throws {TestRailApiError} When the API request fails
432
377
  */
433
378
  async getTest(testId) {
434
- this.validateId(testId, 'testId');
435
- return this.request('GET', `get_test/${testId}`);
379
+ return this.tests.getTest(testId);
436
380
  }
437
381
  /**
438
382
  * Get all tests for a run with optional filters.
@@ -442,15 +386,7 @@ export class TestRailClient extends TestRailClientCore {
442
386
  * @throws {TestRailApiError} When the API request fails
443
387
  */
444
388
  async getTests(runId, options) {
445
- this.validateId(runId, 'runId');
446
- this.validatePaginationParams(options?.limit, options?.offset);
447
- const endpoint = this.buildEndpoint(`get_tests/${runId}`, {
448
- status_id: this.serializeIdList(options?.status_id),
449
- limit: options?.limit,
450
- offset: options?.offset,
451
- });
452
- const response = await this.request('GET', endpoint);
453
- return response.tests ?? [];
389
+ return this.tests.getTests(runId, options);
454
390
  }
455
391
  // ── Results ───────────────────────────────────────────────────────────────
456
392
  /**
@@ -462,18 +398,7 @@ export class TestRailClient extends TestRailClientCore {
462
398
  * @throws {TestRailApiError} When the API request fails
463
399
  */
464
400
  async getResults(testId, options) {
465
- this.validateId(testId, 'testId');
466
- this.validatePaginationParams(options?.limit, options?.offset);
467
- const endpoint = this.buildEndpoint(`get_results/${testId}`, {
468
- created_after: options?.created_after,
469
- created_before: options?.created_before,
470
- created_by: this.serializeIdList(options?.created_by),
471
- status_id: this.serializeIdList(options?.status_id),
472
- limit: options?.limit,
473
- offset: options?.offset,
474
- });
475
- const response = await this.request('GET', endpoint);
476
- return response.results ?? [];
401
+ return this.results.getResults(testId, options);
477
402
  }
478
403
  /**
479
404
  * Get results for a specific case within a run with optional filters.
@@ -485,19 +410,7 @@ export class TestRailClient extends TestRailClientCore {
485
410
  * @throws {TestRailApiError} When the API request fails
486
411
  */
487
412
  async getResultsForCase(runId, caseId, options) {
488
- this.validateId(runId, 'runId');
489
- this.validateId(caseId, 'caseId');
490
- this.validatePaginationParams(options?.limit, options?.offset);
491
- const endpoint = this.buildEndpoint(`get_results_for_case/${runId}/${caseId}`, {
492
- created_after: options?.created_after,
493
- created_before: options?.created_before,
494
- created_by: this.serializeIdList(options?.created_by),
495
- status_id: this.serializeIdList(options?.status_id),
496
- limit: options?.limit,
497
- offset: options?.offset,
498
- });
499
- const response = await this.request('GET', endpoint);
500
- return response.results ?? [];
413
+ return this.results.getResultsForCase(runId, caseId, options);
501
414
  }
502
415
  /**
503
416
  * Get all results for a run with optional filters.
@@ -508,18 +421,7 @@ export class TestRailClient extends TestRailClientCore {
508
421
  * @throws {TestRailApiError} When the API request fails
509
422
  */
510
423
  async getResultsForRun(runId, options) {
511
- this.validateId(runId, 'runId');
512
- this.validatePaginationParams(options?.limit, options?.offset);
513
- const endpoint = this.buildEndpoint(`get_results_for_run/${runId}`, {
514
- created_after: options?.created_after,
515
- created_before: options?.created_before,
516
- created_by: this.serializeIdList(options?.created_by),
517
- status_id: this.serializeIdList(options?.status_id),
518
- limit: options?.limit,
519
- offset: options?.offset,
520
- });
521
- const response = await this.request('GET', endpoint);
522
- return response.results ?? [];
424
+ return this.results.getResultsForRun(runId, options);
523
425
  }
524
426
  /**
525
427
  * Add a result for a test.
@@ -527,8 +429,7 @@ export class TestRailClient extends TestRailClientCore {
527
429
  * @throws {TestRailApiError} When the API request fails
528
430
  */
529
431
  async addResult(testId, payload) {
530
- this.validateId(testId, 'testId');
531
- return this.request('POST', `add_result/${testId}`, payload);
432
+ return this.results.addResult(testId, payload);
532
433
  }
533
434
  /**
534
435
  * Add a result for a specific case within a run.
@@ -536,9 +437,7 @@ export class TestRailClient extends TestRailClientCore {
536
437
  * @throws {TestRailApiError} When the API request fails
537
438
  */
538
439
  async addResultForCase(runId, caseId, payload) {
539
- this.validateId(runId, 'runId');
540
- this.validateId(caseId, 'caseId');
541
- return this.request('POST', `add_result_for_case/${runId}/${caseId}`, payload);
440
+ return this.results.addResultForCase(runId, caseId, payload);
542
441
  }
543
442
  /**
544
443
  * Add multiple results for cases in a run.
@@ -546,8 +445,7 @@ export class TestRailClient extends TestRailClientCore {
546
445
  * @throws {TestRailApiError} When the API request fails
547
446
  */
548
447
  async addResultsForCases(runId, payload) {
549
- this.validateId(runId, 'runId');
550
- return this.request('POST', `add_results_for_cases/${runId}`, payload);
448
+ return this.results.addResultsForCases(runId, payload);
551
449
  }
552
450
  // ── Milestones ────────────────────────────────────────────────────────────
553
451
  /**
@@ -556,551 +454,594 @@ export class TestRailClient extends TestRailClientCore {
556
454
  * @throws {TestRailApiError} When the API request fails
557
455
  */
558
456
  async getMilestone(milestoneId) {
559
- this.validateId(milestoneId, 'milestoneId');
560
- return this.request('GET', `get_milestone/${milestoneId}`);
457
+ return this.milestones.getMilestone(milestoneId);
561
458
  }
562
459
  /**
563
- * Get all milestones for a project with optional filters.
564
- * @param projectId - The project ID
565
- * @param options - Optional filter parameters (is_completed, limit, offset)
566
- * @throws {TestRailValidationError} When projectId is invalid
460
+ * Get milestones.
461
+ *
462
+ * @param projectId - Project identifier.
463
+ * @param options - Optional filters and pagination settings.
464
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
567
465
  * @throws {TestRailApiError} When the API request fails
568
466
  */
569
467
  async getMilestones(projectId, options) {
570
- this.validateId(projectId, 'projectId');
571
- this.validatePaginationParams(options?.limit, options?.offset);
572
- const endpoint = this.buildEndpoint(`get_milestones/${projectId}`, {
573
- is_completed: options?.is_completed,
574
- limit: options?.limit,
575
- offset: options?.offset,
576
- });
577
- const response = await this.request('GET', endpoint);
578
- return response.milestones ?? [];
579
- }
580
- /**
581
- * Add a new milestone to a project.
582
- * @throws {TestRailValidationError} When projectId is invalid
468
+ return this.milestones.getMilestones(projectId, options);
469
+ }
470
+ /**
471
+ * Add milestone.
472
+ *
473
+ * @param projectId - Project identifier.
474
+ * @param payload - Request payload for this operation.
475
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
583
476
  * @throws {TestRailApiError} When the API request fails
584
477
  */
585
478
  async addMilestone(projectId, payload) {
586
- this.validateId(projectId, 'projectId');
587
- return this.request('POST', `add_milestone/${projectId}`, payload);
479
+ return this.milestones.addMilestone(projectId, payload);
588
480
  }
589
481
  /**
590
- * Update an existing milestone.
591
- * @throws {TestRailValidationError} When milestoneId is invalid
482
+ * Update milestone.
483
+ *
484
+ * @param milestoneId - Milestone identifier.
485
+ * @param payload - Request payload for this operation.
486
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
592
487
  * @throws {TestRailApiError} When the API request fails
593
488
  */
594
489
  async updateMilestone(milestoneId, payload) {
595
- this.validateId(milestoneId, 'milestoneId');
596
- return this.request('POST', `update_milestone/${milestoneId}`, payload);
490
+ return this.milestones.updateMilestone(milestoneId, payload);
597
491
  }
598
492
  /**
599
- * Delete a milestone.
600
- * @throws {TestRailValidationError} When milestoneId is invalid
493
+ * Delete milestone.
494
+ *
495
+ * @param milestoneId - Milestone identifier.
496
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
601
497
  * @throws {TestRailApiError} When the API request fails
602
498
  */
603
499
  async deleteMilestone(milestoneId) {
604
- this.validateId(milestoneId, 'milestoneId');
605
- await this.request('POST', `delete_milestone/${milestoneId}`);
500
+ return this.milestones.deleteMilestone(milestoneId);
606
501
  }
607
502
  // ── Users ─────────────────────────────────────────────────────────────────
608
503
  /**
609
- * Get a user by ID.
610
- * @throws {TestRailValidationError} When userId is invalid
504
+ * Get user.
505
+ *
506
+ * @param userId - User identifier.
507
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
611
508
  * @throws {TestRailApiError} When the API request fails
612
509
  */
613
510
  async getUser(userId) {
614
- this.validateId(userId, 'userId');
615
- return this.request('GET', `get_user/${userId}`);
511
+ return this.users.getUser(userId);
616
512
  }
617
513
  /**
618
- * Get a user by email address.
514
+ * Get user by email.
515
+ *
516
+ * @param email - Email address to look up.
619
517
  * @throws {TestRailValidationError} When email format is invalid
620
518
  * @throws {TestRailApiError} When the API request fails
621
519
  */
622
520
  async getUserByEmail(email) {
623
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
624
- if (!emailRegex.test(email)) {
625
- throw new TestRailValidationError('Invalid email format');
626
- }
627
- // buildEndpoint now encodes all values via encodeURIComponent internally.
628
- return this.request('GET', this.buildEndpoint('get_user_by_email', { email }));
521
+ return this.users.getUserByEmail(email);
629
522
  }
630
523
  /**
631
- * Get all users, optionally scoped to a project.
632
- * @param limit - Maximum number of users to return
633
- * @param offset - Number of users to skip
634
- * @param projectId - When provided, returns only users with access to the specified project
635
- * @throws {TestRailValidationError} When pagination or projectId is invalid
524
+ * Get users.
525
+ *
526
+ * @param limit - Optional maximum number of results to return.
527
+ * @param offset - Optional number of results to skip before returning results.
528
+ * @param projectId - Optional project identifier to scope results when provided.
529
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
636
530
  * @throws {TestRailApiError} When the API request fails
637
531
  */
638
532
  async getUsers(limit, offset, projectId) {
639
- this.validatePaginationParams(limit, offset);
640
- if (projectId !== undefined) {
641
- this.validateId(projectId, 'projectId');
642
- }
643
- const endpoint = this.buildEndpoint(projectId !== undefined ? `get_users/${projectId}` : 'get_users', {
644
- limit,
645
- offset,
646
- });
647
- const response = await this.request('GET', endpoint);
648
- return response.users ?? [];
533
+ return this.users.getUsers(limit, offset, projectId);
649
534
  }
650
535
  /**
651
536
  * Get the currently authenticated user.
652
537
  * @throws {TestRailApiError} When the API request fails
653
538
  */
654
539
  async getCurrentUser() {
655
- return this.request('GET', 'get_current_user');
540
+ return this.users.getCurrentUser();
541
+ }
542
+ /**
543
+ * Add user.
544
+ *
545
+ * @param payload - Request payload for this operation.
546
+ * @throws {TestRailApiError} When the API request fails
547
+ */
548
+ async addUser(payload) {
549
+ return this.users.addUser(payload);
550
+ }
551
+ /**
552
+ * Update user.
553
+ *
554
+ * @param userId - User identifier.
555
+ * @param payload - Request payload for this operation.
556
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
557
+ * @throws {TestRailApiError} When the API request fails
558
+ */
559
+ async updateUser(userId, payload) {
560
+ return this.users.updateUser(userId, payload);
656
561
  }
657
562
  // ── Statuses ──────────────────────────────────────────────────────────────
658
563
  /**
659
- * Get all test statuses.
564
+ * Get statuses.
660
565
  * @throws {TestRailApiError} When the API request fails
661
566
  */
662
567
  async getStatuses() {
663
- return this.request('GET', 'get_statuses');
568
+ return this.metadata.getStatuses();
664
569
  }
665
570
  // ── Priorities ────────────────────────────────────────────────────────────
666
571
  /**
667
- * Get all case priorities.
572
+ * Get priorities.
668
573
  * @throws {TestRailApiError} When the API request fails
669
574
  */
670
575
  async getPriorities() {
671
- return this.request('GET', 'get_priorities');
576
+ return this.metadata.getPriorities();
672
577
  }
673
578
  // ── Result Fields ─────────────────────────────────────────────────────────
674
579
  /**
675
- * Get all available custom result fields.
580
+ * Get result fields.
676
581
  * @throws {TestRailApiError} When the API request fails
677
582
  */
678
583
  async getResultFields() {
679
- return this.request('GET', 'get_result_fields');
584
+ return this.metadata.getResultFields();
680
585
  }
681
586
  // ── Case Fields & Types ───────────────────────────────────────────────────
682
587
  /**
683
- * Get all available custom case fields.
588
+ * Get case fields.
684
589
  * @throws {TestRailApiError} When the API request fails
685
590
  */
686
591
  async getCaseFields() {
687
- return this.request('GET', 'get_case_fields');
592
+ return this.metadata.getCaseFields();
688
593
  }
689
594
  /**
690
- * Get all available case types.
595
+ * Get case types.
691
596
  * @throws {TestRailApiError} When the API request fails
692
597
  */
693
598
  async getCaseTypes() {
694
- return this.request('GET', 'get_case_types');
599
+ return this.metadata.getCaseTypes();
695
600
  }
696
601
  // ── Templates ─────────────────────────────────────────────────────────────
697
602
  /**
698
- * Get all available case templates for a project (requires TestRail 5.2+).
699
- * @throws {TestRailValidationError} When projectId is invalid
603
+ * Get templates.
604
+ *
605
+ * @param projectId - Project identifier.
606
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
700
607
  * @throws {TestRailApiError} When the API request fails
701
608
  */
702
609
  async getTemplates(projectId) {
703
- this.validateId(projectId, 'projectId');
704
- return this.request('GET', `get_templates/${projectId}`);
610
+ return this.metadata.getTemplates(projectId);
705
611
  }
706
612
  // ── Configurations ────────────────────────────────────────────────────────
707
613
  /**
708
- * Get all configuration groups and their configurations for a project.
709
- * @throws {TestRailValidationError} When projectId is invalid
614
+ * Get configurations.
615
+ *
616
+ * @param projectId - Project identifier.
617
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
710
618
  * @throws {TestRailApiError} When the API request fails
711
619
  */
712
620
  async getConfigurations(projectId) {
713
- this.validateId(projectId, 'projectId');
714
- return this.request('GET', `get_configs/${projectId}`);
621
+ return this.configurations.getConfigurations(projectId);
715
622
  }
716
623
  /**
717
- * Add a new configuration group to a project.
718
- * @throws {TestRailValidationError} When projectId is invalid
624
+ * Add configuration group.
625
+ *
626
+ * @param projectId - Project identifier.
627
+ * @param payload - Request payload for this operation.
628
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
719
629
  * @throws {TestRailApiError} When the API request fails
720
630
  */
721
631
  async addConfigurationGroup(projectId, payload) {
722
- this.validateId(projectId, 'projectId');
723
- return this.request('POST', `add_config_group/${projectId}`, payload);
632
+ return this.configurations.addConfigurationGroup(projectId, payload);
724
633
  }
725
634
  /**
726
- * Update an existing configuration group.
727
- * @throws {TestRailValidationError} When configGroupId is invalid
635
+ * Update configuration group.
636
+ *
637
+ * @param configGroupId - Config group identifier.
638
+ * @param payload - Request payload for this operation.
639
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
728
640
  * @throws {TestRailApiError} When the API request fails
729
641
  */
730
642
  async updateConfigurationGroup(configGroupId, payload) {
731
- this.validateId(configGroupId, 'configGroupId');
732
- return this.request('POST', `update_config_group/${configGroupId}`, payload);
643
+ return this.configurations.updateConfigurationGroup(configGroupId, payload);
733
644
  }
734
645
  /**
735
- * Delete an existing configuration group and all its configurations.
736
- * @throws {TestRailValidationError} When configGroupId is invalid
646
+ * Delete configuration group.
647
+ *
648
+ * @param configGroupId - Config group identifier.
649
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
737
650
  * @throws {TestRailApiError} When the API request fails
738
651
  */
739
652
  async deleteConfigurationGroup(configGroupId) {
740
- this.validateId(configGroupId, 'configGroupId');
741
- await this.request('POST', `delete_config_group/${configGroupId}`);
653
+ return this.configurations.deleteConfigurationGroup(configGroupId);
742
654
  }
743
655
  /**
744
- * Add a new configuration to a configuration group.
745
- * @throws {TestRailValidationError} When configGroupId is invalid
656
+ * Add configuration.
657
+ *
658
+ * @param configGroupId - Config group identifier.
659
+ * @param payload - Request payload for this operation.
660
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
746
661
  * @throws {TestRailApiError} When the API request fails
747
662
  */
748
663
  async addConfiguration(configGroupId, payload) {
749
- this.validateId(configGroupId, 'configGroupId');
750
- return this.request('POST', `add_config/${configGroupId}`, payload);
664
+ return this.configurations.addConfiguration(configGroupId, payload);
751
665
  }
752
666
  /**
753
- * Update an existing configuration.
754
- * @throws {TestRailValidationError} When configId is invalid
667
+ * Update configuration.
668
+ *
669
+ * @param configId - Config identifier.
670
+ * @param payload - Request payload for this operation.
671
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
755
672
  * @throws {TestRailApiError} When the API request fails
756
673
  */
757
674
  async updateConfiguration(configId, payload) {
758
- this.validateId(configId, 'configId');
759
- return this.request('POST', `update_config/${configId}`, payload);
675
+ return this.configurations.updateConfiguration(configId, payload);
760
676
  }
761
677
  /**
762
- * Delete an existing configuration.
763
- * @throws {TestRailValidationError} When configId is invalid
678
+ * Delete configuration.
679
+ *
680
+ * @param configId - Config identifier.
681
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
764
682
  * @throws {TestRailApiError} When the API request fails
765
683
  */
766
684
  async deleteConfiguration(configId) {
767
- this.validateId(configId, 'configId');
768
- await this.request('POST', `delete_config/${configId}`);
769
- }
770
- // ── User Management (TASK-024, requires TestRail 7.3+) ────────────────────
771
- /**
772
- * Create a new TestRail user (requires TestRail 7.3+).
773
- * @throws {TestRailApiError} When the API request fails
774
- */
775
- async addUser(payload) {
776
- return this.request('POST', 'add_user', payload);
777
- }
778
- /**
779
- * Update an existing TestRail user (requires TestRail 7.3+).
780
- * @throws {TestRailValidationError} When userId is invalid
781
- * @throws {TestRailApiError} When the API request fails
782
- */
783
- async updateUser(userId, payload) {
784
- this.validateId(userId, 'userId');
785
- return this.request('POST', `update_user/${userId}`, payload);
685
+ return this.configurations.deleteConfiguration(configId);
786
686
  }
787
- // ── Roles (TASK-025, requires TestRail 7.3+) ──────────────────────────────
687
+ // ── Roles ─────────────────────────────────────────────────────────────────
788
688
  /**
789
- * Get all available user roles (requires TestRail 7.3+).
689
+ * Get roles.
790
690
  * @throws {TestRailApiError} When the API request fails
791
691
  */
792
692
  async getRoles() {
793
- return this.request('GET', 'get_roles');
693
+ return this.metadata.getRoles();
794
694
  }
795
- // ── Groups (TASK-026, requires TestRail 7.5+) ─────────────────────────────
695
+ // ── Groups ────────────────────────────────────────────────────────────────
796
696
  /**
797
- * Get a single group by ID (requires TestRail 7.5+).
798
- * @throws {TestRailValidationError} When groupId is invalid
697
+ * Get group.
698
+ *
699
+ * @param groupId - Group identifier.
700
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
799
701
  * @throws {TestRailApiError} When the API request fails
800
702
  */
801
703
  async getGroup(groupId) {
802
- this.validateId(groupId, 'groupId');
803
- return this.request('GET', `get_group/${groupId}`);
704
+ return this.users.getGroup(groupId);
804
705
  }
805
706
  /**
806
- * Get all groups (requires TestRail 7.5+).
707
+ * Get groups.
807
708
  * @throws {TestRailApiError} When the API request fails
808
709
  */
809
710
  async getGroups() {
810
- return this.request('GET', 'get_groups');
711
+ return this.users.getGroups();
811
712
  }
812
713
  /**
813
- * Create a new group (requires TestRail 7.5+).
714
+ * Add group.
715
+ *
716
+ * @param payload - Request payload for this operation.
814
717
  * @throws {TestRailApiError} When the API request fails
815
718
  */
816
719
  async addGroup(payload) {
817
- return this.request('POST', 'add_group', payload);
720
+ return this.users.addGroup(payload);
818
721
  }
819
722
  /**
820
- * Update an existing group (requires TestRail 7.5+).
821
- * @throws {TestRailValidationError} When groupId is invalid
723
+ * Update group.
724
+ *
725
+ * @param groupId - Group identifier.
726
+ * @param payload - Request payload for this operation.
727
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
822
728
  * @throws {TestRailApiError} When the API request fails
823
729
  */
824
730
  async updateGroup(groupId, payload) {
825
- this.validateId(groupId, 'groupId');
826
- return this.request('POST', `update_group/${groupId}`, payload);
731
+ return this.users.updateGroup(groupId, payload);
827
732
  }
828
733
  /**
829
- * Delete a group (requires TestRail 7.5+).
830
- * @throws {TestRailValidationError} When groupId is invalid
734
+ * Delete group.
735
+ *
736
+ * @param groupId - Group identifier.
737
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
831
738
  * @throws {TestRailApiError} When the API request fails
832
739
  */
833
740
  async deleteGroup(groupId) {
834
- this.validateId(groupId, 'groupId');
835
- await this.request('POST', `delete_group/${groupId}`);
741
+ return this.users.deleteGroup(groupId);
836
742
  }
837
- // ── Attachments (TASK-027) ────────────────────────────────────────────────
743
+ // ── Attachments ───────────────────────────────────────────────────────────
838
744
  /**
839
- * Get all attachments for a test case.
840
- * @throws {TestRailValidationError} When caseId is invalid
745
+ * Get attachments for case.
746
+ *
747
+ * @param caseId - Case identifier.
748
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
841
749
  * @throws {TestRailApiError} When the API request fails
842
750
  */
843
751
  async getAttachmentsForCase(caseId) {
844
- this.validateId(caseId, 'caseId');
845
- const response = await this.request('GET', `get_attachments_for_case/${caseId}`);
846
- return response.attachments ?? [];
752
+ return this.attachments.getAttachmentsForCase(caseId);
847
753
  }
848
754
  /**
849
- * Get all attachments for a test run.
850
- * @throws {TestRailValidationError} When runId is invalid
755
+ * Get attachments for run.
756
+ *
757
+ * @param runId - Run identifier.
758
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
851
759
  * @throws {TestRailApiError} When the API request fails
852
760
  */
853
761
  async getAttachmentsForRun(runId) {
854
- this.validateId(runId, 'runId');
855
- const response = await this.request('GET', `get_attachments_for_run/${runId}`);
856
- return response.attachments ?? [];
762
+ return this.attachments.getAttachmentsForRun(runId);
857
763
  }
858
764
  /**
859
- * Get all attachments for a test.
860
- * @throws {TestRailValidationError} When testId is invalid
765
+ * Get attachments for test.
766
+ *
767
+ * @param testId - Test identifier.
768
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
861
769
  * @throws {TestRailApiError} When the API request fails
862
770
  */
863
771
  async getAttachmentsForTest(testId) {
864
- this.validateId(testId, 'testId');
865
- const response = await this.request('GET', `get_attachments_for_test/${testId}`);
866
- return response.attachments ?? [];
772
+ return this.attachments.getAttachmentsForTest(testId);
867
773
  }
868
774
  /**
869
- * Get all attachments for a test plan.
870
- * @throws {TestRailValidationError} When planId is invalid
775
+ * Get attachments for plan.
776
+ *
777
+ * @param planId - Plan identifier.
778
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
871
779
  * @throws {TestRailApiError} When the API request fails
872
780
  */
873
781
  async getAttachmentsForPlan(planId) {
874
- this.validateId(planId, 'planId');
875
- const response = await this.request('GET', `get_attachments_for_plan/${planId}`);
876
- return response.attachments ?? [];
782
+ return this.attachments.getAttachmentsForPlan(planId);
877
783
  }
878
784
  /**
879
- * Get all attachments for a specific plan entry.
880
- * @throws {TestRailValidationError} When planId or entryId is invalid
785
+ * Get attachments for plan entry.
786
+ *
787
+ * @param planId - Plan identifier.
788
+ * @param entryId - Plan entry identifier.
789
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
881
790
  * @throws {TestRailApiError} When the API request fails
882
791
  */
883
792
  async getAttachmentsForPlanEntry(planId, entryId) {
884
- this.validateId(planId, 'planId');
885
- this.validateId(entryId, 'entryId');
886
- const response = await this.request('GET', `get_attachments_for_plan_entry/${planId}/${entryId}`);
887
- return response.attachments ?? [];
793
+ return this.attachments.getAttachmentsForPlanEntry(planId, entryId);
888
794
  }
889
795
  /**
890
- * Download the raw binary content of an attachment.
891
- * @param attachmentId - The attachment ID (numeric)
892
- * @throws {TestRailValidationError} When attachmentId is invalid
796
+ * Download an attachment by ID.
797
+ *
798
+ * @param attachmentId - Attachment identifier.
799
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
893
800
  * @throws {TestRailApiError} When the API request fails
894
801
  */
895
802
  async getAttachment(attachmentId) {
896
- this.validateId(attachmentId, 'attachmentId');
897
- return this.requestBinary(`get_attachment/${attachmentId}`);
803
+ return this.attachments.getAttachment(attachmentId);
898
804
  }
899
805
  /**
900
- * Upload a file attachment to a test case.
901
- * @throws {TestRailValidationError} When caseId is invalid
806
+ * Add attachment to case.
807
+ *
808
+ * @param caseId - Case identifier.
809
+ * @param file - Attachment contents to upload.
810
+ * @param filename - Filename to send with the uploaded attachment.
811
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
902
812
  * @throws {TestRailApiError} When the API request fails
903
813
  */
904
814
  async addAttachmentToCase(caseId, file, filename) {
905
- this.validateId(caseId, 'caseId');
906
- return this.requestMultipart(`add_attachment_to_case/${caseId}`, file, filename);
815
+ return this.attachments.addAttachmentToCase(caseId, file, filename);
907
816
  }
908
817
  /**
909
- * Upload a file attachment to a test result.
910
- * @throws {TestRailValidationError} When resultId is invalid
818
+ * Add attachment to result.
819
+ *
820
+ * @param resultId - Result identifier.
821
+ * @param file - Attachment contents to upload.
822
+ * @param filename - Filename to send with the uploaded attachment.
823
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
911
824
  * @throws {TestRailApiError} When the API request fails
912
825
  */
913
826
  async addAttachmentToResult(resultId, file, filename) {
914
- this.validateId(resultId, 'resultId');
915
- return this.requestMultipart(`add_attachment_to_result/${resultId}`, file, filename);
827
+ return this.attachments.addAttachmentToResult(resultId, file, filename);
916
828
  }
917
829
  /**
918
- * Upload a file attachment to a test run.
919
- * @throws {TestRailValidationError} When runId is invalid
830
+ * Add attachment to run.
831
+ *
832
+ * @param runId - Run identifier.
833
+ * @param file - Attachment contents to upload.
834
+ * @param filename - Filename to send with the uploaded attachment.
835
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
920
836
  * @throws {TestRailApiError} When the API request fails
921
837
  */
922
838
  async addAttachmentToRun(runId, file, filename) {
923
- this.validateId(runId, 'runId');
924
- return this.requestMultipart(`add_attachment_to_run/${runId}`, file, filename);
839
+ return this.attachments.addAttachmentToRun(runId, file, filename);
925
840
  }
926
841
  /**
927
- * Upload a file attachment to a test plan (requires TestRail 6.5.2+).
928
- * @throws {TestRailValidationError} When planId is invalid
842
+ * Add attachment to plan.
843
+ *
844
+ * @param planId - Plan identifier.
845
+ * @param file - Attachment contents to upload.
846
+ * @param filename - Filename to send with the uploaded attachment.
847
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
929
848
  * @throws {TestRailApiError} When the API request fails
930
849
  */
931
850
  async addAttachmentToPlan(planId, file, filename) {
932
- this.validateId(planId, 'planId');
933
- return this.requestMultipart(`add_attachment_to_plan/${planId}`, file, filename);
851
+ return this.attachments.addAttachmentToPlan(planId, file, filename);
934
852
  }
935
853
  /**
936
- * Upload a file attachment to a specific plan entry (requires TestRail 6.5.2+).
937
- * @throws {TestRailValidationError} When planId or entryId is invalid
854
+ * Add attachment to plan entry.
855
+ *
856
+ * @param planId - Plan identifier.
857
+ * @param entryId - Plan entry identifier.
858
+ * @param file - Attachment contents to upload.
859
+ * @param filename - Filename to send with the uploaded attachment.
860
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
938
861
  * @throws {TestRailApiError} When the API request fails
939
862
  */
940
863
  async addAttachmentToPlanEntry(planId, entryId, file, filename) {
941
- this.validateId(planId, 'planId');
942
- this.validateId(entryId, 'entryId');
943
- return this.requestMultipart(`add_attachment_to_plan_entry/${planId}/${entryId}`, file, filename);
864
+ return this.attachments.addAttachmentToPlanEntry(planId, entryId, file, filename);
944
865
  }
945
866
  /**
946
- * Delete an attachment by ID.
947
- * @throws {TestRailValidationError} When attachmentId is invalid
867
+ * Delete attachment.
868
+ *
869
+ * @param attachmentId - Attachment identifier.
870
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
948
871
  * @throws {TestRailApiError} When the API request fails
949
872
  */
950
873
  async deleteAttachment(attachmentId) {
951
- this.validateId(attachmentId, 'attachmentId');
952
- await this.request('POST', `delete_attachment/${attachmentId}`);
874
+ return this.attachments.deleteAttachment(attachmentId);
953
875
  }
954
- // ── Shared Steps (TASK-028, requires TestRail 7.0+) ───────────────────────
876
+ // ── Shared Steps ──────────────────────────────────────────────────────────
955
877
  /**
956
- * Get a single shared step by ID (requires TestRail 7.0+).
957
- * @throws {TestRailValidationError} When sharedStepId is invalid
878
+ * Get shared step.
879
+ *
880
+ * @param sharedStepId - Shared step identifier.
881
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
958
882
  * @throws {TestRailApiError} When the API request fails
959
883
  */
960
884
  async getSharedStep(sharedStepId) {
961
- this.validateId(sharedStepId, 'sharedStepId');
962
- return this.request('GET', `get_shared_step/${sharedStepId}`);
885
+ return this.sharedSteps.getSharedStep(sharedStepId);
963
886
  }
964
887
  /**
965
- * Get all shared steps for a project (requires TestRail 7.0+).
966
- * @throws {TestRailValidationError} When projectId is invalid
888
+ * Get shared steps.
889
+ *
890
+ * @param projectId - Project identifier.
891
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
967
892
  * @throws {TestRailApiError} When the API request fails
968
893
  */
969
894
  async getSharedSteps(projectId) {
970
- this.validateId(projectId, 'projectId');
971
- return this.request('GET', `get_shared_steps/${projectId}`);
895
+ return this.sharedSteps.getSharedSteps(projectId);
972
896
  }
973
897
  /**
974
- * Create a new shared step in a project (requires TestRail 7.0+).
975
- * @throws {TestRailValidationError} When projectId is invalid
898
+ * Add shared step.
899
+ *
900
+ * @param projectId - Project identifier.
901
+ * @param payload - Request payload for this operation.
902
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
976
903
  * @throws {TestRailApiError} When the API request fails
977
904
  */
978
905
  async addSharedStep(projectId, payload) {
979
- this.validateId(projectId, 'projectId');
980
- return this.request('POST', `add_shared_step/${projectId}`, payload);
906
+ return this.sharedSteps.addSharedStep(projectId, payload);
981
907
  }
982
908
  /**
983
- * Update an existing shared step (requires TestRail 7.0+).
984
- * @throws {TestRailValidationError} When sharedStepId is invalid
909
+ * Update shared step.
910
+ *
911
+ * @param sharedStepId - Shared step identifier.
912
+ * @param payload - Request payload for this operation.
913
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
985
914
  * @throws {TestRailApiError} When the API request fails
986
915
  */
987
916
  async updateSharedStep(sharedStepId, payload) {
988
- this.validateId(sharedStepId, 'sharedStepId');
989
- return this.request('POST', `update_shared_step/${sharedStepId}`, payload);
917
+ return this.sharedSteps.updateSharedStep(sharedStepId, payload);
990
918
  }
991
919
  /**
992
- * Delete a shared step (requires TestRail 7.0+).
993
- * @throws {TestRailValidationError} When sharedStepId is invalid
920
+ * Delete shared step.
921
+ *
922
+ * @param sharedStepId - Shared step identifier.
923
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
994
924
  * @throws {TestRailApiError} When the API request fails
995
925
  */
996
926
  async deleteSharedStep(sharedStepId) {
997
- this.validateId(sharedStepId, 'sharedStepId');
998
- await this.request('POST', `delete_shared_step/${sharedStepId}`);
927
+ return this.sharedSteps.deleteSharedStep(sharedStepId);
999
928
  }
1000
- // ── Variables (TASK-029) ──────────────────────────────────────────────────
929
+ // ── Variables ─────────────────────────────────────────────────────────────
1001
930
  /**
1002
- * Get all variables for a project.
1003
- * @throws {TestRailValidationError} When projectId is invalid
931
+ * Get variables.
932
+ *
933
+ * @param projectId - Project identifier.
934
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
1004
935
  * @throws {TestRailApiError} When the API request fails
1005
936
  */
1006
937
  async getVariables(projectId) {
1007
- this.validateId(projectId, 'projectId');
1008
- return this.request('GET', `get_variables/${projectId}`);
938
+ return this.variables.getVariables(projectId);
1009
939
  }
1010
940
  /**
1011
- * Create a new variable in a project.
1012
- * @throws {TestRailValidationError} When projectId is invalid
941
+ * Add variable.
942
+ *
943
+ * @param projectId - Project identifier.
944
+ * @param payload - Request payload for this operation.
945
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
1013
946
  * @throws {TestRailApiError} When the API request fails
1014
947
  */
1015
948
  async addVariable(projectId, payload) {
1016
- this.validateId(projectId, 'projectId');
1017
- return this.request('POST', `add_variable/${projectId}`, payload);
949
+ return this.variables.addVariable(projectId, payload);
1018
950
  }
1019
951
  /**
1020
- * Update an existing variable.
1021
- * @throws {TestRailValidationError} When variableId is invalid
952
+ * Update variable.
953
+ *
954
+ * @param variableId - Variable identifier.
955
+ * @param payload - Request payload for this operation.
956
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
1022
957
  * @throws {TestRailApiError} When the API request fails
1023
958
  */
1024
959
  async updateVariable(variableId, payload) {
1025
- this.validateId(variableId, 'variableId');
1026
- return this.request('POST', `update_variable/${variableId}`, payload);
960
+ return this.variables.updateVariable(variableId, payload);
1027
961
  }
1028
962
  /**
1029
- * Delete a variable.
1030
- * @throws {TestRailValidationError} When variableId is invalid
963
+ * Delete variable.
964
+ *
965
+ * @param variableId - Variable identifier.
966
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
1031
967
  * @throws {TestRailApiError} When the API request fails
1032
968
  */
1033
969
  async deleteVariable(variableId) {
1034
- this.validateId(variableId, 'variableId');
1035
- await this.request('POST', `delete_variable/${variableId}`);
970
+ return this.variables.deleteVariable(variableId);
1036
971
  }
1037
- // ── Datasets (TASK-030) ───────────────────────────────────────────────────
972
+ // ── Datasets ──────────────────────────────────────────────────────────────
1038
973
  /**
1039
- * Get a single dataset by ID.
1040
- * @throws {TestRailValidationError} When datasetId is invalid
974
+ * Get dataset.
975
+ *
976
+ * @param datasetId - Dataset identifier.
977
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
1041
978
  * @throws {TestRailApiError} When the API request fails
1042
979
  */
1043
980
  async getDataset(datasetId) {
1044
- this.validateId(datasetId, 'datasetId');
1045
- return this.request('GET', `get_dataset/${datasetId}`);
981
+ return this.datasets.getDataset(datasetId);
1046
982
  }
1047
983
  /**
1048
- * Get all datasets for a project.
1049
- * @throws {TestRailValidationError} When projectId is invalid
984
+ * Get datasets.
985
+ *
986
+ * @param projectId - Project identifier.
987
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
1050
988
  * @throws {TestRailApiError} When the API request fails
1051
989
  */
1052
990
  async getDatasets(projectId) {
1053
- this.validateId(projectId, 'projectId');
1054
- return this.request('GET', `get_datasets/${projectId}`);
991
+ return this.datasets.getDatasets(projectId);
1055
992
  }
1056
993
  /**
1057
- * Create a new dataset in a project.
1058
- * @throws {TestRailValidationError} When projectId is invalid
994
+ * Add dataset.
995
+ *
996
+ * @param projectId - Project identifier.
997
+ * @param payload - Request payload for this operation.
998
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
1059
999
  * @throws {TestRailApiError} When the API request fails
1060
1000
  */
1061
1001
  async addDataset(projectId, payload) {
1062
- this.validateId(projectId, 'projectId');
1063
- return this.request('POST', `add_dataset/${projectId}`, payload);
1002
+ return this.datasets.addDataset(projectId, payload);
1064
1003
  }
1065
1004
  /**
1066
- * Update an existing dataset.
1067
- * @throws {TestRailValidationError} When datasetId is invalid
1005
+ * Update dataset.
1006
+ *
1007
+ * @param datasetId - Dataset identifier.
1008
+ * @param payload - Request payload for this operation.
1009
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
1068
1010
  * @throws {TestRailApiError} When the API request fails
1069
1011
  */
1070
1012
  async updateDataset(datasetId, payload) {
1071
- this.validateId(datasetId, 'datasetId');
1072
- return this.request('POST', `update_dataset/${datasetId}`, payload);
1013
+ return this.datasets.updateDataset(datasetId, payload);
1073
1014
  }
1074
1015
  /**
1075
- * Delete a dataset.
1076
- * @throws {TestRailValidationError} When datasetId is invalid
1016
+ * Delete dataset.
1017
+ *
1018
+ * @param datasetId - Dataset identifier.
1019
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
1077
1020
  * @throws {TestRailApiError} When the API request fails
1078
1021
  */
1079
1022
  async deleteDataset(datasetId) {
1080
- this.validateId(datasetId, 'datasetId');
1081
- await this.request('POST', `delete_dataset/${datasetId}`);
1023
+ return this.datasets.deleteDataset(datasetId);
1082
1024
  }
1083
- // ── Reports (TASK-031) ────────────────────────────────────────────────────
1025
+ // ── Reports ───────────────────────────────────────────────────────────────
1084
1026
  /**
1085
- * Get all available report templates for a project.
1086
- * @throws {TestRailValidationError} When projectId is invalid
1027
+ * Get reports.
1028
+ *
1029
+ * @param projectId - Project identifier.
1030
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
1087
1031
  * @throws {TestRailApiError} When the API request fails
1088
1032
  */
1089
1033
  async getReports(projectId) {
1090
- this.validateId(projectId, 'projectId');
1091
- return this.request('GET', `get_reports/${projectId}`);
1034
+ return this.reports.getReports(projectId);
1092
1035
  }
1093
1036
  /**
1094
- * Execute a report template and return URLs to the generated output.
1095
- * @throws {TestRailValidationError} When reportTemplateId is invalid
1037
+ * Run report.
1038
+ *
1039
+ * @param reportTemplateId - Report template identifier.
1040
+ * @throws {TestRailValidationError} When identifiers or request parameters are invalid
1096
1041
  * @throws {TestRailApiError} When the API request fails
1097
1042
  */
1098
1043
  async runReport(reportTemplateId) {
1099
- this.validateId(reportTemplateId, 'reportTemplateId');
1100
- return this.request('GET', `run_report/${reportTemplateId}`);
1101
- }
1102
- serializeIdList(ids) {
1103
- return ids !== undefined && ids.length > 0 ? ids.join(',') : undefined;
1044
+ return this.reports.runReport(reportTemplateId);
1104
1045
  }
1105
1046
  }
1106
1047
  //# sourceMappingURL=client.js.map