@uarlouski/testrail-mcp-server 1.3.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/testrail.js +167 -0
- package/{src/index.ts → dist/index.js} +25 -35
- package/{src/tools/add_attachment_to_run.ts → dist/tools/add_attachment_to_run.js} +8 -18
- package/{src/tools/add_results.ts → dist/tools/add_results.js} +3 -7
- package/{src/tools/add_run.ts → dist/tools/add_run.js} +3 -8
- package/{src/tools/create_case.ts → dist/tools/create_case.js} +1 -7
- package/{src/tools/get_case.ts → dist/tools/get_case.js} +2 -11
- package/{src/tools/get_case_fields.ts → dist/tools/get_case_fields.js} +8 -37
- package/{src/tools/get_cases.ts → dist/tools/get_cases.js} +5 -19
- package/{src/tools/get_projects.ts → dist/tools/get_projects.js} +1 -6
- package/{src/tools/get_sections.ts → dist/tools/get_sections.js} +1 -6
- package/{src/tools/get_statuses.ts → dist/tools/get_statuses.js} +2 -7
- package/{src/tools/get_templates.ts → dist/tools/get_templates.js} +1 -6
- package/{src/tools/get_tests.ts → dist/tools/get_tests.js} +5 -10
- package/{src/tools/update_case.ts → dist/tools/update_case.js} +1 -7
- package/{src/tools/update_cases.ts → dist/tools/update_cases.js} +1 -6
- package/dist/types/custom.js +1 -0
- package/{src/types/testrail.ts → dist/types/testrail.js} +2 -42
- package/{src/utils/mapper.ts → dist/utils/mapper.js} +16 -36
- package/{src/utils/sanitizer.ts → dist/utils/sanitizer.js} +4 -8
- package/package.json +8 -2
- package/.env.example +0 -3
- package/.github/workflows/ci.yml +0 -46
- package/.github/workflows/publish.yml +0 -35
- package/CHANGELOG.md +0 -38
- package/jest.config.js +0 -24
- package/src/client/testrail.ts +0 -227
- package/src/types/custom.ts +0 -19
- package/test/client/testrail.test.ts +0 -545
- package/test/tools/add_results.test.ts +0 -94
- package/test/tools/add_run.test.ts +0 -83
- package/test/tools/create_case.test.ts +0 -101
- package/test/tools/get_case.test.ts +0 -185
- package/test/tools/get_case_fields.test.ts +0 -132
- package/test/tools/get_cases.test.ts +0 -104
- package/test/tools/get_projects.test.ts +0 -38
- package/test/tools/get_sections.test.ts +0 -39
- package/test/tools/get_statuses.test.ts +0 -56
- package/test/tools/get_templates.test.ts +0 -38
- package/test/tools/get_tests.test.ts +0 -47
- package/test/tools/update_case.test.ts +0 -102
- package/test/tools/update_cases.test.ts +0 -89
- package/test/utils/mapper.test.ts +0 -112
- package/test/utils/sanitizer.test.ts +0 -143
- package/tsconfig.json +0 -24
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { TestRailClient } from "../client/testrail.js";
|
|
3
|
-
import { ToolDefinition } from "../types/custom.js";
|
|
4
2
|
import { TemplateSchema } from "../types/testrail.js";
|
|
5
|
-
|
|
6
3
|
const parameters = {
|
|
7
4
|
project_id: z.string().describe("The ID of the project. Use get_projects to find available projects"),
|
|
8
5
|
};
|
|
9
|
-
|
|
10
|
-
export const getTemplatesTool: ToolDefinition<typeof parameters, TestRailClient> = {
|
|
6
|
+
export const getTemplatesTool = {
|
|
11
7
|
name: "get_templates",
|
|
12
8
|
description: "Get available test case templates for a project. Template IDs determine which fields are available when creating or updating test cases",
|
|
13
9
|
parameters,
|
|
14
10
|
handler: async ({ project_id }, client) => {
|
|
15
11
|
const templates = await client.getTemplates(project_id);
|
|
16
|
-
|
|
17
12
|
return {
|
|
18
13
|
templates: templates.map(t => TemplateSchema.parse(t)),
|
|
19
14
|
};
|
|
@@ -1,20 +1,15 @@
|
|
|
1
|
-
import { TestRailClient } from "../client/testrail.js";
|
|
2
1
|
import { z } from "zod";
|
|
3
|
-
import {
|
|
4
|
-
import { ToolDefinition } from "../types/custom.js";
|
|
5
|
-
|
|
2
|
+
import { TestSchema } from "../types/testrail.js";
|
|
6
3
|
const parameters = {
|
|
7
4
|
run_id: z.number().describe("The ID of the test run"),
|
|
8
5
|
status_id: z.array(z.number()).optional().describe("Optional array of status IDs to filter by. Use get_statuses to retrieve available status IDs"),
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export const getTestsTool: ToolDefinition<typeof parameters, TestRailClient> = {
|
|
6
|
+
};
|
|
7
|
+
export const getTestsTool = {
|
|
12
8
|
name: "get_tests",
|
|
13
9
|
description: "Get tests for a test run, optionally filtered by status",
|
|
14
10
|
parameters,
|
|
15
|
-
handler: async ({ run_id, status_id }, client
|
|
16
|
-
const tests
|
|
17
|
-
|
|
11
|
+
handler: async ({ run_id, status_id }, client) => {
|
|
12
|
+
const tests = await client.getTests(run_id, status_id);
|
|
18
13
|
return {
|
|
19
14
|
tests: tests.map(test => TestSchema.parse(test)),
|
|
20
15
|
};
|
|
@@ -1,21 +1,15 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { TestRailClient } from "../client/testrail.js";
|
|
3
|
-
import { ToolDefinition } from "../types/custom.js";
|
|
4
|
-
|
|
5
2
|
const parameters = {
|
|
6
3
|
case_id: z.string().describe("The ID of the test case to update (e.g. '123' or 'C123')"),
|
|
7
4
|
fields: z.record(z.string(), z.any()).describe("Object containing fields to update. Use get_case_fields to see available fields. Example: {\"title\": \"New title\", \"priority_id\": 2, \"custom_automation_priority\": 1}"),
|
|
8
5
|
};
|
|
9
|
-
|
|
10
|
-
export const updateCaseTool: ToolDefinition<typeof parameters, TestRailClient> = {
|
|
6
|
+
export const updateCaseTool = {
|
|
11
7
|
name: "update_case",
|
|
12
8
|
description: "Update a test case in TestRail. Supports partial updates - only specify the fields you want to change",
|
|
13
9
|
parameters,
|
|
14
10
|
handler: async ({ case_id, fields }, client) => {
|
|
15
11
|
const id = case_id.toUpperCase().startsWith("C") ? case_id.substring(1) : case_id;
|
|
16
|
-
|
|
17
12
|
const updatedCase = await client.updateCase(id, fields);
|
|
18
|
-
|
|
19
13
|
return {
|
|
20
14
|
success: true,
|
|
21
15
|
case_id: updatedCase.id,
|
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { TestRailClient } from "../client/testrail.js";
|
|
3
|
-
import { ToolDefinition } from "../types/custom.js";
|
|
4
|
-
|
|
5
2
|
const parameters = {
|
|
6
3
|
case_ids: z.array(z.number()).describe("Array of case IDs to update (e.g. [123, 456, 789])"),
|
|
7
4
|
fields: z.record(z.string(), z.any()).describe("Object containing fields to update for ALL specified cases. Use get_case_fields to see available fields. Example: {\"priority_id\": 2, \"type_id\": 1}"),
|
|
8
5
|
};
|
|
9
|
-
|
|
10
|
-
export const updateCasesTool: ToolDefinition<typeof parameters, TestRailClient> = {
|
|
6
|
+
export const updateCasesTool = {
|
|
11
7
|
name: "update_cases",
|
|
12
8
|
description: "Bulk update multiple test cases with the same field values. More efficient than calling update_case multiple times",
|
|
13
9
|
parameters,
|
|
14
10
|
handler: async ({ case_ids, fields }, client) => {
|
|
15
11
|
const caseData = await client.getCase(String(case_ids[0]));
|
|
16
12
|
const updatedCases = await client.updateCases(caseData.suite_id, case_ids, fields);
|
|
17
|
-
|
|
18
13
|
return {
|
|
19
14
|
success: true,
|
|
20
15
|
updated_count: updatedCases.length,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
|
|
3
2
|
export const CaseFieldConfigSchema = z.object({
|
|
4
3
|
options: z.object({
|
|
5
4
|
default_value: z.string().optional(),
|
|
@@ -7,9 +6,6 @@ export const CaseFieldConfigSchema = z.object({
|
|
|
7
6
|
items: z.string().optional(),
|
|
8
7
|
}),
|
|
9
8
|
});
|
|
10
|
-
|
|
11
|
-
export type CaseFieldConfig = z.infer<typeof CaseFieldConfigSchema>;
|
|
12
|
-
|
|
13
9
|
export const CaseFieldSchema = z.object({
|
|
14
10
|
id: z.number(),
|
|
15
11
|
name: z.string(),
|
|
@@ -22,9 +18,6 @@ export const CaseFieldSchema = z.object({
|
|
|
22
18
|
include_all: z.boolean(),
|
|
23
19
|
configs: z.array(CaseFieldConfigSchema),
|
|
24
20
|
});
|
|
25
|
-
|
|
26
|
-
export type CaseField = z.infer<typeof CaseFieldSchema>;
|
|
27
|
-
|
|
28
21
|
export const CaseSchema = z.object({
|
|
29
22
|
id: z.number(),
|
|
30
23
|
title: z.string(),
|
|
@@ -40,9 +33,6 @@ export const CaseSchema = z.object({
|
|
|
40
33
|
suite_id: z.number(),
|
|
41
34
|
labels: z.array(z.any()),
|
|
42
35
|
}).loose();
|
|
43
|
-
|
|
44
|
-
export type Case = z.infer<typeof CaseSchema>;
|
|
45
|
-
|
|
46
36
|
export const SectionSchema = z.object({
|
|
47
37
|
id: z.number(),
|
|
48
38
|
name: z.string(),
|
|
@@ -50,42 +40,27 @@ export const SectionSchema = z.object({
|
|
|
50
40
|
parent_id: z.number().nullish(),
|
|
51
41
|
suite_id: z.number(),
|
|
52
42
|
});
|
|
53
|
-
|
|
54
|
-
export type Section = z.infer<typeof SectionSchema>;
|
|
55
|
-
|
|
56
43
|
export const PrioritySchema = z.object({
|
|
57
44
|
id: z.number(),
|
|
58
45
|
is_default: z.boolean(),
|
|
59
46
|
name: z.string(),
|
|
60
47
|
});
|
|
61
|
-
|
|
62
|
-
export type Priority = z.infer<typeof PrioritySchema>;
|
|
63
|
-
|
|
64
48
|
export const CaseTypeSchema = z.object({
|
|
65
49
|
id: z.number(),
|
|
66
50
|
is_default: z.boolean(),
|
|
67
51
|
name: z.string(),
|
|
68
52
|
});
|
|
69
|
-
|
|
70
|
-
export type CaseType = z.infer<typeof CaseTypeSchema>;
|
|
71
|
-
|
|
72
53
|
export const TemplateSchema = z.object({
|
|
73
54
|
id: z.number(),
|
|
74
55
|
name: z.string(),
|
|
75
56
|
is_default: z.boolean(),
|
|
76
57
|
});
|
|
77
|
-
|
|
78
|
-
export type Template = z.infer<typeof TemplateSchema>;
|
|
79
|
-
|
|
80
58
|
export const ProjectSchema = z.object({
|
|
81
59
|
id: z.number(),
|
|
82
60
|
name: z.string(),
|
|
83
61
|
is_completed: z.boolean(),
|
|
84
62
|
suite_mode: z.number(),
|
|
85
63
|
});
|
|
86
|
-
|
|
87
|
-
export type Project = z.infer<typeof ProjectSchema>;
|
|
88
|
-
|
|
89
64
|
export const RunSchema = z.object({
|
|
90
65
|
id: z.number(),
|
|
91
66
|
name: z.string(),
|
|
@@ -100,29 +75,19 @@ export const RunSchema = z.object({
|
|
|
100
75
|
failed_count: z.number(),
|
|
101
76
|
url: z.string(),
|
|
102
77
|
});
|
|
103
|
-
|
|
104
|
-
export type Run = z.infer<typeof RunSchema>;
|
|
105
|
-
|
|
106
78
|
export const StatusSchema = z.object({
|
|
107
79
|
id: z.number(),
|
|
108
80
|
name: z.string(),
|
|
109
81
|
label: z.string(),
|
|
110
82
|
});
|
|
111
|
-
|
|
112
|
-
export type Status = z.infer<typeof StatusSchema>;
|
|
113
|
-
|
|
114
83
|
export const TestSchema = z.object({
|
|
115
84
|
id: z.number(),
|
|
116
85
|
case_id: z.number(),
|
|
117
86
|
status_id: z.number(),
|
|
118
87
|
title: z.string(),
|
|
119
88
|
run_id: z.number(),
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
export const TestsSchema = z.array(TestSchema)
|
|
123
|
-
|
|
124
|
-
export type Test = z.infer<typeof TestSchema>
|
|
125
|
-
|
|
89
|
+
});
|
|
90
|
+
export const TestsSchema = z.array(TestSchema);
|
|
126
91
|
export const ResultSchema = z.object({
|
|
127
92
|
id: z.number(),
|
|
128
93
|
test_id: z.number(),
|
|
@@ -130,11 +95,6 @@ export const ResultSchema = z.object({
|
|
|
130
95
|
comment: z.string().nullable(),
|
|
131
96
|
defects: z.string().nullable(),
|
|
132
97
|
});
|
|
133
|
-
|
|
134
|
-
export type Result = z.infer<typeof ResultSchema>
|
|
135
|
-
|
|
136
98
|
export const AttachmentSchema = z.object({
|
|
137
99
|
attachment_id: z.number(),
|
|
138
100
|
});
|
|
139
|
-
|
|
140
|
-
export type Attachment = z.infer<typeof AttachmentSchema>
|
|
@@ -1,73 +1,55 @@
|
|
|
1
|
-
import { Case, CaseField } from "../types/testrail.js";
|
|
2
1
|
import { sanitizeValue } from "./sanitizer.js";
|
|
3
|
-
|
|
4
2
|
/**
|
|
5
3
|
* Processes custom fields from a test case, converting system names to human-readable labels
|
|
6
4
|
* and mapping dropdown values to their display text.
|
|
7
5
|
*/
|
|
8
|
-
export function processCustomFields(
|
|
9
|
-
testCase: Case,
|
|
10
|
-
caseFields: CaseField[]
|
|
11
|
-
): Record<string, any> {
|
|
6
|
+
export function processCustomFields(testCase, caseFields) {
|
|
12
7
|
if (!testCase) {
|
|
13
8
|
throw new Error("Test case is undefined or null");
|
|
14
9
|
}
|
|
15
|
-
|
|
16
10
|
const templateId = testCase.template_id;
|
|
17
|
-
const result
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
);
|
|
22
|
-
|
|
23
|
-
const fieldNameMap = new Map<string, string>();
|
|
24
|
-
const dropdownOptionsMap = new Map<string, Map<string, string>>();
|
|
25
|
-
|
|
11
|
+
const result = {};
|
|
12
|
+
const applicableFields = caseFields.filter(field => field.include_all || field.template_ids.includes(templateId));
|
|
13
|
+
const fieldNameMap = new Map();
|
|
14
|
+
const dropdownOptionsMap = new Map();
|
|
26
15
|
for (const field of applicableFields) {
|
|
27
16
|
fieldNameMap.set(field.system_name, toSnakeCase(field.label));
|
|
28
|
-
|
|
29
17
|
const optionsMap = parseDropdownOptions(field);
|
|
30
18
|
if (optionsMap.size > 0) {
|
|
31
19
|
dropdownOptionsMap.set(field.system_name, optionsMap);
|
|
32
20
|
}
|
|
33
21
|
}
|
|
34
|
-
|
|
35
22
|
for (const [key, value] of Object.entries(testCase)) {
|
|
36
|
-
if (!key.startsWith("custom_"))
|
|
37
|
-
|
|
38
|
-
|
|
23
|
+
if (!key.startsWith("custom_"))
|
|
24
|
+
continue;
|
|
25
|
+
if (value === null || value === undefined)
|
|
26
|
+
continue;
|
|
39
27
|
if (!fieldNameMap.has(key)) {
|
|
40
28
|
console.error(`No field mapping found for: ${key}`);
|
|
41
29
|
result[key] = value;
|
|
42
30
|
continue;
|
|
43
31
|
}
|
|
44
|
-
|
|
45
|
-
const outputKey = fieldNameMap.get(key)!;
|
|
32
|
+
const outputKey = fieldNameMap.get(key);
|
|
46
33
|
let finalValue = value;
|
|
47
|
-
|
|
48
34
|
if (dropdownOptionsMap.has(key)) {
|
|
49
|
-
const options = dropdownOptionsMap.get(key)
|
|
35
|
+
const options = dropdownOptionsMap.get(key);
|
|
50
36
|
const optionKey = String(value);
|
|
51
37
|
finalValue = options.get(optionKey) || value;
|
|
52
38
|
}
|
|
53
|
-
|
|
54
39
|
result[outputKey] = sanitizeValue(finalValue);
|
|
55
40
|
}
|
|
56
|
-
|
|
57
41
|
return result;
|
|
58
42
|
}
|
|
59
|
-
|
|
60
43
|
/**
|
|
61
44
|
* Parse dropdown options from field configs.
|
|
62
45
|
* Format: "1, First\n2, Second\n3, Third"
|
|
63
46
|
*/
|
|
64
|
-
export function parseDropdownOptions(field
|
|
65
|
-
const options = new Map
|
|
66
|
-
|
|
47
|
+
export function parseDropdownOptions(field) {
|
|
48
|
+
const options = new Map();
|
|
67
49
|
for (const config of field.configs) {
|
|
68
50
|
const items = config.options?.items;
|
|
69
|
-
if (!items)
|
|
70
|
-
|
|
51
|
+
if (!items)
|
|
52
|
+
continue;
|
|
71
53
|
const lines = items.split('\n');
|
|
72
54
|
for (const line of lines) {
|
|
73
55
|
const commaIndex = line.indexOf(',');
|
|
@@ -78,11 +60,9 @@ export function parseDropdownOptions(field: CaseField): Map<string, string> {
|
|
|
78
60
|
}
|
|
79
61
|
}
|
|
80
62
|
}
|
|
81
|
-
|
|
82
63
|
return options;
|
|
83
64
|
}
|
|
84
|
-
|
|
85
|
-
function toSnakeCase(str: string): string {
|
|
65
|
+
function toSnakeCase(str) {
|
|
86
66
|
return str
|
|
87
67
|
.toLowerCase()
|
|
88
68
|
.replace(/[^a-z0-9]+/g, '_')
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* in an object or array. Useful for cleaning up TestRail markdown content before sending
|
|
4
4
|
* to LLMs.
|
|
5
5
|
*/
|
|
6
|
-
export function sanitizeValue(value
|
|
6
|
+
export function sanitizeValue(value) {
|
|
7
7
|
if (typeof value === 'string') {
|
|
8
8
|
return value.replace(/\s*style\s*=\s*["'][^"']*["']/gi, '');
|
|
9
9
|
}
|
|
@@ -11,7 +11,7 @@ export function sanitizeValue(value: any): any {
|
|
|
11
11
|
return value.map(sanitizeValue);
|
|
12
12
|
}
|
|
13
13
|
if (value !== null && typeof value === 'object') {
|
|
14
|
-
const result
|
|
14
|
+
const result = {};
|
|
15
15
|
for (const [key, val] of Object.entries(value)) {
|
|
16
16
|
result[key] = sanitizeValue(val);
|
|
17
17
|
}
|
|
@@ -19,24 +19,21 @@ export function sanitizeValue(value: any): any {
|
|
|
19
19
|
}
|
|
20
20
|
return value;
|
|
21
21
|
}
|
|
22
|
-
|
|
23
22
|
/**
|
|
24
23
|
* Recursively removes null and undefined values from objects and arrays.
|
|
25
24
|
* For arrays, filters nested object items as well.
|
|
26
25
|
*/
|
|
27
|
-
export function removeNullish(value
|
|
26
|
+
export function removeNullish(value) {
|
|
28
27
|
if (value == null) {
|
|
29
28
|
return value;
|
|
30
29
|
}
|
|
31
|
-
|
|
32
30
|
if (Array.isArray(value)) {
|
|
33
31
|
return value
|
|
34
32
|
.map(item => removeNullish(item))
|
|
35
33
|
.filter(item => item != null);
|
|
36
34
|
}
|
|
37
|
-
|
|
38
35
|
if (typeof value === 'object') {
|
|
39
|
-
const result
|
|
36
|
+
const result = {};
|
|
40
37
|
for (const [key, val] of Object.entries(value)) {
|
|
41
38
|
const cleanedVal = removeNullish(val);
|
|
42
39
|
if (cleanedVal != null) {
|
|
@@ -45,6 +42,5 @@ export function removeNullish(value: any): any {
|
|
|
45
42
|
}
|
|
46
43
|
return result;
|
|
47
44
|
}
|
|
48
|
-
|
|
49
45
|
return value;
|
|
50
46
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uarlouski/testrail-mcp-server",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "Model Context Protocol (MCP) server for TestRail integration, enabling LLMs to fetch test cases and metadata.",
|
|
5
|
-
"main": "index.js",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"testrail-mcp-server": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
6
12
|
"type": "module",
|
|
7
13
|
"scripts": {
|
|
8
14
|
"build": "rimraf dist && tsc",
|
package/.env.example
DELETED
package/.github/workflows/ci.yml
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: ["main"]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: ["main"]
|
|
8
|
-
|
|
9
|
-
jobs:
|
|
10
|
-
build-and-test:
|
|
11
|
-
name: Build and Test (Node ${{ matrix.node-version }})
|
|
12
|
-
runs-on: ubuntu-latest
|
|
13
|
-
|
|
14
|
-
strategy:
|
|
15
|
-
matrix:
|
|
16
|
-
node-version: [18.x, 20.x, 22.x]
|
|
17
|
-
|
|
18
|
-
steps:
|
|
19
|
-
- name: Checkout code
|
|
20
|
-
uses: actions/checkout@v4
|
|
21
|
-
|
|
22
|
-
- name: Setup Node.js ${{ matrix.node-version }}
|
|
23
|
-
uses: actions/setup-node@v4
|
|
24
|
-
with:
|
|
25
|
-
node-version: ${{ matrix.node-version }}
|
|
26
|
-
cache: "npm"
|
|
27
|
-
|
|
28
|
-
- name: Install dependencies
|
|
29
|
-
run: npm ci
|
|
30
|
-
|
|
31
|
-
- name: Run tests
|
|
32
|
-
run: npm test
|
|
33
|
-
|
|
34
|
-
- name: Run tests with coverage
|
|
35
|
-
run: npm run test:coverage
|
|
36
|
-
|
|
37
|
-
- name: Build project
|
|
38
|
-
run: npm run build
|
|
39
|
-
|
|
40
|
-
- name: Upload coverage reports
|
|
41
|
-
uses: actions/upload-artifact@v4
|
|
42
|
-
if: matrix.node-version == '20.x'
|
|
43
|
-
with:
|
|
44
|
-
name: coverage-report
|
|
45
|
-
path: coverage/
|
|
46
|
-
retention-days: 7
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
name: Publish to NPM
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
release:
|
|
5
|
-
types: [published]
|
|
6
|
-
|
|
7
|
-
jobs:
|
|
8
|
-
publish:
|
|
9
|
-
runs-on: ubuntu-latest
|
|
10
|
-
permissions:
|
|
11
|
-
contents: read
|
|
12
|
-
id-token: write
|
|
13
|
-
steps:
|
|
14
|
-
- name: Checkout code
|
|
15
|
-
uses: actions/checkout@v4
|
|
16
|
-
|
|
17
|
-
- name: Setup Node.js
|
|
18
|
-
uses: actions/setup-node@v4
|
|
19
|
-
with:
|
|
20
|
-
node-version: "20.x"
|
|
21
|
-
registry-url: "https://registry.npmjs.org"
|
|
22
|
-
|
|
23
|
-
- name: Install dependencies
|
|
24
|
-
run: npm ci
|
|
25
|
-
|
|
26
|
-
- name: Run tests
|
|
27
|
-
run: npm test
|
|
28
|
-
|
|
29
|
-
- name: Build package
|
|
30
|
-
run: npm run build
|
|
31
|
-
|
|
32
|
-
- name: Publish to NPM
|
|
33
|
-
run: npm publish --provenance --access public
|
|
34
|
-
env:
|
|
35
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/CHANGELOG.md
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
## [1.3.0] - 2026-02-18
|
|
4
|
-
|
|
5
|
-
### Added
|
|
6
|
-
|
|
7
|
-
- **Test run and result management tools**
|
|
8
|
-
- `add_run` - Create a new test run in TestRail
|
|
9
|
-
- `get_tests` - Get tests for a test run, optionally filtered by status
|
|
10
|
-
- `add_results` - Add one or more test results to a test run
|
|
11
|
-
- `get_statuses` - Get all available test statuses (e.g. Passed, Failed, Blocked)
|
|
12
|
-
- Add `add_attachment_to_run` tool to attach files to test runs
|
|
13
|
-
|
|
14
|
-
## [1.2.0] - 2026-02-14
|
|
15
|
-
|
|
16
|
-
### Changed
|
|
17
|
-
|
|
18
|
-
- Optimize MCP call responses by removing non-essential fields and nullish values
|
|
19
|
-
- Migrated from `axios` to native `fetch` API for reduced dependency footprint
|
|
20
|
-
|
|
21
|
-
## [1.1.0] - 2026-02-09
|
|
22
|
-
|
|
23
|
-
### Added
|
|
24
|
-
|
|
25
|
-
- **Configuration via environment variables**
|
|
26
|
-
- `TESTRAIL_INSTANCE_URL` - Your TestRail instance URL
|
|
27
|
-
- `TESTRAIL_USERNAME` - Your TestRail username
|
|
28
|
-
- `TESTRAIL_API_KEY` - [How to get your API key](https://support.testrail.com/hc/en-us/articles/7077039051412-Accessing-the-TestRail-API)
|
|
29
|
-
|
|
30
|
-
- **Test case management tools**
|
|
31
|
-
- `get_projects` - Discover available projects in your TestRail instance
|
|
32
|
-
- `get_case` - Fetch detailed test case info including custom fields
|
|
33
|
-
- `get_cases` - Query cases with filtering and pagination support
|
|
34
|
-
- `get_case_fields` - Explore available fields and dropdown options
|
|
35
|
-
- `get_templates` - List project templates to understand case structures
|
|
36
|
-
- `get_sections` - Navigate the test case hierarchy
|
|
37
|
-
- `create_case` - Create new test cases with full custom field support
|
|
38
|
-
- `update_case` / `update_cases` - Modify single or bulk update cases
|
package/jest.config.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
preset: 'ts-jest/presets/default-esm',
|
|
3
|
-
testEnvironment: 'node',
|
|
4
|
-
extensionsToTreatAsEsm: ['.ts'],
|
|
5
|
-
moduleNameMapper: {
|
|
6
|
-
'^(\\.{1,2}/.*)\\.js$': '$1',
|
|
7
|
-
},
|
|
8
|
-
transform: {
|
|
9
|
-
'^.+\\.tsx?$': [
|
|
10
|
-
'ts-jest',
|
|
11
|
-
{
|
|
12
|
-
useESM: true,
|
|
13
|
-
},
|
|
14
|
-
],
|
|
15
|
-
},
|
|
16
|
-
coverageThreshold: {
|
|
17
|
-
global: {
|
|
18
|
-
branches: 95,
|
|
19
|
-
functions: 95,
|
|
20
|
-
lines: 95,
|
|
21
|
-
statements: 95,
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
};
|