import { describe, test, expect, vi, beforeEach } from 'vitest'; import { uploadRecipeWithIngredientsDTO, uploadRecipeImage } from '$lib/server/tandoor'; import * as logger from '$lib/server/utils/logger'; vi.mock('$lib/server/tandoor-config', () => ({ tandoorConfig: { serverUrl: 'http://localhost:8000', token: 'test-token' } })); describe('tandoor logging', () => { let logErrorSpy: any; beforeEach(() => { vi.clearAllMocks(); logErrorSpy = vi.spyOn(logger, 'logError'); }); test('should use logError on upload failure', async () => { vi.spyOn(global, 'fetch').mockRejectedValue(new Error('Network error')); const recipe = { name: 'Test Recipe', servings: 4, description: 'Test description', ingredients: [{ item: 'Flour', amount: '2', unit: 'cups' }], steps: ['Mix ingredients'] }; await uploadRecipeWithIngredientsDTO(recipe); expect(logErrorSpy).toHaveBeenCalledWith('[Tandoor] Fetch error', expect.any(Error)); }); test('should use logError on API error response', async () => { const errorBody = { detail: 'Invalid token' }; vi.spyOn(global, 'fetch').mockResolvedValue({ ok: false, status: 401, statusText: 'Unauthorized', json: vi.fn().mockResolvedValue(errorBody) } as any); const recipe = { name: 'Test Recipe', servings: 4, description: null, ingredients: null, steps: null }; await uploadRecipeWithIngredientsDTO(recipe); expect(logErrorSpy).toHaveBeenCalledWith( expect.stringContaining('[Tandoor] API Error'), errorBody ); }); test('should use logError on recipe upload exception', async () => { const error = new Error('Upload failed'); vi.spyOn(global, 'fetch').mockResolvedValue({ ok: true, json: vi.fn().mockRejectedValue(error) } as any); const recipe = { name: 'Test Recipe', servings: 4, description: null, ingredients: null, steps: null }; await uploadRecipeWithIngredientsDTO(recipe); expect(logErrorSpy).toHaveBeenCalledWith('[Tandoor] Fetch error', expect.any(Error)); }); test('should use logError on image upload failure', async () => { const error = new Error('Image upload failed'); vi.spyOn(global, 'fetch').mockRejectedValue(error); const result = await uploadRecipeImage(123, 'https://example.com/image.jpg'); expect(result.success).toBe(false); expect(logErrorSpy).toHaveBeenCalledWith('[Tandoor Upload] Exception', error); }); test('should use logError instead of manual error logging', async () => { const error = new Error('Test error'); vi.spyOn(global, 'fetch').mockRejectedValue(error); await uploadRecipeWithIngredientsDTO({ name: 'Test', servings: null, description: null, ingredients: null, steps: null }); // Verify logError was called (which handles stack trace serialization) expect(logErrorSpy).toHaveBeenCalledWith('[Tandoor] Fetch error', error); // logError itself logs stack traces, which is expected behavior // The key is that tandoor.ts uses logError instead of manual logging }); test('should serialize complex error objects', async () => { const complexError = { code: 'ERR_VALIDATION', message: 'Invalid recipe data', details: { field: 'name', reason: 'required' } }; vi.spyOn(global, 'fetch').mockResolvedValue({ ok: false, status: 400, statusText: 'Bad Request', json: vi.fn().mockResolvedValue(complexError) } as any); await uploadRecipeWithIngredientsDTO({ name: 'Test', servings: null, description: null, ingredients: null, steps: null }); expect(logErrorSpy).toHaveBeenCalledWith( expect.stringContaining('[Tandoor] API Error'), complexError ); }); });