Skip to main content
Glama

JIRA MCP Server

issue-test-data-factory.ts13.2 kB
/** * Issue Test Data Factory * * Implements the Hybrid Builder-Template System from creative phase design: * - Templates for common cases (80% use cases) - O(1) access time * - Builders for complex scenarios (20% use cases) - O(k) build time * - Full TypeScript inference and compile-time checking * - Performance target: <0.5ms per mock generation */ import type { Comment } from "@features/jira/issues/models/comment.models"; import type { Issue } from "@features/jira/issues/models/issue.models"; import type { ADFDocument } from "@features/jira/shared/parsers/adf.parser"; import type { User } from "@features/jira/users/models/user.models"; /** * Template-based mock data for common scenarios (80% use cases) * O(1) access time for fast test execution */ export const IssueTestTemplates = { /** * Valid issue template - most common test scenario */ VALID_ISSUE: { id: "10001", key: "TEST-123", self: "https://test.atlassian.net/rest/api/3/issue/10001", fields: { summary: "Test Issue Summary", description: "Test issue description for validation testing", issuetype: { name: "Task", iconUrl: "https://test.atlassian.net/secure/viewavatar?size=medium&avatarId=10318&avatarType=issuetype", }, status: { name: "To Do", statusCategory: { name: "To Do", colorName: "blue-gray", }, }, priority: { name: "Medium", iconUrl: "https://test.atlassian.net/images/icons/priorities/medium.svg", }, assignee: { accountId: "123456:abcdef-test-user", displayName: "Test Assignee", emailAddress: "assignee@test.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", }, }, reporter: { accountId: "123456:abcdef-reporter", displayName: "Test Reporter", emailAddress: "reporter@test.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", }, }, created: "2023-01-01T10:00:00.000Z", updated: "2023-01-02T15:30:00.000Z", labels: ["testing", "validation"], }, } as Issue, /** * Issue with null/undefined fields - common validation test scenario */ ISSUE_WITH_NULL_FIELDS: { id: "10002", key: "TEST-124", self: "https://test.atlassian.net/rest/api/3/issue/10002", fields: { summary: null, description: null, issuetype: null, status: null, priority: null, assignee: null, reporter: null, created: null, updated: null, labels: null, }, } as Issue, /** * Issue with missing fields - validation edge case */ ISSUE_WITH_MISSING_FIELDS: { id: "10003", key: "TEST-125", self: "https://test.atlassian.net/rest/api/3/issue/10003", fields: null, } as Issue, /** * Issue with ADF description - complex content testing */ get ISSUE_WITH_ADF_DESCRIPTION(): Issue { return { ...this.VALID_ISSUE, id: "10004", key: "TEST-126", fields: { ...this.VALID_ISSUE.fields, description: { version: 1, type: "doc", content: [ { type: "paragraph", content: [ { type: "text", text: "This is a test issue with ADF description content.", }, ], }, { type: "codeBlock", attrs: { language: "javascript", }, content: [ { type: "text", text: "console.log('Test code block');", }, ], }, ], } as ADFDocument, }, }; }, /** * Issue with invalid key format - validation error testing */ get ISSUE_WITH_INVALID_KEY(): Partial<Issue> { return { id: "10005", key: "invalid-key-format", self: "https://test.atlassian.net/rest/api/3/issue/10005", fields: this.VALID_ISSUE.fields, }; }, /** * Minimal valid issue - boundary testing */ MINIMAL_VALID_ISSUE: { id: "10006", key: "TEST-127", self: "https://test.atlassian.net/rest/api/3/issue/10006", fields: { summary: "Minimal Issue", }, } as Issue, /** * Valid comment template */ VALID_COMMENT: { id: "10001", body: "This is a test comment for validation testing", author: { accountId: "123456:comment-author", displayName: "Comment Author", 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", }, }, created: "2023-01-01T12:00:00.000Z", updated: "2023-01-01T12:00:00.000Z", } as Comment, /** * Valid user template */ VALID_USER: { accountId: "123456:valid-user", displayName: "Valid Test User", emailAddress: "valid.user@test.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", }, } as User, } as const; /** * Builder-based mock data for complex scenarios (20% use cases) * O(k) build time for flexible test construction */ export class IssueTestBuilder { private issue: Partial<Issue>; constructor(template?: Issue) { this.issue = template ? { ...template } : { ...IssueTestTemplates.VALID_ISSUE }; } /** * Set issue ID */ withId(id: string): IssueTestBuilder { this.issue.id = id; return this; } /** * Set issue key */ withKey(key: string): IssueTestBuilder { this.issue.key = key; return this; } /** * Set issue summary */ withSummary(summary: string | null): IssueTestBuilder { if (!this.issue.fields) { this.issue.fields = {}; } this.issue.fields.summary = summary; return this; } /** * Set issue description */ withDescription(description: string | ADFDocument | null): IssueTestBuilder { if (!this.issue.fields) { this.issue.fields = {}; } this.issue.fields.description = description; return this; } /** * Set issue status */ withStatus(statusName: string, colorName?: string): IssueTestBuilder { if (!this.issue.fields) { this.issue.fields = {}; } this.issue.fields.status = { name: statusName, statusCategory: { name: statusName, colorName: colorName || "blue-gray", }, }; return this; } /** * Set issue priority */ withPriority(priorityName: string): IssueTestBuilder { if (!this.issue.fields) { this.issue.fields = {}; } this.issue.fields.priority = { name: priorityName, iconUrl: `https://test.atlassian.net/images/icons/priorities/${priorityName.toLowerCase()}.svg`, }; return this; } /** * Set issue assignee */ withAssignee(user: User | null): IssueTestBuilder { if (!this.issue.fields) { this.issue.fields = {}; } this.issue.fields.assignee = user; return this; } /** * Set issue reporter */ withReporter(user: User): IssueTestBuilder { if (!this.issue.fields) { this.issue.fields = {}; } this.issue.fields.reporter = user; return this; } /** * Set issue labels */ withLabels(labels: string[] | null): IssueTestBuilder { if (!this.issue.fields) { this.issue.fields = {}; } this.issue.fields.labels = labels; return this; } /** * Set issue dates */ withDates(created: string, updated?: string): IssueTestBuilder { if (!this.issue.fields) { this.issue.fields = {}; } this.issue.fields.created = created; this.issue.fields.updated = updated || created; return this; } /** * Set null fields for validation testing */ withNullFields(): IssueTestBuilder { this.issue.fields = { summary: null, description: null, issuetype: null, status: null, priority: null, assignee: null, reporter: null, created: null, updated: null, labels: null, }; return this; } /** * Remove fields entirely for validation testing */ withoutFields(): IssueTestBuilder { this.issue.fields = null; return this; } /** * Set invalid key format for validation testing */ withInvalidKey(invalidKey: string): IssueTestBuilder { this.issue.key = invalidKey; return this; } /** * Build the final issue object */ build(): Issue { return this.issue as Issue; } } /** * Comment builder for complex comment scenarios */ export class CommentTestBuilder { private comment: Partial<Comment>; constructor(template?: Comment) { this.comment = template ? { ...template } : { ...IssueTestTemplates.VALID_COMMENT }; } withId(id: string): CommentTestBuilder { this.comment.id = id; return this; } withBody(body: string): CommentTestBuilder { this.comment.body = body; return this; } withAuthor(author: User): CommentTestBuilder { this.comment.author = author; return this; } withDates(created: string, updated?: string): CommentTestBuilder { this.comment.created = created; this.comment.updated = updated || created; return this; } build(): Comment { return this.comment as Comment; } } /** * User builder for complex user scenarios */ export class UserTestBuilder { private user: Partial<User>; constructor(template?: User) { this.user = template ? { ...template } : { ...IssueTestTemplates.VALID_USER }; } withAccountId(accountId: string): UserTestBuilder { this.user.accountId = accountId; return this; } withDisplayName(displayName: string): UserTestBuilder { this.user.displayName = displayName; return this; } withEmail(email: string): UserTestBuilder { this.user.emailAddress = email; return this; } withoutEmail(): UserTestBuilder { this.user.emailAddress = undefined; return this; } build(): User { return this.user as User; } } /** * Main factory implementing the hybrid system * Provides both template-based (fast) and builder-based (flexible) access */ export const IssueTestDataFactory = { /** * Template access for common scenarios (O(1) performance) */ templates: IssueTestTemplates, /** * Create a new issue builder for complex scenarios */ createIssueBuilder(template?: Issue): IssueTestBuilder { return new IssueTestBuilder(template); }, /** * Create a new comment builder for complex scenarios */ createCommentBuilder(template?: Comment): CommentTestBuilder { return new CommentTestBuilder(template); }, /** * Create a new user builder for complex scenarios */ createUserBuilder(template?: User): UserTestBuilder { return new UserTestBuilder(template); }, /** * Quick access methods for common templates */ validIssue(): Issue { return { ...IssueTestTemplates.VALID_ISSUE }; }, issueWithNullFields(): Issue { return { ...IssueTestTemplates.ISSUE_WITH_NULL_FIELDS }; }, issueWithMissingFields(): Issue { return { ...IssueTestTemplates.ISSUE_WITH_MISSING_FIELDS }; }, issueWithAdfDescription(): Issue { return { ...IssueTestTemplates.ISSUE_WITH_ADF_DESCRIPTION }; }, minimalValidIssue(): Issue { return { ...IssueTestTemplates.MINIMAL_VALID_ISSUE }; }, validComment(): Comment { return { ...IssueTestTemplates.VALID_COMMENT }; }, validUser(): User { return { ...IssueTestTemplates.VALID_USER }; }, /** * Generate multiple issues for list testing */ generateIssueList(count: number, baseTemplate?: Issue): Issue[] { const template = baseTemplate || IssueTestTemplates.VALID_ISSUE; return Array.from({ length: count }, (_, index) => ({ ...template, id: `${Number.parseInt(template.id) + index}`, key: `TEST-${123 + index}`, })); }, /** * Generate multiple comments for list testing */ generateCommentList(count: number, baseTemplate?: Comment): Comment[] { const template = baseTemplate || IssueTestTemplates.VALID_COMMENT; return Array.from({ length: count }, (_, index) => ({ ...template, id: `${Number.parseInt(template.id) + index}`, body: `${template.body} - Comment ${index + 1}`, })); }, } as const;

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