Spaces:
Sleeping
Sleeping
File size: 4,618 Bytes
194aaa5 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | import { describe, it, expect, vi, beforeEach } from 'vitest';
const mockFetch = vi.fn();
global.fetch = mockFetch;
// Set VITE_API_URL for tests
import.meta.env.VITE_API_URL = 'http://localhost:8000';
import {
fetchDocuments,
uploadDocument,
deleteDocument,
streamChat,
} from '../client';
// Mock auth headers
vi.mock('../../lib/auth', () => ({
getAuthHeaders: vi.fn(() => ({ Authorization: 'Bearer test-token' })),
}));
describe('API client', () => {
beforeEach(() => {
vi.clearAllMocks();
mockFetch.mockReset();
});
// ββ fetchDocuments ββ
describe('fetchDocuments', () => {
it('fetches documents list with auth header', async () => {
const docs = [
{ id: '1', user_id: 'u1', filename: 'doc1.pdf', status: 'ready', created_at: '2025-01-01' },
];
mockFetch.mockResolvedValueOnce({
ok: true,
json: async () => docs,
});
const result = await fetchDocuments();
expect(result).toEqual(docs);
expect(mockFetch).toHaveBeenCalledWith(
'http://localhost:8000/documents',
expect.objectContaining({
headers: expect.objectContaining({ Authorization: 'Bearer test-token' }),
})
);
});
it('throws on fetch failure', async () => {
mockFetch.mockResolvedValueOnce({ ok: false, json: async () => ({ detail: 'Failed' }) });
await expect(fetchDocuments()).rejects.toThrow('Failed to fetch documents');
});
});
// ββ uploadDocument ββ
describe('uploadDocument', () => {
it('uploads a file as FormData', async () => {
const file = new File(['test content'], 'test.txt', { type: 'text/plain' });
mockFetch.mockResolvedValueOnce({
ok: true,
json: async () => ({ id: '1', filename: 'test.txt', status: 'ready' }),
});
await uploadDocument(file);
expect(mockFetch).toHaveBeenCalledWith(
'http://localhost:8000/documents/upload',
expect.objectContaining({
method: 'POST',
headers: expect.not.objectContaining({ 'Content-Type': 'application/json' }),
})
);
});
it('throws on upload failure with detail', async () => {
const file = new File(['bad'], 'bad.txt', { type: 'text/plain' });
mockFetch.mockResolvedValueOnce({
ok: false,
json: async () => ({ detail: 'Unsupported file' }),
});
await expect(uploadDocument(file)).rejects.toThrow('Unsupported file');
});
});
// ββ deleteDocument ββ
describe('deleteDocument', () => {
it('sends DELETE request', async () => {
mockFetch.mockResolvedValueOnce({ ok: true });
await deleteDocument('doc-123');
expect(mockFetch).toHaveBeenCalledWith(
'http://localhost:8000/documents/doc-123',
expect.objectContaining({ method: 'DELETE' })
);
});
it('throws on delete failure', async () => {
mockFetch.mockResolvedValueOnce({ ok: false });
await expect(deleteDocument('doc-123')).rejects.toThrow('Failed to delete document');
});
});
// ββ streamChat ββ
describe('streamChat', () => {
function createMockStream(chunks: string[]): ReadableStream {
const encoder = new TextEncoder();
return new ReadableStream({
async start(controller) {
for (const chunk of chunks) {
controller.enqueue(encoder.encode(chunk));
}
controller.close();
},
});
}
it('calls onChunk with streamed content', async () => {
const mockBody = createMockStream(['Hello', ' world']);
mockFetch.mockResolvedValueOnce({
ok: true,
body: mockBody,
});
const onChunk = vi.fn();
const onError = vi.fn();
await streamChat(
{ messages: [{ role: 'user', content: 'Hi' }], document_id: null },
{ onChunk, onError },
);
expect(onChunk).toHaveBeenCalled();
expect(onError).not.toHaveBeenCalled();
});
it('calls onError when request fails', async () => {
mockFetch.mockResolvedValueOnce({
ok: false,
json: async () => ({ detail: 'Chat error' }),
});
const onChunk = vi.fn();
const onError = vi.fn();
await streamChat(
{ messages: [{ role: 'user', content: 'Hi' }], document_id: null },
{ onChunk, onError },
);
expect(onError).toHaveBeenCalledWith('Chat error');
});
});
}); |