diff --git a/lib/services/autotask-client.test.ts b/lib/services/autotask-client.test.ts new file mode 100644 index 0000000..cc50a0d --- /dev/null +++ b/lib/services/autotask-client.test.ts @@ -0,0 +1,73 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; +import { AutotaskClient } from './autotask-client'; +import type { AutotaskConfig } from '@/lib/types/autotask'; + +const FIXTURE_CONFIG: AutotaskConfig = { + apiUrl: 'https://webservices.autotask.net/atservicesrest/v1.0', + username: 'fixture@example.com', + password: 'fixture-secret', + apiIntegrationCode: 'FIXTURE-CODE', +}; + +function jsonResponse(body: unknown, ok = true, status = 200): Response { + return { + ok, + status, + statusText: ok ? 'OK' : 'Error', + text: async () => JSON.stringify(body), + } as unknown as Response; +} + +describe('AutotaskClient.getAttachmentContent', () => { + const originalFetch = global.fetch; + + beforeEach(() => { + global.fetch = vi.fn(); + }); + + afterEach(() => { + global.fetch = originalFetch; + vi.restoreAllMocks(); + }); + + it('returns items[0] with populated base64 data when the API returns an items-shaped envelope', async () => { + const attachment = { id: 555, fullPath: 'rfc.eml', title: 'rfc.eml', data: 'YmFzZTY0LWNvbnRlbnQ=' }; + (global.fetch as unknown as ReturnType).mockResolvedValue( + jsonResponse({ items: [attachment] }) + ); + + const client = new AutotaskClient(FIXTURE_CONFIG); + const result = await client.getAttachmentContent('Tickets', 12345, 555); + + expect(result).toEqual(attachment); + expect(global.fetch).toHaveBeenCalledWith( + `${FIXTURE_CONFIG.apiUrl}/Tickets/12345/Attachments/555`, + expect.objectContaining({ method: 'GET' }) + ); + }); + + it('returns null when the API returns an empty items array', async () => { + (global.fetch as unknown as ReturnType).mockResolvedValue( + jsonResponse({ items: [] }) + ); + + const client = new AutotaskClient(FIXTURE_CONFIG); + const result = await client.getAttachmentContent('Tickets', 12345, 999); + + expect(result).toBeNull(); + }); + + it('returns null (not the attachment) when the API returns an {item:...}-shaped response', async () => { + // Guards against a future refactor copying uploadAttachment's `.item` + // convention onto this method — the live shape is `.items`. + const attachment = { id: 555, fullPath: 'rfc.eml', title: 'rfc.eml', data: 'YmFzZTY0LWNvbnRlbnQ=' }; + (global.fetch as unknown as ReturnType).mockResolvedValue( + jsonResponse({ item: attachment }) + ); + + const client = new AutotaskClient(FIXTURE_CONFIG); + const result = await client.getAttachmentContent('Tickets', 12345, 555); + + expect(result).toBeNull(); + }); +});