Skip to main content
Glama

JIRA MCP Server

jira-mock-factory.tsโ€ข13.1 kB
/** * JIRA Mock Data Factory * * Centralized factory for creating mock JIRA data for testing * Provides consistent test data across all test suites */ import type { Board } from "@features/jira/boards/models/board.models"; import type { IssueSearchResult } from "@features/jira/issues/models/issue-search.models"; import type { Issue } from "@features/jira/issues/models/issue.models"; import type { ADFNode } from "@features/jira/shared/parsers/adf.parser"; import { type Sprint, SprintState, } from "@features/jira/sprints/models/sprint.models"; import type { User } from "@features/jira/users/models/user.models"; export interface ADFDocument extends ADFNode { version: number; type: "doc"; } export interface MockProject { id: string; key: string; name: string; projectTypeKey: string; simplified: boolean; style: string; isPrivate: boolean; description?: string; lead?: User; projectCategory?: { id: string; name: string; description: string; }; components?: Array<{ id: string; name: string; }>; versions?: Array<{ id: string; name: string; released: boolean; archived: boolean; }>; issueTypes?: Array<{ id: string; name: string; subtask: boolean; }>; } export interface MockScenario { name: string; description: string; data: { issues?: Issue[]; projects?: MockProject[]; users?: User[]; searchResults?: IssueSearchResult; }; } export class JiraMockFactory { private static instance: JiraMockFactory; static getInstance(): JiraMockFactory { if (!JiraMockFactory.instance) { JiraMockFactory.instance = new JiraMockFactory(); } return JiraMockFactory.instance; } // ADF Content Generation Utilities createADFParagraph(text: string): ADFNode { return { type: "paragraph", content: [ { type: "text", text, }, ], }; } createADFCodeBlock(language: string, code: string): ADFNode { return { type: "codeBlock", attrs: { language, }, content: [ { type: "text", text: code, }, ], }; } createADFList(items: string[], ordered = false): ADFNode { return { type: ordered ? "orderedList" : "bulletList", content: items.map((item) => ({ type: "listItem", content: [ { type: "paragraph", content: [ { type: "text", text: item, }, ], }, ], })), }; } createComplexADFDescription(): ADFDocument { return { version: 1, type: "doc", content: [ this.createADFParagraph( "This is a comprehensive bug report with multiple formatting elements.", ), this.createADFCodeBlock( "javascript", ` function buggyFunction() { // This function has a memory leak let data = []; setInterval(() => { data.push(new Array(1000).fill('memory')); }, 100); } `.trim(), ), this.createADFParagraph("Steps to reproduce:"), this.createADFList( [ "Navigate to the dashboard", 'Click on the "Generate Report" button', "Wait for 30 seconds", "Observe memory usage spike", ], true, ), this.createADFParagraph("Expected: Memory usage should remain stable"), this.createADFParagraph("Actual: Memory usage increases continuously"), ], }; } // Mock Data Generators createMockUser(overrides: Partial<User> = {}): User { const defaults: User = { accountId: `user-${Math.random().toString(36).substr(2, 9)}`, displayName: "John Developer", emailAddress: "john.developer@company.com", avatarUrls: { "16x16": "https://avatar.atlassian.com/16x16.png", "24x24": "https://avatar.atlassian.com/24x24.png", "32x32": "https://avatar.atlassian.com/32x32.png", "48x48": "https://avatar.atlassian.com/48x48.png", }, }; return { ...defaults, ...overrides }; } createMockProject(overrides: Partial<MockProject> = {}): MockProject { return { id: "10001", key: "TEST", name: "Test Project", projectTypeKey: "software", simplified: false, style: "classic", isPrivate: false, description: "A test project for development", lead: this.createMockUser({ accountId: "lead-123", displayName: "Project Lead", emailAddress: "lead@company.com", }), projectCategory: { id: "10001", name: "Development", description: "Software development projects", }, components: [ { id: "10001", name: "Frontend" }, { id: "10002", name: "Backend" }, ], versions: [ { id: "10001", name: "v1.0.0", released: true, archived: false }, { id: "10002", name: "v1.1.0", released: false, archived: false }, ], issueTypes: [ { id: "10001", name: "Task", subtask: false }, { id: "10002", name: "Bug", subtask: false }, { id: "10003", name: "Sub-task", subtask: true }, ], ...overrides, }; } createMockBoard(overrides: Partial<Board> = {}): Board { const boardId = Math.floor(Math.random() * 1000) + 1; const defaults: Board = { id: boardId.toString(), self: `https://company.atlassian.net/rest/agile/1.0/board/${boardId}`, name: "Test Board", type: "scrum", location: { projectId: "10001", projectKey: "TEST", projectName: "Test Project", projectTypeKey: "software", displayName: "Test Project (TEST)", }, canEdit: true, isPrivate: false, favourite: false, }; return { ...defaults, ...overrides }; } createMockSprint(overrides: Partial<Sprint> = {}): Sprint { const sprintId = Math.floor(Math.random() * 1000) + 1; const now = new Date(); const startDate = new Date(now.getTime() - 14 * 24 * 60 * 60 * 1000); // 2 weeks ago const endDate = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000); // 1 week from now const defaults: Sprint = { id: sprintId, self: `https://company.atlassian.net/rest/agile/1.0/sprint/${sprintId}`, state: SprintState.ACTIVE, name: `Sprint ${sprintId}`, startDate: startDate.toISOString(), endDate: endDate.toISOString(), createdDate: new Date( startDate.getTime() - 24 * 60 * 60 * 1000, ).toISOString(), // 1 day before start originBoardId: 1, goal: "Complete user story implementation and bug fixes", }; return { ...defaults, ...overrides }; } createMockIssue(overrides: Partial<Issue> = {}): Issue { const issueId = `issue-${Math.random().toString(36).substr(2, 9)}`; const defaults: Issue = { id: issueId, key: `TEST-${Math.floor(Math.random() * 1000)}`, self: `https://company.atlassian.net/rest/api/3/issue/${issueId}`, fields: { summary: "Sample issue for testing", description: this.createComplexADFDescription(), status: { name: "To Do", statusCategory: { name: "To Do", colorName: "blue-gray", }, }, priority: { name: "Medium", }, assignee: this.createMockUser({ displayName: "Jane Assignee", emailAddress: "jane.assignee@company.com", }), reporter: this.createMockUser({ displayName: "Bob Reporter", emailAddress: "bob.reporter@company.com", }), created: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(), // 1 day ago updated: new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString(), // 2 hours ago labels: ["testing", "mock-data"], }, }; return { ...defaults, ...overrides }; } createMockSearchResult( overrides: Partial<IssueSearchResult> = {}, ): IssueSearchResult { const issues = Array.from({ length: 5 }, () => this.createMockIssue()); const defaults: IssueSearchResult = { startAt: 0, maxResults: 50, total: issues.length, issues, }; return { ...defaults, ...overrides }; } // Pre-configured Scenarios getScenario(name: string): MockScenario | undefined { const scenarios = this.getAllScenarios(); return scenarios.find((scenario) => scenario.name === name); } getAllScenarios(): MockScenario[] { return [ { name: "empty-project", description: "Empty project with no issues", data: { projects: [ this.createMockProject({ name: "Empty Project", key: "EMPTY" }), ], issues: [], searchResults: this.createMockSearchResult({ issues: [], total: 0 }), }, }, { name: "single-bug", description: "Single critical bug issue", data: { issues: [ this.createMockIssue({ fields: { ...this.createMockIssue().fields, summary: "Critical memory leak in dashboard", priority: { name: "Critical" }, status: { name: "In Progress", statusCategory: { name: "In Progress", colorName: "yellow" }, }, }, }), ], }, }, { name: "mixed-issues", description: "Mix of different issue types and statuses", data: { issues: [ this.createMockIssue({ fields: { ...this.createMockIssue().fields, summary: "Add dark mode support", priority: { name: "Medium" }, }, }), this.createMockIssue({ fields: { ...this.createMockIssue().fields, summary: "Fix login validation bug", priority: { name: "High" }, status: { name: "Done", statusCategory: { name: "Done", colorName: "green" }, }, }, }), this.createMockIssue({ fields: { ...this.createMockIssue().fields, summary: "Research new authentication methods", priority: { name: "Low" }, }, }), ], }, }, { name: "large-result-set", description: "Large search result set for pagination testing", data: { searchResults: this.createMockSearchResult({ startAt: 0, maxResults: 25, total: 150, issues: Array.from({ length: 25 }, (_, i) => this.createMockIssue({ key: `LARGE-${i + 1}`, fields: { ...this.createMockIssue().fields, summary: `Issue ${i + 1} - Testing pagination`, }, }), ), }), }, }, { name: "complex-adf-content", description: "Issues with complex ADF descriptions for parser testing", data: { issues: [ this.createMockIssue({ fields: { ...this.createMockIssue().fields, summary: "Complex formatting issue", description: { version: 1, type: "doc", content: [ this.createADFParagraph( "This issue demonstrates complex ADF formatting.", ), this.createADFCodeBlock( "typescript", ` interface ComplexType { id: string; data: { nested: { values: Array<string | number>; }; }; } `.trim(), ), this.createADFList([ "First nested item", "Second nested item with more detail", "Third item with special characters: !@#$%^&*()", ]), this.createADFParagraph( "Final paragraph with **bold** and *italic* text.", ), ], } as ADFDocument, }, }), ], }, }, ]; } // Quick access methods for common test patterns createEmptyResponse() { return this.getScenario("empty-project"); } createSingleIssueResponse() { return this.getScenario("single-bug"); } createMultipleIssuesResponse() { return this.getScenario("mixed-issues"); } createLargeDatasetResponse() { return this.getScenario("large-result-set"); } createComplexADFResponse() { return this.getScenario("complex-adf-content"); } } export const mockFactory = JiraMockFactory.getInstance();

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

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