138 lines
3.6 KiB
TypeScript
138 lines
3.6 KiB
TypeScript
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
|
|
);
|
|
});
|
|
});
|