Skip to main content
Glama
enterprise-workflows.js21.9 kB
/** * Advanced TestRail MCP Server Examples * * This file demonstrates advanced usage patterns and complex workflows * for enterprise-level TestRail integration scenarios. */ // ============================================================================ // 1. CI/CD PIPELINE INTEGRATION // ============================================================================ /** * GitHub Actions Integration Example * This example shows how to integrate TestRail with GitHub Actions */ const githubActionsIntegration = { // Step 1: Create test run from CI trigger createCIRun: { tool: "create_run", parameters: { projectId: 1, name: `CI Build ${process.env.GITHUB_RUN_NUMBER} - ${process.env.GITHUB_REF_NAME}`, description: `Automated test run from GitHub Actions Branch: ${process.env.GITHUB_REF_NAME} Commit: ${process.env.GITHUB_SHA} Triggered by: ${process.env.GITHUB_ACTOR} Workflow: ${process.env.GITHUB_WORKFLOW}`, includeAll: false, caseIds: [101, 102, 103, 104, 105], // Smoke test cases configIds: [1] // CI environment config } }, // Step 2: Process test results from multiple test frameworks processTestResults: { tool: "add_bulk_results", parameters: { runId: "{{CI_RUN_ID}}", // From step 1 results: [ // Jest unit test results { caseId: 101, statusId: 1, comment: `Unit Tests - All 45 tests passed Coverage: 92.3% Duration: 12.5s Framework: Jest v29.7.0`, version: process.env.GITHUB_SHA?.substring(0, 7), elapsed: "12.5s" }, // Cypress e2e test results { caseId: 102, statusId: 1, comment: `E2E Tests - Login Flow Browser: Chrome 120 Viewport: 1280x720 Screenshots: Available in artifacts`, version: process.env.GITHUB_SHA?.substring(0, 7), elapsed: "2m 15s" }, // API integration test results { caseId: 103, statusId: 5, comment: `API Integration Tests - FAILED Error: Authentication endpoint returning 500 Response time: 5.2s (exceeds 2s threshold) Environment: staging`, version: process.env.GITHUB_SHA?.substring(0, 7), elapsed: "45s", defects: `GH-${process.env.GITHUB_RUN_NUMBER}-API-FAIL` }, // Performance test results { caseId: 104, statusId: 1, comment: `Performance Tests - PASSED Load: 100 concurrent users Response time p95: 1.2s Error rate: 0.02% Tool: Artillery`, version: process.env.GITHUB_SHA?.substring(0, 7), elapsed: "5m 30s" }, // Security scan results { caseId: 105, statusId: 2, comment: `Security Scan - BLOCKED OWASP ZAP scan could not complete Reason: Target environment unreachable Will retry on next build`, version: process.env.GITHUB_SHA?.substring(0, 7) } ] } } }; /** * Jenkins Pipeline Integration Example */ const jenkinsPipelineIntegration = { // Groovy script for Jenkins Pipeline jenkinsScript: ` pipeline { agent any environment { TESTRAIL_PROJECT_ID = '1' TESTRAIL_SUITE_ID = '2' } stages { stage('Create Test Run') { steps { script { def runData = [ projectId: env.TESTRAIL_PROJECT_ID as Integer, name: "Jenkins Build #\${env.BUILD_NUMBER} - \${env.BRANCH_NAME}", description: "Automated Jenkins pipeline execution", suiteId: env.TESTRAIL_SUITE_ID as Integer, includeAll: true ] // Call TestRail MCP Server def createRunResult = sh( script: "node testrail-mcp-client.js create_run '\${groovy.json.JsonOutput.toJson(runData)}'", returnStdout: true ).trim() def runResponse = readJSON text: createRunResult env.TESTRAIL_RUN_ID = runResponse.data.run.id echo "Created TestRail run: \${env.TESTRAIL_RUN_ID}" } } } stage('Execute Tests') { parallel { stage('Unit Tests') { steps { sh 'npm test' publishTestResults testResultsPattern: 'test-results.xml' } } stage('Integration Tests') { steps { sh 'npm run test:integration' publishTestResults testResultsPattern: 'integration-results.xml' } } } } stage('Update TestRail') { steps { script { // Parse test results and update TestRail def testResults = readJSON file: 'test-results.json' def results = testResults.collect { result -> [ caseId: result.testRailCaseId, statusId: result.passed ? 1 : 5, comment: result.message, version: env.BUILD_NUMBER, elapsed: result.duration ] } def bulkResults = [ runId: env.TESTRAIL_RUN_ID as Integer, results: results ] sh "node testrail-mcp-client.js add_bulk_results '\${groovy.json.JsonOutput.toJson(bulkResults)}'" } } } } post { always { script { if (env.TESTRAIL_RUN_ID) { // Close the test run sh "node testrail-mcp-client.js close_run '{\\"runId\\": \${env.TESTRAIL_RUN_ID}}'" } } } } } ` }; // ============================================================================ // 2. TEST AUTOMATION FRAMEWORK INTEGRATION // ============================================================================ /** * Playwright Test Results Integration */ const playwrightIntegration = { // Custom Playwright reporter for TestRail reporter: ` // playwright-testrail-reporter.js class TestRailReporter { constructor(options) { this.testRailRunId = options.runId; this.results = []; } onTestEnd(test, result) { const testRailCaseId = this.extractCaseId(test.title); if (testRailCaseId) { this.results.push({ caseId: testRailCaseId, statusId: this.mapStatus(result.status), comment: this.formatComment(test, result), elapsed: this.formatDuration(result.duration), version: process.env.npm_package_version }); } } async onEnd() { if (this.results.length > 0) { // Call TestRail MCP Server const mcpResponse = await fetch('http://localhost:3000/tools/add_bulk_results', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ runId: this.testRailRunId, results: this.results }) }); const response = await mcpResponse.json(); console.log('TestRail results updated:', response.data.processed); } } extractCaseId(title) { const match = title.match(/\\[C(\\d+)\\]/); return match ? parseInt(match[1]) : null; } mapStatus(status) { switch (status) { case 'passed': return 1; case 'failed': return 5; case 'skipped': return 2; case 'timedOut': return 5; default: return 3; } } formatComment(test, result) { let comment = \`Test: \${test.title}\\n\`; comment += \`Status: \${result.status.toUpperCase()}\\n\`; if (result.error) { comment += \`Error: \${result.error.message}\\n\`; comment += \`Stack: \${result.error.stack}\`; } if (result.attachments && result.attachments.length > 0) { comment += \`\\nAttachments: \${result.attachments.length} files\`; } return comment; } formatDuration(ms) { if (ms < 1000) return \`\${ms}ms\`; if (ms < 60000) return \`\${(ms / 1000).toFixed(1)}s\`; return \`\${Math.floor(ms / 60000)}m \${((ms % 60000) / 1000).toFixed(0)}s\`; } } module.exports = TestRailReporter; `, // Playwright test with TestRail case IDs testExample: ` // login.spec.js import { test, expect } from '@playwright/test'; test('[C123] User can login with valid credentials', async ({ page }) => { await page.goto('/login'); await page.fill('[data-testid=username]', 'testuser@example.com'); await page.fill('[data-testid=password]', 'password123'); await page.click('[data-testid=login-button]'); await expect(page).toHaveURL('/dashboard'); await expect(page.locator('[data-testid=welcome-message]')).toContainText('Welcome'); }); test('[C124] User cannot login with invalid credentials', async ({ page }) => { await page.goto('/login'); await page.fill('[data-testid=username]', 'invalid@example.com'); await page.fill('[data-testid=password]', 'wrongpassword'); await page.click('[data-testid=login-button]'); await expect(page.locator('[data-testid=error-message]')).toContainText('Invalid credentials'); }); ` }; /** * Selenium WebDriver Integration (Java) */ const seleniumIntegration = { // Java TestNG listener for TestRail testNGListener: ` // TestRailListener.java public class TestRailListener implements ITestListener { private TestRailClient testRailClient; private int runId; private List<TestResult> results = new ArrayList<>(); @Override public void onStart(ITestContext context) { testRailClient = new TestRailClient(); runId = Integer.parseInt(System.getProperty("testrail.run.id")); } @Override public void onTestSuccess(ITestResult result) { updateTestRailResult(result, 1); // Passed } @Override public void onTestFailure(ITestResult result) { updateTestRailResult(result, 5); // Failed } @Override public void onTestSkipped(ITestResult result) { updateTestRailResult(result, 2); // Blocked } private void updateTestRailResult(ITestResult result, int statusId) { TestRailCase annotation = result.getMethod() .getConstructorOrMethod() .getMethod() .getAnnotation(TestRailCase.class); if (annotation != null) { TestResult testResult = new TestResult(); testResult.setCaseId(annotation.id()); testResult.setStatusId(statusId); testResult.setComment(formatComment(result)); testResult.setElapsed(formatDuration(result)); results.add(testResult); } } @Override public void onFinish(ITestContext context) { if (!results.isEmpty()) { testRailClient.addBulkResults(runId, results); } } } `, // Java test with TestRail annotation javaTestExample: ` // LoginTest.java public class LoginTest { private WebDriver driver; @Test @TestRailCase(id = 123) @Description("Verify user can login with valid credentials") public void testValidLogin() { driver.get("https://example.com/login"); WebElement username = driver.findElement(By.id("username")); WebElement password = driver.findElement(By.id("password")); WebElement loginButton = driver.findElement(By.id("login")); username.sendKeys("testuser@example.com"); password.sendKeys("password123"); loginButton.click(); WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10)); wait.until(ExpectedConditions.urlContains("/dashboard")); Assert.assertTrue(driver.getCurrentUrl().contains("/dashboard")); } @Test @TestRailCase(id = 124) @Description("Verify user cannot login with invalid credentials") public void testInvalidLogin() { driver.get("https://example.com/login"); driver.findElement(By.id("username")).sendKeys("invalid@example.com"); driver.findElement(By.id("password")).sendKeys("wrongpassword"); driver.findElement(By.id("login")).click(); WebElement errorMessage = driver.findElement(By.className("error-message")); Assert.assertTrue(errorMessage.getText().contains("Invalid credentials")); } } ` }; // ============================================================================ // 3. ADVANCED REPORTING AND ANALYTICS // ============================================================================ /** * Custom Dashboard Generation */ const advancedReporting = { // Generate executive dashboard executiveDashboard: { tool: "generate_report", parameters: { projectId: 1, format: "detailed", dateRange: { start: "2024-01-01", end: "2024-12-31" } } }, // Custom analytics queries customAnalytics: [ { description: "Get test execution trends over time", workflow: [ { tool: "get_runs", parameters: { projectId: 1, isCompleted: true, limit: 100 } }, { tool: "generate_report", parameters: { projectId: 1, format: "csv" } } ] }, { description: "Identify flaky tests", workflow: [ { tool: "get_cases", parameters: { projectId: 1, filter: { priority_id: [3, 4] // High and Critical priority } } } // Additional analysis would be done in post-processing ] } ], // Test coverage analysis coverageAnalysis: { tool: "search", parameters: { projectId: 1, query: "automated", entityType: "cases" } } }; // ============================================================================ // 4. BULK OPERATIONS AND DATA MIGRATION // ============================================================================ /** * Large Scale Data Operations */ const bulkOperations = { // Migrate test cases from another system migrateTestCases: { description: "Bulk import test cases from CSV/JSON", batchSize: 100, workflow: ` // Process test cases in batches const testCases = loadTestCasesFromFile('test-cases.json'); const batchSize = 100; for (let i = 0; i < testCases.length; i += batchSize) { const batch = testCases.slice(i, i + batchSize); for (const testCase of batch) { await mcpClient.callTool('create_case', { sectionId: testCase.sectionId, title: testCase.title, typeId: testCase.typeId, priorityId: testCase.priorityId, preconditions: testCase.preconditions, steps: testCase.steps, expectedResult: testCase.expectedResult }); } // Rate limiting: wait between batches await new Promise(resolve => setTimeout(resolve, 1000)); } ` }, // Bulk update test case priorities bulkUpdatePriorities: { description: "Update priorities based on business rules", workflow: ` // Get all test cases const cases = await mcpClient.callTool('get_cases', { projectId: 1, limit: 1000 }); // Apply business rules for (const testCase of cases.data.cases) { let newPriorityId = testCase.priority_id; // Business rule: Security tests are high priority if (testCase.title.toLowerCase().includes('security')) { newPriorityId = 3; // High priority } // Business rule: API tests are medium priority if (testCase.title.toLowerCase().includes('api')) { newPriorityId = 2; // Medium priority } // Update if priority changed if (newPriorityId !== testCase.priority_id) { await mcpClient.callTool('update_case', { caseId: testCase.id, priorityId: newPriorityId }); } } ` } }; // ============================================================================ // 5. COMPLEX WORKFLOW ORCHESTRATION // ============================================================================ /** * Multi-Environment Test Orchestration */ const multiEnvironmentWorkflow = { description: "Orchestrate tests across multiple environments", environments: ['dev', 'staging', 'production'], workflow: { // Step 1: Create runs for each environment createEnvironmentRuns: { dev: { tool: "create_run", parameters: { projectId: 1, name: "Smoke Test - Development", configIds: [1], // Dev config caseIds: [1, 2, 3] // Smoke test cases } }, staging: { tool: "create_run", parameters: { projectId: 1, name: "Regression Test - Staging", configIds: [2], // Staging config includeAll: true } }, production: { tool: "create_run", parameters: { projectId: 1, name: "Health Check - Production", configIds: [3], // Prod config caseIds: [1, 5, 10] // Critical path only } } }, // Step 2: Execute tests in sequence with dependencies executionFlow: ` // Development tests (must pass before staging) const devResults = await executeTests('dev'); if (devResults.passRate >= 0.95) { // Staging tests (must pass before production) const stagingResults = await executeTests('staging'); if (stagingResults.passRate >= 0.90) { // Production health checks const prodResults = await executeTests('production'); // Generate consolidated report await generateConsolidatedReport([devResults, stagingResults, prodResults]); } else { // Block production deployment await notifyStakeholders('Staging tests failed - Production deployment blocked'); } } else { // Block all downstream environments await notifyStakeholders('Development tests failed - All deployments blocked'); } ` } }; /** * Test Plan Management Workflow */ const testPlanManagement = { // Create comprehensive test plan createMasterPlan: { tool: "create_plan", parameters: { projectId: 1, name: "Release 3.0 Master Test Plan", description: "Comprehensive testing plan for major release 3.0", milestoneId: 10, entries: [ { name: "Unit Tests", suiteId: 1, assignedToId: 5, includeAll: false, caseIds: [1, 2, 3, 4, 5] }, { name: "Integration Tests", suiteId: 2, assignedToId: 6, includeAll: true }, { name: "E2E Tests", suiteId: 3, assignedToId: 7, configIds: [1, 2, 3] // All environments }, { name: "Performance Tests", suiteId: 4, assignedToId: 8, includeAll: false, caseIds: [100, 101, 102] // Critical performance scenarios } ] } }, // Monitor plan progress monitorProgress: ` // Get plan details const plan = await mcpClient.callTool('get_plan', { planId: 123 }); // Calculate overall progress let totalTests = 0; let completedTests = 0; let passedTests = 0; for (const entry of plan.data.plan.entries) { for (const run of entry.runs) { totalTests += run.passed_count + run.failed_count + run.blocked_count + run.untested_count; completedTests += run.passed_count + run.failed_count + run.blocked_count; passedTests += run.passed_count; } } const progressReport = { totalTests, completedTests, passedTests, progressPercentage: (completedTests / totalTests) * 100, passPercentage: (passedTests / completedTests) * 100, status: plan.data.plan.is_completed ? 'Completed' : 'In Progress' }; console.log('Test Plan Progress:', progressReport); ` }; // Export all advanced examples module.exports = { cicd: { githubActionsIntegration, jenkinsPipelineIntegration }, automation: { playwrightIntegration, seleniumIntegration }, reporting: { advancedReporting }, bulkOperations, workflows: { multiEnvironmentWorkflow, testPlanManagement } };

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/samuelvinay91/testrail-mcp'

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