Skip to main content
Glama

validate_test_case

Validate test cases against quality standards and best practices with dynamic rules support and automated improvement suggestions.

Instructions

๐Ÿ” Validate a test case against quality standards and best practices (Dynamic Rules Support + Improvement)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
projectKeyYesProject key (e.g., 'android' or 'ANDROID')
caseKeyYesTest case key (e.g., 'ANDROID-29')
rulesFilePathNoPath to custom rules markdown file
checkpointsFilePathNoPath to custom checkpoints markdown file
formatNoOutput formatmarkdown
improveIfPossibleNoAttempt to automatically improve the test case
include_clickable_linksNoInclude clickable links to Zebrunner web UI

Implementation Reference

  • Main MCP tool handler: fetches Zebrunner test case by key, initializes TestCaseValidator (with optional custom rules files), runs validation, optionally generates improvements via TestCaseImprover, formats output (JSON/markdown/string), returns MCP content response.
    async validateTestCase(input: z.infer<typeof ValidateTestCaseInputSchema>) { const { projectKey, caseKey, rulesFilePath, checkpointsFilePath, format, improveIfPossible } = input; try { // Get the test case data first const testCase = await this.client.getTestCaseByKey(projectKey, caseKey); // Initialize validator with dynamic rules let validator: TestCaseValidator; if (rulesFilePath && checkpointsFilePath) { // Use custom rules from files - validate paths first try { const resolvedRulesPath = validateFilePath(rulesFilePath, process.cwd()); const resolvedCheckpointsPath = validateFilePath(checkpointsFilePath, process.cwd()); validator = await TestCaseValidator.fromMarkdownFiles(resolvedRulesPath, resolvedCheckpointsPath); } catch (error) { throw new Error(`Invalid file path provided: ${error instanceof Error ? error.message : error}`); } } else { // Use default rules, but try to load from standard files if they exist const defaultRulesPath = path.resolve(process.cwd(), 'test_case_review_rules.md'); const defaultCheckpointsPath = path.resolve(process.cwd(), 'test_case_analysis_checkpoints.md'); try { validator = await TestCaseValidator.fromMarkdownFiles(defaultRulesPath, defaultCheckpointsPath); } catch (error) { // Fall back to default rules if files don't exist validator = new TestCaseValidator(); } } // Validate the test case const validationResult = await validator.validateTestCase(testCase); // Attempt improvement if requested let improvementResult = null; if (improveIfPossible) { const improver = new TestCaseImprover(); improvementResult = await improver.improveTestCase(testCase, validationResult); } // Format the result based on requested format let formattedResult: string; if (format === 'markdown') { formattedResult = this.formatValidationResultAsMarkdown(validationResult, improvementResult); } else if (format === 'string') { formattedResult = this.formatValidationResultAsString(validationResult, improvementResult); } else { const result = improvementResult ? { validation: validationResult, improvement: improvementResult } : validationResult; formattedResult = JSON.stringify(result, null, 2); } return { content: [ { type: "text" as const, text: formattedResult } ] }; } catch (error: any) { const errorMsg = sanitizeErrorMessage(error, 'Error validating test case', 'validateTestCase'); return { content: [ { type: "text" as const, text: errorMsg } ] }; } }
  • Zod input schema for validate_test_case tool defining required projectKey/caseKey and optional custom rules paths, output format, improvement flag.
    export const ValidateTestCaseInputSchema = z.object({ projectKey: z.string().min(1), caseKey: z.string().min(1), rulesFilePath: z.string().optional(), checkpointsFilePath: z.string().optional(), format: z.enum(['dto', 'json', 'string', 'markdown']).default('json'), improveIfPossible: z.boolean().default(true) });
  • Core helper implementing test case validation logic: iterates over dynamic rule set, executes specific validators (title, steps, preconditions, etc.), calculates score, categorizes readiness for automation/manual, generates issues/summary.
    async validateTestCase(testCase: ZebrunnerTestCase): Promise<ValidationResult> { const issues: ValidationIssue[] = []; const passedCheckpoints: string[] = []; // Run validation based on enabled rules for (const rule of this.ruleSet.rules.filter(r => r.enabled)) { const validationFunction = this.validationFunctions.get(rule.checkFunction); if (validationFunction) { try { const result = validationFunction(testCase, rule); if (result.passed) { passedCheckpoints.push(rule.name); } else { issues.push({ category: rule.category, severity: rule.severity, checkpoint: rule.name, description: result.message || rule.description, suggestion: result.suggestion || rule.suggestion, ruleId: rule.id }); } } catch (error) { console.warn(`Error executing validation rule ${rule.id}: ${error}`); } } } // Calculate score const totalCheckpoints = issues.length + passedCheckpoints.length; const score = totalCheckpoints > 0 ? Math.round((passedCheckpoints.length / totalCheckpoints) * 100) : 0; const scoreCategory = this.getScoreCategory(score); const readyForAutomation = score >= this.ruleSet.scoreThresholds.good && !this.hasAutomationBlockers(issues); const readyForManualExecution = score >= this.ruleSet.scoreThresholds.needs_improvement; // Extract automation status, priority, and status const automationStatus = testCase.automationState?.name || 'Unknown'; const priority = testCase.priority?.name || undefined; // Construct status from available boolean fields let status: string | undefined; if (testCase.draft) { status = 'Draft'; } else if (testCase.deprecated) { status = 'Deprecated'; } else { // If neither draft nor deprecated, it's likely active status = 'Active'; } // Extract Manual Only from custom fields const manualOnly = testCase.customField?.manualOnly || undefined; return { testCaseKey: testCase.key || 'Unknown', testCaseTitle: testCase.title || 'Untitled', automationStatus, priority, status, manualOnly, overallScore: score, scoreCategory, issues, passedCheckpoints, summary: this.generateSummary(score, issues, readyForAutomation, readyForManualExecution, automationStatus), readyForAutomation, readyForManualExecution, rulesUsed: `${this.ruleSet.name} v${this.ruleSet.version}` }; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/maksimsarychau/mcp-zebrunner'

If you have feedback or need assistance with the MCP directory API, please join our Discord server