@debugg-ai/debugg-ai-mcp 2.6.1 → 2.8.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/CHANGELOG.md +15 -0
- package/dist/config/index.js +11 -1
- package/dist/handlers/createTestCaseHandler.js +46 -0
- package/dist/handlers/createTestSuiteHandler.js +31 -0
- package/dist/handlers/deleteTestCaseHandler.js +20 -0
- package/dist/handlers/deleteTestSuiteHandler.js +38 -0
- package/dist/handlers/getTestSuiteResultsHandler.js +38 -0
- package/dist/handlers/index.js +8 -0
- package/dist/handlers/probePageHandler.js +48 -41
- package/dist/handlers/runTestSuiteHandler.js +122 -0
- package/dist/handlers/searchTestSuitesHandler.js +36 -0
- package/dist/handlers/testPageChangesHandler.js +63 -57
- package/dist/handlers/triggerCrawlHandler.js +43 -37
- package/dist/handlers/updateTestCaseHandler.js +24 -0
- package/dist/services/index.js +145 -0
- package/dist/services/workflows.js +17 -1
- package/dist/tools/index.js +17 -0
- package/dist/tools/testSuiteTools.js +183 -0
- package/dist/types/index.js +51 -0
- package/dist/utils/resolveProject.js +27 -0
- package/package.json +1 -1
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { CreateTestSuiteInputSchema, SearchTestSuitesInputSchema, DeleteTestSuiteInputSchema, CreateTestCaseInputSchema, UpdateTestCaseInputSchema, DeleteTestCaseInputSchema, RunTestSuiteInputSchema, GetTestSuiteResultsInputSchema, } from '../types/index.js';
|
|
2
|
+
import { createTestSuiteHandler } from '../handlers/createTestSuiteHandler.js';
|
|
3
|
+
import { searchTestSuitesHandler } from '../handlers/searchTestSuitesHandler.js';
|
|
4
|
+
import { deleteTestSuiteHandler } from '../handlers/deleteTestSuiteHandler.js';
|
|
5
|
+
import { createTestCaseHandler } from '../handlers/createTestCaseHandler.js';
|
|
6
|
+
import { updateTestCaseHandler } from '../handlers/updateTestCaseHandler.js';
|
|
7
|
+
import { deleteTestCaseHandler } from '../handlers/deleteTestCaseHandler.js';
|
|
8
|
+
import { runTestSuiteHandler } from '../handlers/runTestSuiteHandler.js';
|
|
9
|
+
import { getTestSuiteResultsHandler } from '../handlers/getTestSuiteResultsHandler.js';
|
|
10
|
+
const PROJECT_PROPS = {
|
|
11
|
+
projectUuid: { type: 'string', description: 'Project UUID. Provide projectUuid OR projectName.' },
|
|
12
|
+
projectName: { type: 'string', description: 'Project name (case-insensitive exact match). Provide projectUuid OR projectName.' },
|
|
13
|
+
};
|
|
14
|
+
const SUITE_PROPS = {
|
|
15
|
+
suiteUuid: { type: 'string', description: 'Test suite UUID. Provide suiteUuid OR (suiteName + project identifier).' },
|
|
16
|
+
suiteName: { type: 'string', description: 'Test suite name (case-insensitive exact match). Requires projectUuid or projectName.' },
|
|
17
|
+
};
|
|
18
|
+
// ── create_test_suite ─────────────────────────────────────────────────────────
|
|
19
|
+
export function buildCreateTestSuiteTool() {
|
|
20
|
+
return {
|
|
21
|
+
name: 'create_test_suite',
|
|
22
|
+
title: 'Create Test Suite',
|
|
23
|
+
description: 'Create a named test suite for a project. A test suite is a collection of test cases that can be run together. Requires name, description, and a project identifier (projectUuid or projectName). Returns {uuid, name, description, runStatus, testsCount}.',
|
|
24
|
+
inputSchema: {
|
|
25
|
+
type: 'object',
|
|
26
|
+
properties: {
|
|
27
|
+
name: { type: 'string', description: 'Suite name. Required.', minLength: 1 },
|
|
28
|
+
description: { type: 'string', description: 'Suite description. Required.', minLength: 1 },
|
|
29
|
+
...PROJECT_PROPS,
|
|
30
|
+
},
|
|
31
|
+
required: ['name', 'description'],
|
|
32
|
+
additionalProperties: false,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export function buildValidatedCreateTestSuiteTool() {
|
|
37
|
+
return { ...buildCreateTestSuiteTool(), inputSchema: CreateTestSuiteInputSchema, handler: createTestSuiteHandler };
|
|
38
|
+
}
|
|
39
|
+
// ── search_test_suites ────────────────────────────────────────────────────────
|
|
40
|
+
export function buildSearchTestSuitesTool() {
|
|
41
|
+
return {
|
|
42
|
+
name: 'search_test_suites',
|
|
43
|
+
title: 'Search Test Suites',
|
|
44
|
+
description: 'List and search test suites for a project. Returns paginated results with suite status, test counts, pass rates, and last run timestamps. Requires a project identifier (projectUuid or projectName). Optional: search text filter, page, pageSize (1-100, default 20).',
|
|
45
|
+
inputSchema: {
|
|
46
|
+
type: 'object',
|
|
47
|
+
properties: {
|
|
48
|
+
...PROJECT_PROPS,
|
|
49
|
+
search: { type: 'string', description: 'Optional text filter applied to suite name and description.' },
|
|
50
|
+
page: { type: 'number', description: 'Page number (default 1).', minimum: 1 },
|
|
51
|
+
pageSize: { type: 'number', description: 'Results per page (default 20, max 100).', minimum: 1, maximum: 100 },
|
|
52
|
+
},
|
|
53
|
+
additionalProperties: false,
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export function buildValidatedSearchTestSuitesTool() {
|
|
58
|
+
return { ...buildSearchTestSuitesTool(), inputSchema: SearchTestSuitesInputSchema, handler: searchTestSuitesHandler };
|
|
59
|
+
}
|
|
60
|
+
// ── delete_test_suite ─────────────────────────────────────────────────────────
|
|
61
|
+
export function buildDeleteTestSuiteTool() {
|
|
62
|
+
return {
|
|
63
|
+
name: 'delete_test_suite',
|
|
64
|
+
title: 'Delete Test Suite',
|
|
65
|
+
description: 'Disable (soft-delete) a test suite. The suite and its tests are hidden from default list queries but not permanently removed. Accepts suiteUuid directly, or suiteName + project identifier for name-based lookup. Returns {deleted: true, suiteUuid}.',
|
|
66
|
+
inputSchema: {
|
|
67
|
+
type: 'object',
|
|
68
|
+
properties: {
|
|
69
|
+
...SUITE_PROPS,
|
|
70
|
+
...PROJECT_PROPS,
|
|
71
|
+
},
|
|
72
|
+
additionalProperties: false,
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
export function buildValidatedDeleteTestSuiteTool() {
|
|
77
|
+
return { ...buildDeleteTestSuiteTool(), inputSchema: DeleteTestSuiteInputSchema, handler: deleteTestSuiteHandler };
|
|
78
|
+
}
|
|
79
|
+
// ── create_test_case ──────────────────────────────────────────────────────────
|
|
80
|
+
export function buildCreateTestCaseTool() {
|
|
81
|
+
return {
|
|
82
|
+
name: 'create_test_case',
|
|
83
|
+
title: 'Create Test Case',
|
|
84
|
+
description: 'Create an individual test case and assign it to a test suite. The test is NOT automatically executed. Requires name, description, agentTaskDescription (the AI agent\'s goal), and suite + project identifiers. Optional: relativeUrl (must start with "/") and maxSteps (1-100). Returns {uuid, name, description, agentTaskDescription, suite, project, runCount}.',
|
|
85
|
+
inputSchema: {
|
|
86
|
+
type: 'object',
|
|
87
|
+
properties: {
|
|
88
|
+
name: { type: 'string', description: 'Test case name. Required.', minLength: 1 },
|
|
89
|
+
description: { type: 'string', description: 'Test case description. Required.', minLength: 1 },
|
|
90
|
+
agentTaskDescription: { type: 'string', description: 'Natural language description of what the AI agent should do and verify. Required.', minLength: 1 },
|
|
91
|
+
...SUITE_PROPS,
|
|
92
|
+
...PROJECT_PROPS,
|
|
93
|
+
relativeUrl: { type: 'string', description: 'Optional starting URL path relative to the app root, e.g. "/login". Must start with "/".' },
|
|
94
|
+
maxSteps: { type: 'number', description: 'Maximum agent steps (1-100).', minimum: 1, maximum: 100 },
|
|
95
|
+
},
|
|
96
|
+
required: ['name', 'description', 'agentTaskDescription'],
|
|
97
|
+
additionalProperties: false,
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
export function buildValidatedCreateTestCaseTool() {
|
|
102
|
+
return { ...buildCreateTestCaseTool(), inputSchema: CreateTestCaseInputSchema, handler: createTestCaseHandler };
|
|
103
|
+
}
|
|
104
|
+
// ── update_test_case ──────────────────────────────────────────────────────────
|
|
105
|
+
export function buildUpdateTestCaseTool() {
|
|
106
|
+
return {
|
|
107
|
+
name: 'update_test_case',
|
|
108
|
+
title: 'Update Test Case',
|
|
109
|
+
description: 'Update a test case\'s name, description, or agentTaskDescription. Requires testUuid. At least one of name, description, or agentTaskDescription must be provided. Returns the updated test case.',
|
|
110
|
+
inputSchema: {
|
|
111
|
+
type: 'object',
|
|
112
|
+
properties: {
|
|
113
|
+
testUuid: { type: 'string', description: 'UUID of the test case to update. Required.' },
|
|
114
|
+
name: { type: 'string', description: 'New name for the test case.', minLength: 1 },
|
|
115
|
+
description: { type: 'string', description: 'New description.', minLength: 1 },
|
|
116
|
+
agentTaskDescription: { type: 'string', description: 'New agent task description.', minLength: 1 },
|
|
117
|
+
},
|
|
118
|
+
required: ['testUuid'],
|
|
119
|
+
additionalProperties: false,
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
export function buildValidatedUpdateTestCaseTool() {
|
|
124
|
+
return { ...buildUpdateTestCaseTool(), inputSchema: UpdateTestCaseInputSchema, handler: updateTestCaseHandler };
|
|
125
|
+
}
|
|
126
|
+
// ── delete_test_case ──────────────────────────────────────────────────────────
|
|
127
|
+
export function buildDeleteTestCaseTool() {
|
|
128
|
+
return {
|
|
129
|
+
name: 'delete_test_case',
|
|
130
|
+
title: 'Delete Test Case',
|
|
131
|
+
description: 'Disable (soft-delete) a test case. The test is hidden from default list queries but not permanently removed. Requires testUuid. Returns {deleted: true, testUuid}.',
|
|
132
|
+
inputSchema: {
|
|
133
|
+
type: 'object',
|
|
134
|
+
properties: {
|
|
135
|
+
testUuid: { type: 'string', description: 'UUID of the test case to delete. Required.' },
|
|
136
|
+
},
|
|
137
|
+
required: ['testUuid'],
|
|
138
|
+
additionalProperties: false,
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
export function buildValidatedDeleteTestCaseTool() {
|
|
143
|
+
return { ...buildDeleteTestCaseTool(), inputSchema: DeleteTestCaseInputSchema, handler: deleteTestCaseHandler };
|
|
144
|
+
}
|
|
145
|
+
// ── run_test_suite ────────────────────────────────────────────────────────────
|
|
146
|
+
export function buildRunTestSuiteTool() {
|
|
147
|
+
return {
|
|
148
|
+
name: 'run_test_suite',
|
|
149
|
+
title: 'Run Test Suite',
|
|
150
|
+
description: 'Trigger all test cases in a suite to run asynchronously. Accepts suiteUuid directly, or suiteName + project identifier. Optional: targetUrl to override the default test target. Returns {suiteUuid, runStatus, testsTriggered, note}. Use get_test_suite_results to poll for results.',
|
|
151
|
+
inputSchema: {
|
|
152
|
+
type: 'object',
|
|
153
|
+
properties: {
|
|
154
|
+
...SUITE_PROPS,
|
|
155
|
+
...PROJECT_PROPS,
|
|
156
|
+
targetUrl: { type: 'string', description: 'Optional URL to run tests against (overrides default). Must be a full URL.' },
|
|
157
|
+
},
|
|
158
|
+
additionalProperties: false,
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
export function buildValidatedRunTestSuiteTool() {
|
|
163
|
+
return { ...buildRunTestSuiteTool(), inputSchema: RunTestSuiteInputSchema, handler: runTestSuiteHandler };
|
|
164
|
+
}
|
|
165
|
+
// ── get_test_suite_results ────────────────────────────────────────────────────
|
|
166
|
+
export function buildGetTestSuiteResultsTool() {
|
|
167
|
+
return {
|
|
168
|
+
name: 'get_test_suite_results',
|
|
169
|
+
title: 'Get Test Suite Results',
|
|
170
|
+
description: 'Fetch a test suite with full per-test results. Returns suite-level status (NEVER_RUN, PENDING, RUNNING, COMPLETED, ERROR), pass rate, last run timestamp, and per-test outcomes (PASS, FAIL, ERROR, TIMEOUT, etc.) with execution times. Accepts suiteUuid directly or suiteName + project identifier.',
|
|
171
|
+
inputSchema: {
|
|
172
|
+
type: 'object',
|
|
173
|
+
properties: {
|
|
174
|
+
...SUITE_PROPS,
|
|
175
|
+
...PROJECT_PROPS,
|
|
176
|
+
},
|
|
177
|
+
additionalProperties: false,
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
export function buildValidatedGetTestSuiteResultsTool() {
|
|
182
|
+
return { ...buildGetTestSuiteResultsTool(), inputSchema: GetTestSuiteResultsInputSchema, handler: getTestSuiteResultsHandler };
|
|
183
|
+
}
|
package/dist/types/index.js
CHANGED
|
@@ -169,3 +169,54 @@ export const ProbePageInputSchema = z.object({
|
|
|
169
169
|
captureScreenshots: z.boolean().default(true),
|
|
170
170
|
repoName: z.string().optional(),
|
|
171
171
|
}).strict();
|
|
172
|
+
// ── E2E Suite Management ──────────────────────────────────────────────────────
|
|
173
|
+
const projectIdentifier = {
|
|
174
|
+
projectUuid: z.string().uuid().optional(),
|
|
175
|
+
projectName: z.string().min(1).optional(),
|
|
176
|
+
};
|
|
177
|
+
const suiteIdentifier = {
|
|
178
|
+
suiteUuid: z.string().uuid().optional(),
|
|
179
|
+
suiteName: z.string().min(1).optional(),
|
|
180
|
+
};
|
|
181
|
+
export const CreateTestSuiteInputSchema = z.object({
|
|
182
|
+
name: z.string().min(1),
|
|
183
|
+
description: z.string().min(1),
|
|
184
|
+
...projectIdentifier,
|
|
185
|
+
}).strict();
|
|
186
|
+
export const SearchTestSuitesInputSchema = z.object({
|
|
187
|
+
...projectIdentifier,
|
|
188
|
+
search: z.string().optional(),
|
|
189
|
+
page: z.number().int().min(1).optional(),
|
|
190
|
+
pageSize: z.number().int().min(1).max(100).optional(),
|
|
191
|
+
}).strict();
|
|
192
|
+
export const DeleteTestSuiteInputSchema = z.object({
|
|
193
|
+
...suiteIdentifier,
|
|
194
|
+
...projectIdentifier,
|
|
195
|
+
}).strict();
|
|
196
|
+
export const CreateTestCaseInputSchema = z.object({
|
|
197
|
+
name: z.string().min(1),
|
|
198
|
+
description: z.string().min(1),
|
|
199
|
+
agentTaskDescription: z.string().min(1),
|
|
200
|
+
...suiteIdentifier,
|
|
201
|
+
...projectIdentifier,
|
|
202
|
+
relativeUrl: z.string().regex(/^\//, 'Must start with /').optional(),
|
|
203
|
+
maxSteps: z.number().int().min(1).max(100).optional(),
|
|
204
|
+
}).strict();
|
|
205
|
+
export const UpdateTestCaseInputSchema = z.object({
|
|
206
|
+
testUuid: z.string().uuid(),
|
|
207
|
+
name: z.string().min(1).optional(),
|
|
208
|
+
description: z.string().min(1).optional(),
|
|
209
|
+
agentTaskDescription: z.string().min(1).optional(),
|
|
210
|
+
}).strict();
|
|
211
|
+
export const DeleteTestCaseInputSchema = z.object({
|
|
212
|
+
testUuid: z.string().uuid(),
|
|
213
|
+
}).strict();
|
|
214
|
+
export const RunTestSuiteInputSchema = z.object({
|
|
215
|
+
...suiteIdentifier,
|
|
216
|
+
...projectIdentifier,
|
|
217
|
+
targetUrl: z.string().url().optional(),
|
|
218
|
+
}).strict();
|
|
219
|
+
export const GetTestSuiteResultsInputSchema = z.object({
|
|
220
|
+
...suiteIdentifier,
|
|
221
|
+
...projectIdentifier,
|
|
222
|
+
}).strict();
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export async function resolveProject(client, name) {
|
|
2
|
+
const { projects } = await client.listProjects({ page: 1, pageSize: 100 }, name);
|
|
3
|
+
return resolveByName(name, projects, 'Project');
|
|
4
|
+
}
|
|
5
|
+
export async function resolveTestSuite(client, suiteName, projectUuid) {
|
|
6
|
+
const { suites } = await client.listTestSuites({ projectUuid, search: suiteName });
|
|
7
|
+
return resolveByName(suiteName, suites, 'TestSuite');
|
|
8
|
+
}
|
|
9
|
+
export function resolveByName(name, candidates, kind) {
|
|
10
|
+
const needle = name.toLowerCase();
|
|
11
|
+
const matches = candidates.filter(c => c.name.toLowerCase() === needle);
|
|
12
|
+
if (matches.length === 0) {
|
|
13
|
+
return {
|
|
14
|
+
error: `${kind}NotFound`,
|
|
15
|
+
message: `No ${kind.toLowerCase().replace('testsuite', 'test suite')} matching "${name}" found.` +
|
|
16
|
+
(candidates.length > 0 ? ` Available: ${candidates.slice(0, 10).map(c => `"${c.name}"`).join(', ')}` : ' (none accessible to this API key)'),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
if (matches.length > 1) {
|
|
20
|
+
return {
|
|
21
|
+
error: 'AmbiguousMatch',
|
|
22
|
+
message: `Multiple ${kind.toLowerCase().replace('testsuite', 'test suite')}s match "${name}". Pass the uuid directly.`,
|
|
23
|
+
candidates: matches.map(m => ({ uuid: m.uuid, name: m.name })),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return { uuid: matches[0].uuid };
|
|
27
|
+
}
|