Add user database service and unit tests
All checks were successful
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Successful in 4m28s
All checks were successful
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Successful in 4m28s
- Implement user database service with functions for user management (create, find, update, delete). - Add comprehensive unit tests for user database service using Vitest. - Mock database interactions to ensure isolated testing. - Create setup files for unit tests to handle database connections and global mocks. - Introduce error handling for unique constraints and foreign key violations. - Enhance logging for better traceability during database operations.
This commit is contained in:
129
src/services/db/recipe.db.test.ts
Normal file
129
src/services/db/recipe.db.test.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
// src/services/db/recipe.db.test.ts
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import {
|
||||
getRecipesBySalePercentage,
|
||||
getRecipesByMinSaleIngredients,
|
||||
findRecipesByIngredientAndTag,
|
||||
getUserFavoriteRecipes,
|
||||
addFavoriteRecipe,
|
||||
removeFavoriteRecipe,
|
||||
getRecipeComments,
|
||||
addRecipeComment,
|
||||
forkRecipe,
|
||||
} from './recipe.db';
|
||||
import { Pool } from 'pg';
|
||||
|
||||
const mockQuery = vi.fn();
|
||||
import type { Recipe, FavoriteRecipe, RecipeComment } from '../../types';
|
||||
|
||||
// Mock the logger to prevent console output during tests
|
||||
vi.mock('../logger', () => ({
|
||||
logger: {
|
||||
info: vi.fn(),
|
||||
warn: vi.fn(),
|
||||
error: vi.fn(),
|
||||
debug: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
describe('Recipe DB Service', () => {
|
||||
beforeEach(() => {
|
||||
// FIX: Use mockImplementation with a standard function to support 'new Pool()'
|
||||
vi.mocked(Pool).mockImplementation(function() {
|
||||
console.log('[DEBUG] recipe.db.test.ts: Local Pool mock instantiated via "new"');
|
||||
return {
|
||||
query: mockQuery,
|
||||
connect: vi.fn().mockResolvedValue({ query: mockQuery, release: vi.fn() }),
|
||||
on: vi.fn(),
|
||||
end: vi.fn(),
|
||||
totalCount: 0,
|
||||
idleCount: 0,
|
||||
waitingCount: 0,
|
||||
} as unknown as Pool;
|
||||
});
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('getRecipesBySalePercentage', () => {
|
||||
it('should call the correct database function', async () => {
|
||||
mockQuery.mockResolvedValue({ rows: [] });
|
||||
await getRecipesBySalePercentage(50);
|
||||
expect(mockQuery).toHaveBeenCalledWith('SELECT * FROM public.get_recipes_by_sale_percentage($1)', [50]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getRecipesByMinSaleIngredients', () => {
|
||||
it('should call the correct database function', async () => {
|
||||
mockQuery.mockResolvedValue({ rows: [] });
|
||||
await getRecipesByMinSaleIngredients(3);
|
||||
expect(mockQuery).toHaveBeenCalledWith('SELECT * FROM public.get_recipes_by_min_sale_ingredients($1)', [3]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('findRecipesByIngredientAndTag', () => {
|
||||
it('should call the correct database function', async () => {
|
||||
mockQuery.mockResolvedValue({ rows: [] });
|
||||
await findRecipesByIngredientAndTag('chicken', 'quick');
|
||||
expect(mockQuery).toHaveBeenCalledWith('SELECT * FROM public.find_recipes_by_ingredient_and_tag($1, $2)', ['chicken', 'quick']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getUserFavoriteRecipes', () => {
|
||||
it('should call the correct database function', async () => {
|
||||
mockQuery.mockResolvedValue({ rows: [] });
|
||||
await getUserFavoriteRecipes('user-123');
|
||||
expect(mockQuery).toHaveBeenCalledWith('SELECT * FROM public.get_user_favorite_recipes($1)', ['user-123']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addFavoriteRecipe', () => {
|
||||
it('should execute an INSERT query and return the new favorite', async () => {
|
||||
const mockFavorite: FavoriteRecipe = { user_id: 'user-123', recipe_id: 1, created_at: new Date().toISOString() };
|
||||
mockQuery.mockResolvedValue({ rows: [mockFavorite] });
|
||||
|
||||
const result = await addFavoriteRecipe('user-123', 1);
|
||||
|
||||
expect(mockQuery).toHaveBeenCalledWith(expect.stringContaining('INSERT INTO public.favorite_recipes'), ['user-123', 1]);
|
||||
expect(result).toEqual(mockFavorite);
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeFavoriteRecipe', () => {
|
||||
it('should execute a DELETE query', async () => {
|
||||
mockQuery.mockResolvedValue({ rowCount: 1 });
|
||||
await removeFavoriteRecipe('user-123', 1);
|
||||
expect(mockQuery).toHaveBeenCalledWith('DELETE FROM public.favorite_recipes WHERE user_id = $1 AND recipe_id = $2', ['user-123', 1]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getRecipeComments', () => {
|
||||
it('should execute a SELECT query with a JOIN', async () => {
|
||||
mockQuery.mockResolvedValue({ rows: [] });
|
||||
await getRecipeComments(1);
|
||||
expect(mockQuery).toHaveBeenCalledWith(expect.stringContaining('FROM public.recipe_comments rc'), [1]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addRecipeComment', () => {
|
||||
it('should execute an INSERT query and return the new comment', async () => {
|
||||
const mockComment: RecipeComment = { recipe_comment_id: 1, recipe_id: 1, user_id: 'user-123', content: 'Great!', status: 'visible', created_at: new Date().toISOString() };
|
||||
mockQuery.mockResolvedValue({ rows: [mockComment] });
|
||||
|
||||
const result = await addRecipeComment(1, 'user-123', 'Great!');
|
||||
|
||||
expect(mockQuery).toHaveBeenCalledWith(expect.stringContaining('INSERT INTO public.recipe_comments'), [1, 'user-123', 'Great!', undefined]);
|
||||
expect(result).toEqual(mockComment);
|
||||
});
|
||||
});
|
||||
|
||||
describe('forkRecipe', () => {
|
||||
it('should call the fork_recipe database function', async () => {
|
||||
const mockRecipe: Recipe = { recipe_id: 2, name: 'Forked Recipe', avg_rating: 0, rating_count: 0, fork_count: 0, status: 'private', created_at: new Date().toISOString() };
|
||||
mockQuery.mockResolvedValue({ rows: [mockRecipe] });
|
||||
|
||||
const result = await forkRecipe('user-123', 1);
|
||||
expect(mockQuery).toHaveBeenCalledWith('SELECT * FROM public.fork_recipe($1, $2)', ['user-123', 1]);
|
||||
expect(result).toEqual(mockRecipe);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user