Skip to main content
Glama
callJiraApi.test.ts6.38 kB
import { handleApiError } from '../apiUtils' import { callJiraApi, RestMethod } from '../callJiraApi' import type { JiraApiConfig } from '../apiTypes' import { Failure } from '../../../utils/try' jest.mock('../apiUtils') jest.mock('../../../utils/logger', () => ({ log: jest.fn(), })) // Mock global fetch const mockHeaders = new Headers({ 'content-type': 'application/json' }) const mockText = jest.fn() const mockClone = jest.fn(() => ({ text: mockText })) const mockFetchResponse = { ok: true, status: 200, statusText: 'OK', json: jest.fn(), headers: mockHeaders, clone: mockClone, } global.fetch = jest.fn().mockResolvedValue(mockFetchResponse) const mockFetch = global.fetch as jest.MockedFunction<typeof fetch> const mockHandleApiError = handleApiError as jest.MockedFunction<typeof handleApiError> describe('callJiraApi', () => { const mockConfig: JiraApiConfig = { baseUrl: 'https://jira.example.com', username: 'testuser', apiToken: 'test-token', } const mockEndpoint = 'rest/api/3/issue/TEST-123' const mockResponseData = { id: '123', key: 'TEST-123' } const expectedAuth = Buffer.from(`${mockConfig.username}:${mockConfig.apiToken}`).toString('base64') beforeEach(() => { jest.clearAllMocks() mockFetchResponse.json.mockResolvedValue(mockResponseData) mockFetchResponse.ok = true mockFetchResponse.status = 200 mockFetchResponse.statusText = 'OK' mockText.mockResolvedValue(JSON.stringify(mockResponseData)) mockClone.mockClear() // Mock the handleApiError function to return a Promise<Try<never>> mockHandleApiError.mockImplementation((response, message) => Promise.resolve(Failure(new Error(`${message}: ${response.status} ${response.statusText}`))), ) }) test('should make a successful GET request', async () => { // Execute const result = await callJiraApi({ config: mockConfig, endpoint: mockEndpoint, method: RestMethod.GET, }) // Verify expect(mockFetch).toHaveBeenCalledWith( `${mockConfig.baseUrl}${mockEndpoint}`, expect.objectContaining({ method: 'GET', headers: expect.objectContaining({ Authorization: `Basic ${expectedAuth}`, Accept: 'application/json', }), }), ) expect(result.success).toBe(true) expect(result.value).toEqual(mockResponseData) }) test('should make a successful POST request with body', async () => { // Setup const mockBody = { summary: 'Test Issue', description: 'Test Description' } // Execute const result = await callJiraApi({ config: mockConfig, endpoint: mockEndpoint, method: RestMethod.POST, body: mockBody, }) // Verify expect(mockFetch).toHaveBeenCalledWith( `${mockConfig.baseUrl}${mockEndpoint}`, expect.objectContaining({ method: 'POST', body: JSON.stringify(mockBody), headers: expect.objectContaining({ Authorization: `Basic ${expectedAuth}`, Accept: 'application/json', }), }), ) expect(result.success).toBe(true) expect(result.value).toEqual(mockResponseData) }) test('should make a successful PUT request with body', async () => { // Setup const mockBody = { summary: 'Updated Test Issue' } // Execute const result = await callJiraApi({ config: mockConfig, endpoint: mockEndpoint, method: RestMethod.PUT, body: mockBody, }) // Verify expect(mockFetch).toHaveBeenCalledWith( `${mockConfig.baseUrl}${mockEndpoint}`, expect.objectContaining({ method: 'PUT', body: JSON.stringify(mockBody), headers: expect.objectContaining({ Authorization: `Basic ${expectedAuth}`, }), }), ) expect(result.success).toBe(true) expect(result.value).toEqual(mockResponseData) }) test('should not include body in GET requests even if provided', async () => { // Setup const mockBody = { someParam: 'value' } // Execute await callJiraApi({ config: mockConfig, endpoint: mockEndpoint, method: RestMethod.GET, body: mockBody, }) // Verify expect(mockFetch).toHaveBeenCalledWith( `${mockConfig.baseUrl}${mockEndpoint}`, expect.objectContaining({ method: 'GET', headers: expect.any(Object), }), ) // Check that body is not included const fetchCallArg = mockFetch.mock.calls[0][1] expect(fetchCallArg).not.toHaveProperty('body') }) test('should handle non-ok responses by calling handleApiError', async () => { // Setup mockFetchResponse.ok = false mockFetchResponse.status = 404 mockFetchResponse.statusText = 'Not Found' const mockError = new Error('Failed to GET rest/api/3/issue/TEST-123: 404 Not Found') mockHandleApiError.mockResolvedValue(Failure(mockError)) // Execute const result = await callJiraApi({ config: mockConfig, endpoint: mockEndpoint, method: RestMethod.GET, }) // Verify expect(mockHandleApiError).toHaveBeenCalledWith(mockFetchResponse, 'Failed to GET rest/api/3/issue/TEST-123') expect(result.success).toBe(false) expect(result.error).toEqual(mockError) }) test('should handle network errors', async () => { // Setup const networkError = new Error('Network error') mockFetch.mockRejectedValueOnce(networkError) // Execute const result = await callJiraApi({ config: mockConfig, endpoint: mockEndpoint, method: RestMethod.GET, }) // Verify expect(result.success).toBe(false) expect(result.error).toEqual(networkError) }) test('should handle JSON parsing errors', async () => { // Setup const jsonError = new Error('Invalid JSON') mockFetchResponse.json.mockRejectedValueOnce(jsonError) // Execute const result = await callJiraApi({ config: mockConfig, endpoint: mockEndpoint, method: RestMethod.GET, }) // Verify expect(result.success).toBe(false) expect(result.error).toEqual(jsonError) }) test('should return Success(null) for 204 No Content responses', async () => { // Setup mockFetchResponse.status = 204 mockFetchResponse.ok = true mockFetchResponse.statusText = 'No Content' // 204 responses have no body, so .json() should not be called mockFetchResponse.json.mockClear() // Execute const result = await callJiraApi({ config: mockConfig, endpoint: mockEndpoint, method: RestMethod.DELETE, // DELETE is a common method for 204 }) // Verify expect(result.success).toBe(true) expect(result.value).toBeNull() expect(mockFetchResponse.json).not.toHaveBeenCalled() }) })

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

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