move_suite
Relocate test suites within TestCollab by moving them to different parent suites or to the root level for better test organization.
Instructions
Move a test suite to a different parent suite, or to root level. Tip: Call get_project_context first to see the current suite tree.
Required: id (suite ID), parent (new parent ID, title, or null for root) Optional: project_id
Examples: Move under a parent: { "id": 10, "parent": "Authentication" } Move to root level: { "id": 10, "parent": null }
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Suite ID to move (required) | |
| project_id | No | Project ID (optional if TC_DEFAULT_PROJECT is set) | |
| parent | Yes | New parent suite ID, title, or null to move to root level (required) |
Implementation Reference
- src/tools/suites/move.ts:82-186 (handler)The handler function `handleMoveSuite` for the `move_suite` tool. It handles resolving the project, resolving the target parent suite (by ID or title), performing safety checks, calling the API, and clearing the cache.
export async function handleMoveSuite(args: { id: number; project_id?: number; parent: number | string | null; }): Promise<{ content: Array<{ type: "text"; text: string }> }> { try { const projectId = resolveProjectId(args.project_id); if (!projectId) { return { content: [ { type: "text" as const, text: JSON.stringify({ error: { code: "MISSING_PROJECT_ID", message: "No project_id provided and no default project configured. Set TC_DEFAULT_PROJECT or pass project_id.", }, }), }, ], }; } // Resolve parent let parentId: number | null = null; if (args.parent !== null) { if (typeof args.parent === "number") { parentId = args.parent; } else { const resolved = resolveSuiteByTitle(args.parent, projectId); if (resolved === null) { return { content: [ { type: "text" as const, text: JSON.stringify({ error: { code: "PARENT_SUITE_NOT_FOUND", message: `Could not find parent suite with title "${args.parent}". Call get_project_context to see available suites.`, }, }), }, ], }; } parentId = resolved; } } // Prevent moving a suite under itself if (parentId === args.id) { return { content: [ { type: "text" as const, text: JSON.stringify({ error: { code: "CIRCULAR_REFERENCE", message: "Cannot move a suite under itself.", }, }), }, ], }; } const client = getApiClient(); const result = await client.updateSuite(args.id, { projectId, parentId, }); // Invalidate project context cache clearProjectContextCache(); return { content: [ { type: "text" as const, text: JSON.stringify({ success: true, suite: result, moved_to_parent: parentId, }), }, ], }; } catch (error) { return { content: [ { type: "text" as const, text: JSON.stringify({ error: { code: "MOVE_SUITE_FAILED", message: error instanceof Error ? error.message : "Unknown error", }, }), }, ], }; } } - src/tools/suites/move.ts:19-30 (schema)Zod schema definition for `move_suite` arguments.
export const moveSuiteSchema = z.object({ id: z.number().describe("Suite ID to move (required)"), project_id: z .number() .optional() .describe("Project ID (optional if TC_DEFAULT_PROJECT is set)"), parent: z .union([z.number(), z.string(), z.null()]) .describe( "New parent suite ID, title, or null to move to root level (required)" ), }); - src/tools/suites/move.ts:36-47 (registration)Tool definition object for `move_suite`.
export const moveSuiteTool = { name: "move_suite", description: `Move a test suite to a different parent suite, or to root level. Tip: Call get_project_context first to see the current suite tree. Required: id (suite ID), parent (new parent ID, title, or null for root) Optional: project_id Examples: Move under a parent: { "id": 10, "parent": "Authentication" } Move to root level: { "id": 10, "parent": null }`, }; - src/tools/suites/move.ts:53-76 (helper)Helper function to resolve a suite ID by its title within the project context.
function resolveSuiteByTitle( title: string, projectId: number ): number | null { const context = getCachedProjectContext(projectId); if (!context) return null; const search = ( nodes: Array<{ id: number; title: string; children: unknown[] }> ): number | null => { for (const node of nodes) { if (node.title.toLowerCase() === title.toLowerCase()) { return node.id; } const childResult = search( node.children as Array<{ id: number; title: string; children: unknown[] }> ); if (childResult !== null) return childResult; } return null; }; return search(context.suites as Array<{ id: number; title: string; children: unknown[] }>); }