mock-helpers.ts•6.3 kB
/**
 * Mock Management Helpers
 * Utilities for creating and managing mocks across test suites
 */
import { type Mock, mock } from "bun:test";
import type { IssueSearchResult } from "@features/jira/issues/models/issue-search.models";
import type { Issue } from "@features/jira/issues/models/issue.models";
import { mockFactory } from "../mocks/jira-mock-factory";
interface MockResponse {
  ok: boolean;
  status: number;
  json: () => Promise<unknown>;
  text: () => Promise<string>;
}
interface JiraErrorResponse {
  errorMessages: string[];
  errors: Record<string, unknown>;
}
type FetchMock = Mock<() => Promise<MockResponse>>;
/**
 * Mock HTTP fetch responses for JIRA API calls
 */
const mocks = new Map<string, FetchMock>();
export const mockHttp = {
  /**
   * Mock a successful JIRA API response
   */
  mockJiraApiSuccess(endpoint: string, responseData: unknown): FetchMock {
    const fetchMock = mock(() =>
      Promise.resolve({
        ok: true,
        status: 200,
        json: () => Promise.resolve(responseData),
        text: () => Promise.resolve(JSON.stringify(responseData)),
      }),
    );
    mocks.set(endpoint, fetchMock);
    (global as { fetch: unknown }).fetch = fetchMock;
    return fetchMock;
  },
  /**
   * Mock a JIRA API error response
   */
  mockJiraApiError(
    endpoint: string,
    status: number,
    message: string,
  ): FetchMock {
    const errorResponse: JiraErrorResponse = {
      errorMessages: [message],
      errors: {},
    };
    const fetchMock = mock(() =>
      Promise.resolve({
        ok: false,
        status,
        json: () => Promise.resolve(errorResponse),
        text: () => Promise.resolve(JSON.stringify(errorResponse)),
      }),
    );
    mocks.set(endpoint, fetchMock);
    (global as { fetch: unknown }).fetch = fetchMock;
    return fetchMock;
  },
  /**
   * Mock network failure
   */
  mockNetworkError(endpoint: string): Mock<() => Promise<never>> {
    const fetchMock = mock(() => Promise.reject(new Error("Network error")));
    mocks.set(endpoint, fetchMock);
    (global as { fetch: unknown }).fetch = fetchMock;
    return fetchMock;
  },
  /**
   * Clear all HTTP mocks
   */
  clearAllMocks() {
    mocks.clear();
    (global as { fetch: unknown }).fetch = fetch; // Restore original fetch
  },
  /**
   * Get mock for specific endpoint
   */
  getMock(endpoint: string): FetchMock | undefined {
    return mocks.get(endpoint);
  },
};
/**
 * Pre-configured JIRA API mock scenarios
 */
export const jiraApiMocks = {
  /**
   * Mock get issue endpoint with sample data
   */
  mockGetIssue(issueKey: string, scenario?: string): FetchMock {
    const scenarioData = scenario ? mockFactory.getScenario(scenario) : null;
    const issue =
      scenarioData?.data.issues?.[0] ||
      mockFactory.createMockIssue({ key: issueKey });
    return mockHttp.mockJiraApiSuccess(`/rest/api/3/issue/${issueKey}`, issue);
  },
  /**
   * Mock search issues endpoint
   */
  mockSearchIssues(scenario?: string): FetchMock {
    const scenarioData = scenario ? mockFactory.getScenario(scenario) : null;
    const searchResult =
      scenarioData?.data.searchResults || mockFactory.createMockSearchResult();
    return mockHttp.mockJiraApiSuccess("/rest/api/3/search", searchResult);
  },
  /**
   * Mock get assigned issues (search with assignee = currentUser)
   */
  mockGetAssignedIssues(scenario?: string): FetchMock {
    const scenarioData = scenario ? mockFactory.getScenario(scenario) : null;
    const searchResult =
      scenarioData?.data.searchResults || mockFactory.createMockSearchResult();
    return mockHttp.mockJiraApiSuccess(
      "/rest/api/3/search?jql=assignee=currentUser()",
      searchResult,
    );
  },
  /**
   * Mock issue not found error
   */
  mockIssueNotFound(issueKey: string): FetchMock {
    return mockHttp.mockJiraApiError(
      `/rest/api/3/issue/${issueKey}`,
      404,
      `Issue Does Not Exist: ${issueKey}`,
    );
  },
  /**
   * Mock authentication error
   */
  mockAuthError(): FetchMock {
    return mockHttp.mockJiraApiError(
      "/rest/api/3/issue/TEST-1",
      401,
      "Authentication failed",
    );
  },
  /**
   * Mock permission error
   */
  mockPermissionError(issueKey: string): FetchMock {
    return mockHttp.mockJiraApiError(
      `/rest/api/3/issue/${issueKey}`,
      403,
      "Forbidden - insufficient permissions",
    );
  },
  /**
   * Mock network failure
   */
  mockNetworkError(endpoint: string): Mock<() => Promise<never>> {
    return mockHttp.mockNetworkError(endpoint);
  },
  /**
   * Mock a successful JIRA API response (direct access)
   */
  mockJiraApiSuccess(endpoint: string, responseData: unknown): FetchMock {
    return mockHttp.mockJiraApiSuccess(endpoint, responseData);
  },
  /**
   * Clear all JIRA API mocks
   */
  clearMocks() {
    mockHttp.clearAllMocks();
  },
};
/**
 * Test data builders for quick setup
 */
export const testDataBuilder = {
  /**
   * Create issue with specific status
   */
  issueWithStatus(status: string, statusColor = "blue"): Issue {
    return mockFactory.createMockIssue({
      fields: {
        ...mockFactory.createMockIssue().fields,
        status: {
          name: status,
          statusCategory: {
            name: status,
            colorName: statusColor,
          },
        },
      },
    });
  },
  /**
   * Create issue with specific priority
   */
  issueWithPriority(priority: string): Issue {
    return mockFactory.createMockIssue({
      fields: {
        ...mockFactory.createMockIssue().fields,
        priority: { name: priority },
      },
    });
  },
  /**
   * Create search result with specific count
   */
  searchResultWithCount(count: number): IssueSearchResult {
    const issues = Array.from({ length: count }, (_, i) =>
      mockFactory.createMockIssue({
        key: `TEST-${i + 1}`,
        fields: {
          ...mockFactory.createMockIssue().fields,
          summary: `Test issue ${i + 1}`,
        },
      }),
    );
    return mockFactory.createMockSearchResult({
      total: count,
      issues,
    });
  },
  /**
   * Create empty search result
   */
  emptySearchResult(): IssueSearchResult {
    return mockFactory.createMockSearchResult({
      total: 0,
      issues: [],
    });
  },
};