Skip to main content
Glama
zephyr-client.ts8.49 kB
import axios, { AxiosInstance } from 'axios'; import { getZephyrHeaders } from '../utils/config.js'; import { ZephyrTestPlan, ZephyrTestCycle, ZephyrTestExecution, ZephyrTestCase, ZephyrTestReport, ZephyrExecutionSummary, } from '../types/zephyr-types.js'; export class ZephyrClient { private client: AxiosInstance; constructor() { this.client = axios.create({ baseURL: 'https://api.zephyrscale.smartbear.com/v2', headers: getZephyrHeaders(), timeout: 30000, }); } async createTestPlan(data: { name: string; description?: string; projectKey: string; startDate?: string; endDate?: string; }): Promise<ZephyrTestPlan> { const payload = { name: data.name, objective: data.description, projectKey: data.projectKey, plannedStartDate: data.startDate, plannedEndDate: data.endDate, }; const response = await this.client.post('/testplans', payload); return response.data; } async getTestPlans(projectKey: string, limit = 50, offset = 0): Promise<{ testPlans: ZephyrTestPlan[]; total: number; }> { const params = { projectKey, maxResults: limit, startAt: offset, }; const response = await this.client.get('/testplans', { params }); return { testPlans: response.data.values || response.data, total: response.data.total || response.data.length, }; } async createTestCycle(data: { name: string; description?: string; projectKey: string; versionId: string; environment?: string; startDate?: string; endDate?: string; }): Promise<ZephyrTestCycle> { const payload = { name: data.name, description: data.description, projectKey: data.projectKey, versionId: data.versionId, environment: data.environment, plannedStartDate: data.startDate, plannedEndDate: data.endDate, }; const response = await this.client.post('/testcycles', payload); return response.data; } async getTestCycles(projectKey: string, versionId?: string, limit = 50): Promise<{ testCycles: ZephyrTestCycle[]; total: number; }> { const params = { projectKey, versionId, maxResults: limit, }; const response = await this.client.get('/testcycles', { params }); return { testCycles: response.data.values || response.data, total: response.data.total || response.data.length, }; } async getTestExecution(executionId: string): Promise<ZephyrTestExecution> { const response = await this.client.get(`/testexecutions/${executionId}`); return response.data; } async updateTestExecution(data: { executionId: string; status: 'PASS' | 'FAIL' | 'WIP' | 'BLOCKED'; comment?: string; defects?: string[]; }): Promise<ZephyrTestExecution> { const payload = { status: data.status, comment: data.comment, issues: data.defects?.map(key => ({ key })), }; const response = await this.client.put(`/testexecutions/${data.executionId}`, payload); return response.data; } async getTestExecutionSummary(cycleId: string): Promise<ZephyrExecutionSummary> { const response = await this.client.get(`/testcycles/${cycleId}/testexecutions`); const executions = response.data.values; const summary = executions.reduce( (acc: any, execution: any) => { acc.total++; switch (execution.status) { case 'PASS': acc.passed++; break; case 'FAIL': acc.failed++; break; case 'BLOCKED': acc.blocked++; break; case 'WIP': acc.inProgress++; break; default: acc.notExecuted++; } return acc; }, { total: 0, passed: 0, failed: 0, blocked: 0, inProgress: 0, notExecuted: 0 } ); summary.passRate = summary.total > 0 ? (summary.passed / summary.total) * 100 : 0; return summary; } async linkTestCaseToIssue(testCaseId: string, issueKey: string): Promise<void> { const payload = { issueKeys: [issueKey], }; await this.client.post(`/testcases/${testCaseId}/links`, payload); } async generateTestReport(cycleId: string): Promise<ZephyrTestReport> { const cycleResponse = await this.client.get(`/testcycles/${cycleId}`); const cycle = cycleResponse.data; const executionsResponse = await this.client.get(`/testcycles/${cycleId}/testexecutions`); const executions = executionsResponse.data.values || executionsResponse.data; const summary = await this.getTestExecutionSummary(cycleId); return { cycleId, cycleName: cycle.name, projectKey: cycle.projectKey, summary, executions, generatedOn: new Date().toISOString(), }; } async getTestCase(testCaseId: string): Promise<ZephyrTestCase> { const response = await this.client.get(`/testcases/${testCaseId}`); return response.data; } async searchTestCases(projectKey: string, query?: string, limit = 50): Promise<{ testCases: ZephyrTestCase[]; total: number; }> { const params = { projectKey, query, maxResults: limit, }; const response = await this.client.get('/testcases/search', { params }); return { testCases: response.data.values || response.data, total: response.data.total || response.data.length, }; } async createTestCase(data: { projectKey: string; name: string; objective?: string; precondition?: string; estimatedTime?: number; priority?: string; status?: string; folderId?: string; labels?: string[]; componentId?: string; customFields?: Record<string, any>; testScript?: { type: 'STEP_BY_STEP' | 'PLAIN_TEXT'; steps?: Array<{ index: number; description: string; testData?: string; expectedResult: string; }>; text?: string; }; }): Promise<ZephyrTestCase> { const payload: any = { projectKey: data.projectKey, name: data.name, objective: data.objective, precondition: data.precondition, estimatedTime: data.estimatedTime, }; if (data.priority) { payload.priority = data.priority; } if (data.status) { payload.status = data.status; } if (data.folderId) { payload.folderId = data.folderId; } if (data.labels && data.labels.length > 0) { payload.labels = data.labels; } if (data.componentId) { payload.componentId = data.componentId; } if (data.customFields) { payload.customFields = data.customFields; } if (data.testScript) { payload.testScript = data.testScript; } const response = await this.client.post('/testcases', payload); return response.data; } async createMultipleTestCases(testCases: Array<{ projectKey: string; name: string; objective?: string; precondition?: string; estimatedTime?: number; priority?: string; status?: string; folderId?: string; labels?: string[]; componentId?: string; customFields?: Record<string, any>; testScript?: { type: 'STEP_BY_STEP' | 'PLAIN_TEXT'; steps?: Array<{ index: number; description: string; testData?: string; expectedResult: string; }>; text?: string; }; }>, continueOnError = true): Promise<{ results: Array<{ index: number; success: boolean; data?: ZephyrTestCase; error?: string; }>; summary: { total: number; successful: number; failed: number; }; }> { const results = []; let successful = 0; let failed = 0; for (let i = 0; i < testCases.length; i++) { try { const testCase = await this.createTestCase(testCases[i]); results.push({ index: i, success: true, data: testCase, }); successful++; } catch (error: any) { const errorMessage = error.response?.data?.message || error.message; results.push({ index: i, success: false, error: errorMessage, }); failed++; if (!continueOnError) { break; } } } return { results, summary: { total: testCases.length, successful, failed, }, }; } }

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/leorosignoli/jira-zephyr-mcp'

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