import { describe, expect, test, vi } from 'vitest'; import { createGiteaClient } from '../src/gitea.ts'; type MockFetch = ReturnType; function jsonResponse(body: unknown, status = 200): Response { return new Response(JSON.stringify(body), { status, headers: { 'content-type': 'application/json' }, }); } function makeClient(mockFetch: MockFetch) { return createGiteaClient({ baseUrl: 'https://git.kzntsv.site', token: 'test-token', fetch: mockFetch as unknown as typeof fetch, }); } describe('GiteaClient.getFile', () => { test('hits /api/v1/repos///contents/ with Authorization header', async () => { const mockFetch: MockFetch = vi.fn().mockResolvedValue( jsonResponse({ content: Buffer.from('hello world', 'utf8').toString('base64'), encoding: 'base64', }), ); const client = makeClient(mockFetch); await client.getFile('OpeItcLoc03', 'board-viewer', '.tasks/STATUS.md'); expect(mockFetch).toHaveBeenCalledTimes(1); const [url, init] = mockFetch.mock.calls[0]!; expect(url).toBe( 'https://git.kzntsv.site/api/v1/repos/OpeItcLoc03/board-viewer/contents/.tasks/STATUS.md', ); expect((init as RequestInit).headers).toMatchObject({ Authorization: 'token test-token', }); }); test('decodes base64 content and returns text', async () => { const original = 'STATUS.md body\nwith newline.'; const mockFetch: MockFetch = vi.fn().mockResolvedValue( jsonResponse({ content: Buffer.from(original, 'utf8').toString('base64'), encoding: 'base64', }), ); const client = makeClient(mockFetch); const result = await client.getFile('owner', 'repo', 'file.md'); expect(result).toBe(original); }); test('returns null on 404 (file absent)', async () => { const mockFetch: MockFetch = vi.fn().mockResolvedValue( new Response('Not Found', { status: 404 }), ); const client = makeClient(mockFetch); const result = await client.getFile('owner', 'repo', 'missing.md'); expect(result).toBeNull(); }); test('throws on non-404 HTTP error (e.g. 500)', async () => { const mockFetch: MockFetch = vi.fn().mockResolvedValue( new Response('Server error', { status: 500 }), ); const client = makeClient(mockFetch); await expect(client.getFile('owner', 'repo', 'file.md')).rejects.toThrow(/500/); }); }); describe('GiteaClient.getLatestCommitIso', () => { test('returns commit date ISO string when commit exists', async () => { const mockFetch: MockFetch = vi.fn().mockResolvedValue( jsonResponse([ { commit: { author: { date: '2026-05-22T08:10:00Z' } } }, ]), ); const client = makeClient(mockFetch); const iso = await client.getLatestCommitIso('owner', 'repo', '.tasks/foo.md'); expect(iso).toBe('2026-05-22T08:10:00Z'); const [url] = mockFetch.mock.calls[0]!; expect(url).toMatch( /\/api\/v1\/repos\/owner\/repo\/commits\?path=\.tasks%2Ffoo\.md&limit=1/, ); }); test('returns null when no commits touch the path', async () => { const mockFetch: MockFetch = vi.fn().mockResolvedValue(jsonResponse([])); const client = makeClient(mockFetch); expect(await client.getLatestCommitIso('o', 'r', 'p.md')).toBeNull(); }); }); describe('GiteaClient.rawUrl', () => { test('builds the raw URL for a file on the default branch', () => { const client = makeClient(vi.fn()); const url = client.rawUrl('OpeItcLoc03', 'board-viewer', '.tasks/STATUS.md'); expect(url).toBe( 'https://git.kzntsv.site/OpeItcLoc03/board-viewer/raw/branch/master/.tasks/STATUS.md', ); }); });