mock mock mock !
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 57m50s
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 57m50s
This commit is contained in:
@@ -1,5 +1,43 @@
|
||||
// src/tests/utils/mockFactories.ts
|
||||
import { UserProfile, User, Flyer, Store, SuggestedCorrection, Brand, FlyerItem, MasterGroceryItem, ShoppingList, ShoppingListItem, Achievement, UserAchievement, Budget, SpendingByCategory, Recipe, RecipeComment, ActivityLogItem, DietaryRestriction, Appliance, Notification, UnmatchedFlyerItem, AdminUserView, WatchedItemDeal, LeaderboardUser, UserWithPasswordHash, Profile, Address } from '../../types';
|
||||
import { UserProfile, User, Flyer, Store, SuggestedCorrection, Brand, Category, FlyerItem, MasterGroceryItem, ShoppingList, ShoppingListItem, Achievement, UserAchievement, Budget, SpendingByCategory, Recipe, RecipeIngredient, RecipeComment, ActivityLogItem, DietaryRestriction, UserDietaryRestriction, Appliance, UserAppliance, Notification, UnmatchedFlyerItem, AdminUserView, WatchedItemDeal, LeaderboardUser, UserWithPasswordHash, Profile, Address, MenuPlan, PlannedMeal, PantryItem, Product, ShoppingTrip, ShoppingTripItem, Receipt, ReceiptItem } from '../../types';
|
||||
|
||||
// --- ID Generator for Deterministic Mocking ---
|
||||
let idCounter = 0;
|
||||
|
||||
/**
|
||||
* Generates a sequential number for deterministic IDs in tests.
|
||||
*/
|
||||
const getNextId = () => ++idCounter;
|
||||
|
||||
/**
|
||||
* Resets the ID counter. Call this in `beforeEach` in your test setup
|
||||
* to ensure tests are isolated.
|
||||
*
|
||||
* @example
|
||||
* beforeEach(() => {
|
||||
* resetMockIds();
|
||||
* });
|
||||
*/
|
||||
export const resetMockIds = () => {
|
||||
idCounter = 0;
|
||||
};
|
||||
// --- End ID Generator ---
|
||||
|
||||
/**
|
||||
* Creates a mock User object for use in tests.
|
||||
* @param overrides - An object containing properties to override the default mock values.
|
||||
* @returns A complete and type-safe User object.
|
||||
*/
|
||||
export const createMockUser = (overrides: Partial<User> = {}): User => {
|
||||
const userId = overrides.user_id ?? `user-${getNextId()}`;
|
||||
|
||||
const defaultUser: User = {
|
||||
user_id: userId,
|
||||
email: `${userId}@example.com`,
|
||||
};
|
||||
|
||||
return { ...defaultUser, ...overrides };
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a mock UserProfile object for use in tests, ensuring type safety.
|
||||
@@ -10,24 +48,53 @@ import { UserProfile, User, Flyer, Store, SuggestedCorrection, Brand, FlyerItem,
|
||||
* @returns A complete and type-safe UserProfile object.
|
||||
*/
|
||||
export const createMockUserProfile = (overrides: Partial<UserProfile & { user: Partial<User> }> = {}): UserProfile => {
|
||||
const userId = overrides.user_id ?? `user-${Math.random().toString(36).substring(2, 9)}`;
|
||||
// Ensure the user_id is consistent between the profile and the nested user object
|
||||
const userOverrides: Partial<User> = overrides.user || {};
|
||||
if (overrides.user_id && !userOverrides.user_id) {
|
||||
userOverrides.user_id = overrides.user_id;
|
||||
}
|
||||
|
||||
const user = createMockUser(userOverrides);
|
||||
|
||||
const defaultProfile: UserProfile = {
|
||||
user_id: userId,
|
||||
user_id: user.user_id,
|
||||
role: 'user',
|
||||
points: 0,
|
||||
full_name: 'Test User',
|
||||
avatar_url: null,
|
||||
preferences: {},
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
created_by: null,
|
||||
address: null,
|
||||
user: {
|
||||
user_id: userId,
|
||||
email: `${userId}@example.com`,
|
||||
...overrides.user, // Apply nested user overrides
|
||||
},
|
||||
user,
|
||||
};
|
||||
delete (defaultProfile as Partial<UserProfile>).address_id;
|
||||
|
||||
// Exclude 'user' from overrides to prevent overwriting the complete user object with a partial one
|
||||
const { user: _, ...profileOverrides } = overrides;
|
||||
|
||||
return { ...defaultProfile, ...profileOverrides, user_id: user.user_id };
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a mock Store object for use in tests.
|
||||
* @param overrides - An object containing properties to override the default mock values.
|
||||
* @returns A complete and type-safe Store object.
|
||||
*/
|
||||
export const createMockStore = (overrides: Partial<Store> = {}): Store => {
|
||||
const storeId = overrides.store_id ?? getNextId();
|
||||
|
||||
const defaultStore: Store = {
|
||||
store_id: storeId,
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
name: 'Mock Store',
|
||||
logo_url: null,
|
||||
created_by: null,
|
||||
};
|
||||
|
||||
return { ...defaultProfile, ...overrides };
|
||||
return { ...defaultStore, ...overrides };
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -38,33 +105,52 @@ export const createMockUserProfile = (overrides: Partial<UserProfile & { user: P
|
||||
* e.g., `createMockFlyer({ item_count: 50, store: { name: 'Walmart' } })`
|
||||
* @returns A complete and type-safe Flyer object.
|
||||
*/
|
||||
export const createMockFlyer = (overrides: Partial<Flyer & { store: Partial<Store> }> = {}): Flyer => {
|
||||
const flyerId = overrides.flyer_id ?? Math.floor(Math.random() * 1000);
|
||||
const storeId = overrides.store?.store_id ?? Math.floor(Math.random() * 100);
|
||||
export const createMockFlyer = (overrides: Omit<Partial<Flyer>, 'store'> & { store?: Partial<Store> } = {}): Flyer => {
|
||||
const flyerId = overrides.flyer_id ?? getNextId();
|
||||
|
||||
// Ensure the store_id is consistent between the flyer and the nested store object
|
||||
const storeOverrides = overrides.store || {};
|
||||
if (overrides.store_id && !storeOverrides.store_id) {
|
||||
storeOverrides.store_id = overrides.store_id;
|
||||
}
|
||||
|
||||
const store = createMockStore(storeOverrides);
|
||||
|
||||
// Determine the final file_name to generate dependent properties from.
|
||||
const fileName = overrides.file_name ?? `flyer-${flyerId}.jpg`;
|
||||
|
||||
// A simple hash function for mock checksum generation.
|
||||
const generateMockChecksum = (str: string) => {
|
||||
let hash = 0;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
const char = str.charCodeAt(i);
|
||||
hash = (hash << 5) - hash + char;
|
||||
hash |= 0; // Convert to 32bit integer
|
||||
}
|
||||
return `mock-checksum-${Math.abs(hash).toString(16)}`;
|
||||
};
|
||||
|
||||
const defaultFlyer: Flyer = {
|
||||
flyer_id: flyerId,
|
||||
created_at: new Date().toISOString(),
|
||||
file_name: `flyer-${flyerId}.jpg`,
|
||||
image_url: `/flyer-images/flyer-${flyerId}.jpg`,
|
||||
icon_url: `/flyer-images/icons/icon-flyer-${flyerId}.webp`,
|
||||
checksum: `checksum-${flyerId}`,
|
||||
store_id: storeId,
|
||||
updated_at: new Date().toISOString(),
|
||||
file_name: fileName,
|
||||
image_url: `/flyer-images/${fileName}`,
|
||||
icon_url: `/flyer-images/icons/icon-${fileName.replace(/\.[^/.]+$/, ".webp")}`,
|
||||
checksum: generateMockChecksum(fileName),
|
||||
store_id: store.store_id,
|
||||
valid_from: new Date().toISOString().split('T')[0],
|
||||
valid_to: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0], // 7 days from now
|
||||
store_address: '123 Main St, Anytown, USA',
|
||||
item_count: Math.floor(Math.random() * 100) + 10,
|
||||
item_count: 50,
|
||||
uploaded_by: null,
|
||||
store: {
|
||||
store_id: storeId,
|
||||
created_at: new Date().toISOString(),
|
||||
name: 'Mock Store',
|
||||
logo_url: null,
|
||||
},
|
||||
store,
|
||||
};
|
||||
|
||||
// Deep merge the store object and then merge the top-level properties.
|
||||
return { ...defaultFlyer, ...overrides, store: { ...defaultFlyer.store, ...overrides.store } as Store };
|
||||
const { store: _, ...flyerOverrides } = overrides;
|
||||
|
||||
// Apply overrides. If checksum, file_name, etc., are in overrides, they will correctly replace the generated defaults.
|
||||
return { ...defaultFlyer, ...flyerOverrides };
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -74,13 +160,14 @@ export const createMockFlyer = (overrides: Partial<Flyer & { store: Partial<Stor
|
||||
*/
|
||||
export const createMockSuggestedCorrection = (overrides: Partial<SuggestedCorrection> = {}): SuggestedCorrection => {
|
||||
const defaultCorrection: SuggestedCorrection = {
|
||||
suggested_correction_id: Math.floor(Math.random() * 1000),
|
||||
flyer_item_id: Math.floor(Math.random() * 10000),
|
||||
user_id: `user-${Math.random().toString(36).substring(2, 9)}`,
|
||||
suggested_correction_id: getNextId(),
|
||||
flyer_item_id: getNextId(),
|
||||
user_id: `user-${getNextId()}`,
|
||||
correction_type: 'price',
|
||||
suggested_value: '$9.99',
|
||||
status: 'pending',
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
};
|
||||
|
||||
return { ...defaultCorrection, ...overrides };
|
||||
@@ -92,10 +179,12 @@ export const createMockSuggestedCorrection = (overrides: Partial<SuggestedCorrec
|
||||
* @returns A complete and type-safe Brand object.
|
||||
*/
|
||||
export const createMockBrand = (overrides: Partial<Brand> = {}): Brand => {
|
||||
const brandId = overrides.brand_id ?? Math.floor(Math.random() * 100);
|
||||
const brandId = overrides.brand_id ?? getNextId();
|
||||
|
||||
const defaultBrand: Brand = {
|
||||
brand_id: brandId,
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
name: `Brand ${brandId}`,
|
||||
logo_url: null,
|
||||
store_id: null,
|
||||
@@ -105,15 +194,62 @@ export const createMockBrand = (overrides: Partial<Brand> = {}): Brand => {
|
||||
return { ...defaultBrand, ...overrides };
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a mock Category object for use in tests.
|
||||
* @param overrides - An object containing properties to override the default mock values.
|
||||
* @returns A complete and type-safe Category object.
|
||||
*/
|
||||
export const createMockCategory = (overrides: Partial<Category> = {}): Category => {
|
||||
const categoryId = overrides.category_id ?? getNextId();
|
||||
|
||||
const defaultCategory: Category = {
|
||||
category_id: categoryId,
|
||||
name: `Category ${categoryId}`,
|
||||
};
|
||||
|
||||
return { ...defaultCategory, ...overrides };
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a mock Product object for use in tests.
|
||||
* @param overrides - An object containing properties to override the default mock values.
|
||||
* Can optionally include `master_item` and `brand` to link IDs.
|
||||
* @returns A complete and type-safe Product object.
|
||||
*/
|
||||
export const createMockProduct = (overrides: Partial<Product> & { master_item?: Partial<MasterGroceryItem>, brand?: Partial<Brand> } = {}): Product => {
|
||||
const productId = overrides.product_id ?? getNextId();
|
||||
const masterItemId = overrides.master_item_id ?? overrides.master_item?.master_grocery_item_id ?? getNextId();
|
||||
const brandId = overrides.brand_id ?? overrides.brand?.brand_id; // brand is optional
|
||||
|
||||
const defaultProduct: Product = {
|
||||
product_id: productId,
|
||||
master_item_id: masterItemId,
|
||||
brand_id: brandId,
|
||||
name: `Mock Product ${productId}`,
|
||||
description: 'A mock product description.',
|
||||
size: '100g',
|
||||
upc_code: `0000${productId}`.slice(-12),
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
};
|
||||
|
||||
const { master_item: _, brand: __, ...itemOverrides } = overrides;
|
||||
|
||||
return { ...defaultProduct, ...itemOverrides };
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a mock FlyerItem object for use in tests.
|
||||
* @param overrides - An object containing properties to override the default mock values.
|
||||
* @returns A complete and type-safe FlyerItem object.
|
||||
*/
|
||||
export const createMockFlyerItem = (overrides: Partial<FlyerItem> = {}): FlyerItem => {
|
||||
export const createMockFlyerItem = (overrides: Partial<FlyerItem> & { flyer?: Partial<Flyer> } = {}): FlyerItem => {
|
||||
const flyerItemId = overrides.flyer_item_id ?? getNextId();
|
||||
const flyerId = overrides.flyer_id ?? overrides.flyer?.flyer_id ?? getNextId();
|
||||
|
||||
const defaultItem: FlyerItem = {
|
||||
flyer_item_id: Math.floor(Math.random() * 10000),
|
||||
flyer_id: Math.floor(Math.random() * 1000),
|
||||
flyer_item_id: flyerItemId,
|
||||
flyer_id: flyerId,
|
||||
created_at: new Date().toISOString(),
|
||||
item: 'Mock Item',
|
||||
price_display: '$1.99',
|
||||
@@ -124,7 +260,9 @@ export const createMockFlyerItem = (overrides: Partial<FlyerItem> = {}): FlyerIt
|
||||
updated_at: new Date().toISOString(),
|
||||
};
|
||||
|
||||
return { ...defaultItem, ...overrides };
|
||||
const { flyer: _, ...itemOverrides } = overrides;
|
||||
|
||||
return { ...defaultItem, ...itemOverrides };
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -132,26 +270,71 @@ export const createMockFlyerItem = (overrides: Partial<FlyerItem> = {}): FlyerIt
|
||||
* @param overrides - An object containing properties to override the default mock values.
|
||||
* @returns A complete and type-safe Recipe object.
|
||||
*/
|
||||
export const createMockRecipe = (overrides: Partial<Recipe> = {}): Recipe => {
|
||||
const recipeId = overrides.recipe_id ?? Math.floor(Math.random() * 1000);
|
||||
export const createMockRecipe = (overrides: Omit<Partial<Recipe>, 'comments' | 'ingredients'> & { comments?: Partial<RecipeComment>[], ingredients?: Partial<RecipeIngredient>[] } = {}): Recipe => {
|
||||
const recipeId = overrides.recipe_id ?? getNextId();
|
||||
|
||||
const defaultRecipe: Recipe = {
|
||||
recipe_id: recipeId,
|
||||
user_id: `user-${Math.random().toString(36).substring(2, 9)}`,
|
||||
user_id: `user-${getNextId()}`,
|
||||
name: `Mock Recipe ${recipeId}`,
|
||||
description: 'A delicious mock recipe.',
|
||||
instructions: '1. Mock the ingredients. 2. Mock the cooking. 3. Enjoy!',
|
||||
avg_rating: Math.random() * 5,
|
||||
rating_count: Math.floor(Math.random() * 100),
|
||||
fork_count: Math.floor(Math.random() * 20),
|
||||
avg_rating: 4.5,
|
||||
rating_count: 50,
|
||||
fork_count: 10,
|
||||
status: 'public',
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
prep_time_minutes: 15,
|
||||
cook_time_minutes: 30,
|
||||
servings: 4,
|
||||
};
|
||||
|
||||
return { ...defaultRecipe, ...overrides };
|
||||
const { comments: commentsOverrides, ingredients: ingredientsOverrides, ...recipeOverrides } = overrides;
|
||||
const recipe = { ...defaultRecipe, ...recipeOverrides };
|
||||
|
||||
if (commentsOverrides) {
|
||||
recipe.comments = commentsOverrides.map((comment) =>
|
||||
createMockRecipeComment({
|
||||
recipe_id: recipeId,
|
||||
...comment,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (ingredientsOverrides) {
|
||||
recipe.ingredients = ingredientsOverrides.map((ingredient) =>
|
||||
createMockRecipeIngredient({
|
||||
recipe_id: recipeId,
|
||||
...ingredient,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return recipe;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a mock RecipeIngredient object for use in tests.
|
||||
* @param overrides - An object containing properties to override the default mock values.
|
||||
* Can optionally include a `master_item` to link IDs.
|
||||
* @returns A complete and type-safe RecipeIngredient object.
|
||||
*/
|
||||
export const createMockRecipeIngredient = (overrides: Partial<RecipeIngredient> & { master_item?: Partial<MasterGroceryItem> } = {}): RecipeIngredient => {
|
||||
const recipeIngredientId = overrides.recipe_ingredient_id ?? getNextId();
|
||||
const masterItemId = overrides.master_item_id ?? overrides.master_item?.master_grocery_item_id ?? getNextId();
|
||||
|
||||
const defaultIngredient: RecipeIngredient = {
|
||||
recipe_ingredient_id: recipeIngredientId,
|
||||
recipe_id: getNextId(),
|
||||
master_item_id: masterItemId,
|
||||
quantity: 1,
|
||||
unit: 'cup',
|
||||
};
|
||||
|
||||
const { master_item: _, ...itemOverrides } = overrides;
|
||||
|
||||
return { ...defaultIngredient, ...itemOverrides };
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -161,9 +344,9 @@ export const createMockRecipe = (overrides: Partial<Recipe> = {}): Recipe => {
|
||||
*/
|
||||
export const createMockRecipeComment = (overrides: Partial<RecipeComment> = {}): RecipeComment => {
|
||||
const defaultComment: RecipeComment = {
|
||||
recipe_comment_id: Math.floor(Math.random() * 10000),
|
||||
recipe_id: Math.floor(Math.random() * 1000),
|
||||
user_id: `user-${Math.random().toString(36).substring(2, 9)}`,
|
||||
recipe_comment_id: getNextId(),
|
||||
recipe_id: getNextId(),
|
||||
user_id: `user-${getNextId()}`,
|
||||
content: 'This is a mock comment.',
|
||||
status: 'visible',
|
||||
created_at: new Date().toISOString(),
|
||||
@@ -174,6 +357,56 @@ export const createMockRecipeComment = (overrides: Partial<RecipeComment> = {}):
|
||||
return { ...defaultComment, ...overrides };
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a mock PlannedMeal object for use in tests.
|
||||
* @param overrides - An object containing properties to override the default mock values.
|
||||
* @returns A complete and type-safe PlannedMeal object.
|
||||
*/
|
||||
export const createMockPlannedMeal = (overrides: Partial<PlannedMeal> = {}): PlannedMeal => {
|
||||
const defaultMeal: PlannedMeal = {
|
||||
planned_meal_id: getNextId(),
|
||||
menu_plan_id: getNextId(),
|
||||
recipe_id: getNextId(),
|
||||
plan_date: new Date().toISOString().split('T')[0],
|
||||
meal_type: 'dinner',
|
||||
servings_to_cook: 4,
|
||||
};
|
||||
|
||||
return { ...defaultMeal, ...overrides };
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a mock MenuPlan object for use in tests.
|
||||
* @param overrides - An object containing properties to override the default mock values.
|
||||
* @returns A complete and type-safe MenuPlan object.
|
||||
*/
|
||||
export const createMockMenuPlan = (overrides: Omit<Partial<MenuPlan>, 'planned_meals'> & { planned_meals?: Partial<PlannedMeal>[] } = {}): MenuPlan => {
|
||||
const menuPlanId = overrides.menu_plan_id ?? getNextId();
|
||||
|
||||
const defaultPlan: MenuPlan = {
|
||||
menu_plan_id: menuPlanId,
|
||||
user_id: `user-${getNextId()}`,
|
||||
name: 'Weekly Plan',
|
||||
start_date: new Date().toISOString().split('T')[0],
|
||||
end_date: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0],
|
||||
created_at: new Date().toISOString(),
|
||||
};
|
||||
|
||||
const { planned_meals: mealsOverrides, ...planOverrides } = overrides;
|
||||
const menuPlan = { ...defaultPlan, ...planOverrides };
|
||||
|
||||
if (mealsOverrides) {
|
||||
menuPlan.planned_meals = mealsOverrides.map((meal) =>
|
||||
createMockPlannedMeal({
|
||||
menu_plan_id: menuPlanId,
|
||||
...meal,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return menuPlan;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a mock ActivityLogItem object for use in tests.
|
||||
* This factory handles the discriminated union nature of the ActivityLogItem type.
|
||||
@@ -188,9 +421,10 @@ export const createMockActivityLogItem = (overrides: Partial<ActivityLogItem> =
|
||||
const action = overrides.action ?? 'flyer_processed';
|
||||
|
||||
const baseLog = {
|
||||
activity_log_id: Math.floor(Math.random() * 10000),
|
||||
user_id: `user-${Math.random().toString(36).substring(2, 9)}`,
|
||||
activity_log_id: getNextId(),
|
||||
user_id: `user-${getNextId()}`,
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
};
|
||||
|
||||
let specificLog: ActivityLogItem;
|
||||
@@ -248,11 +482,12 @@ export const createMockActivityLogItem = (overrides: Partial<ActivityLogItem> =
|
||||
*/
|
||||
export const createMockAchievement = (overrides: Partial<Achievement> = {}): Achievement => {
|
||||
const defaultAchievement: Achievement = {
|
||||
achievement_id: Math.floor(Math.random() * 100),
|
||||
achievement_id: getNextId(),
|
||||
name: 'Mock Achievement',
|
||||
description: 'A great accomplishment.',
|
||||
icon: 'star',
|
||||
points_value: 10,
|
||||
created_at: new Date().toISOString(),
|
||||
};
|
||||
return { ...defaultAchievement, ...overrides };
|
||||
};
|
||||
@@ -263,9 +498,9 @@ export const createMockAchievement = (overrides: Partial<Achievement> = {}): Ach
|
||||
* @returns A complete and type-safe object representing the joined achievement data.
|
||||
*/
|
||||
export const createMockUserAchievement = (overrides: Partial<UserAchievement & Achievement> = {}): UserAchievement & Achievement => {
|
||||
const achievementId = overrides.achievement_id ?? Math.floor(Math.random() * 100);
|
||||
const achievementId = overrides.achievement_id ?? getNextId();
|
||||
const defaultUserAchievement: UserAchievement & Achievement = {
|
||||
user_id: `user-${Math.random().toString(36).substring(2, 9)}`,
|
||||
user_id: `user-${getNextId()}`,
|
||||
achievement_id: achievementId,
|
||||
achieved_at: new Date().toISOString(),
|
||||
// from Achievement
|
||||
@@ -273,6 +508,7 @@ export const createMockUserAchievement = (overrides: Partial<UserAchievement & A
|
||||
description: 'An achievement someone earned.',
|
||||
icon: 'award',
|
||||
points_value: 20,
|
||||
created_at: new Date().toISOString(),
|
||||
};
|
||||
return { ...defaultUserAchievement, ...overrides };
|
||||
};
|
||||
@@ -284,12 +520,14 @@ export const createMockUserAchievement = (overrides: Partial<UserAchievement & A
|
||||
*/
|
||||
export const createMockBudget = (overrides: Partial<Budget> = {}): Budget => {
|
||||
const defaultBudget: Budget = {
|
||||
budget_id: Math.floor(Math.random() * 100),
|
||||
user_id: `user-${Math.random().toString(36).substring(2, 9)}`,
|
||||
budget_id: getNextId(),
|
||||
user_id: `user-${getNextId()}`,
|
||||
name: 'Monthly Groceries',
|
||||
amount_cents: 50000,
|
||||
period: 'monthly',
|
||||
start_date: new Date().toISOString().split('T')[0],
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
};
|
||||
return { ...defaultBudget, ...overrides };
|
||||
};
|
||||
@@ -301,9 +539,9 @@ export const createMockBudget = (overrides: Partial<Budget> = {}): Budget => {
|
||||
*/
|
||||
export const createMockSpendingByCategory = (overrides: Partial<SpendingByCategory> = {}): SpendingByCategory => {
|
||||
const defaultSpending: SpendingByCategory = {
|
||||
category_id: Math.floor(Math.random() * 20) + 1,
|
||||
category_id: getNextId(),
|
||||
category_name: 'Produce',
|
||||
total_spent_cents: Math.floor(Math.random() * 20000) + 1000,
|
||||
total_spent_cents: 15000,
|
||||
};
|
||||
return { ...defaultSpending, ...overrides };
|
||||
};
|
||||
@@ -313,16 +551,55 @@ export const createMockSpendingByCategory = (overrides: Partial<SpendingByCatego
|
||||
* @param overrides - An object containing properties to override the default mock values.
|
||||
* @returns A complete and type-safe MasterGroceryItem object.
|
||||
*/
|
||||
export const createMockMasterGroceryItem = (overrides: Partial<MasterGroceryItem> = {}): MasterGroceryItem => {
|
||||
export const createMockMasterGroceryItem = (overrides: Partial<MasterGroceryItem> & { category?: Partial<Category> } = {}): MasterGroceryItem => {
|
||||
// Ensure category_id is consistent between the item and the nested category object
|
||||
const categoryOverrides = overrides.category || {};
|
||||
if (overrides.category_id && !categoryOverrides.category_id) {
|
||||
categoryOverrides.category_id = overrides.category_id;
|
||||
}
|
||||
|
||||
const category = createMockCategory(categoryOverrides);
|
||||
|
||||
const defaultItem: MasterGroceryItem = {
|
||||
master_grocery_item_id: Math.floor(Math.random() * 10000),
|
||||
master_grocery_item_id: getNextId(),
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
name: 'Mock Master Item',
|
||||
category_id: 1,
|
||||
category_name: 'Pantry & Dry Goods',
|
||||
category_id: category.category_id,
|
||||
category_name: category.name,
|
||||
is_allergen: false,
|
||||
allergy_info: null,
|
||||
created_by: null,
|
||||
};
|
||||
|
||||
return { ...defaultItem, ...overrides };
|
||||
const { category: _, ...itemOverrides } = overrides;
|
||||
|
||||
return { ...defaultItem, ...itemOverrides };
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a mock PantryItem object for use in tests.
|
||||
* @param overrides - An object containing properties to override the default mock values.
|
||||
* Can optionally include a `master_item` to link IDs.
|
||||
* @returns A complete and type-safe PantryItem object.
|
||||
*/
|
||||
export const createMockPantryItem = (overrides: Partial<PantryItem> & { master_item?: Partial<MasterGroceryItem> } = {}): PantryItem => {
|
||||
const pantryItemId = overrides.pantry_item_id ?? getNextId();
|
||||
|
||||
const masterItemId = overrides.master_item_id ?? overrides.master_item?.master_grocery_item_id ?? getNextId();
|
||||
|
||||
const defaultItem: PantryItem = {
|
||||
pantry_item_id: pantryItemId,
|
||||
user_id: `user-${getNextId()}`,
|
||||
master_item_id: masterItemId,
|
||||
quantity: 1,
|
||||
unit: 'each',
|
||||
updated_at: new Date().toISOString(),
|
||||
};
|
||||
|
||||
const { master_item: _, ...itemOverrides } = overrides;
|
||||
|
||||
return { ...defaultItem, ...itemOverrides };
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -330,36 +607,173 @@ export const createMockMasterGroceryItem = (overrides: Partial<MasterGroceryItem
|
||||
* @param overrides - An object containing properties to override the default mock values.
|
||||
* @returns A complete and type-safe ShoppingList object.
|
||||
*/
|
||||
export const createMockShoppingList = (overrides: Partial<ShoppingList> = {}): ShoppingList => {
|
||||
export const createMockShoppingList = (overrides: Omit<Partial<ShoppingList>, 'items'> & { items?: (Partial<ShoppingListItem> & { master_item?: Partial<MasterGroceryItem> | null })[] } = {}): ShoppingList => {
|
||||
const shoppingListId = overrides.shopping_list_id ?? getNextId();
|
||||
|
||||
const defaultList: ShoppingList = {
|
||||
shopping_list_id: Math.floor(Math.random() * 100),
|
||||
user_id: `user-${Math.random().toString(36).substring(2, 9)}`,
|
||||
shopping_list_id: shoppingListId,
|
||||
user_id: `user-${getNextId()}`,
|
||||
name: 'My Mock List',
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
items: [],
|
||||
};
|
||||
|
||||
return { ...defaultList, ...overrides };
|
||||
if (overrides.items) {
|
||||
defaultList.items = overrides.items.map((item) =>
|
||||
createMockShoppingListItem({
|
||||
shopping_list_id: shoppingListId,
|
||||
...item,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
const { items: _, ...listOverrides } = overrides;
|
||||
|
||||
return { ...defaultList, ...listOverrides };
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a mock ShoppingListItem object for use in tests.
|
||||
* @param overrides - An object containing properties to override the default mock values.
|
||||
* Can optionally include a `master_item` to link IDs and populate joined data.
|
||||
* @returns A complete and type-safe ShoppingListItem object.
|
||||
*/
|
||||
export const createMockShoppingListItem = (overrides: Partial<ShoppingListItem> = {}): ShoppingListItem => {
|
||||
export const createMockShoppingListItem = (overrides: Partial<ShoppingListItem> & { master_item?: Partial<MasterGroceryItem> | null } = {}): ShoppingListItem => {
|
||||
const shoppingListItemId = overrides.shopping_list_item_id ?? getNextId();
|
||||
const shoppingListId = overrides.shopping_list_id ?? getNextId();
|
||||
|
||||
const masterItemId = overrides.master_item_id ?? overrides.master_item?.master_grocery_item_id;
|
||||
|
||||
const defaultItem: ShoppingListItem = {
|
||||
shopping_list_item_id: Math.floor(Math.random() * 100000),
|
||||
shopping_list_id: Math.floor(Math.random() * 100),
|
||||
shopping_list_item_id: shoppingListItemId,
|
||||
shopping_list_id: shoppingListId,
|
||||
custom_item_name: 'Mock Shopping List Item',
|
||||
quantity: 1,
|
||||
is_purchased: false,
|
||||
added_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
};
|
||||
|
||||
if (masterItemId) {
|
||||
defaultItem.master_item_id = masterItemId;
|
||||
}
|
||||
|
||||
const { master_item: masterItemOverride, ...itemOverrides } = overrides;
|
||||
const result = { ...defaultItem, ...itemOverrides };
|
||||
|
||||
if (masterItemOverride && !result.master_item && masterItemOverride.name) {
|
||||
result.master_item = { name: masterItemOverride.name };
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a mock ShoppingTripItem object for use in tests.
|
||||
* @param overrides - An object containing properties to override the default mock values.
|
||||
* @returns A complete and type-safe ShoppingTripItem object.
|
||||
*/
|
||||
export const createMockShoppingTripItem = (overrides: Partial<ShoppingTripItem> & { master_item?: Partial<MasterGroceryItem> } = {}): ShoppingTripItem => {
|
||||
const tripItemId = overrides.shopping_trip_item_id ?? getNextId();
|
||||
const masterItemId = overrides.master_item_id ?? overrides.master_item?.master_grocery_item_id;
|
||||
|
||||
const defaultItem: ShoppingTripItem = {
|
||||
shopping_trip_item_id: tripItemId,
|
||||
shopping_trip_id: getNextId(),
|
||||
master_item_id: masterItemId,
|
||||
custom_item_name: masterItemId ? null : 'Custom Trip Item',
|
||||
master_item_name: masterItemId ? (overrides.master_item?.name ?? 'Mock Master Item') : null,
|
||||
quantity: 1,
|
||||
price_paid_cents: 199,
|
||||
};
|
||||
|
||||
const { master_item: _, ...itemOverrides } = overrides;
|
||||
|
||||
return { ...defaultItem, ...itemOverrides };
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a mock ShoppingTrip object for use in tests.
|
||||
* @param overrides - An object containing properties to override the default mock values.
|
||||
* @returns A complete and type-safe ShoppingTrip object.
|
||||
*/
|
||||
export const createMockShoppingTrip = (overrides: Omit<Partial<ShoppingTrip>, 'items'> & { items?: Partial<ShoppingTripItem>[] } = {}): ShoppingTrip => {
|
||||
const tripId = overrides.shopping_trip_id ?? getNextId();
|
||||
|
||||
const defaultTrip: ShoppingTrip = {
|
||||
shopping_trip_id: tripId,
|
||||
user_id: `user-${getNextId()}`,
|
||||
shopping_list_id: null,
|
||||
completed_at: new Date().toISOString(),
|
||||
total_spent_cents: 0,
|
||||
items: [],
|
||||
};
|
||||
|
||||
const { items: itemsOverrides, ...tripOverrides } = overrides;
|
||||
const trip = { ...defaultTrip, ...tripOverrides };
|
||||
|
||||
if (itemsOverrides) {
|
||||
trip.items = itemsOverrides.map((item) => createMockShoppingTripItem({ shopping_trip_id: tripId, ...item }));
|
||||
if (overrides.total_spent_cents === undefined) {
|
||||
trip.total_spent_cents = trip.items.reduce((total, item) => total + (item.price_paid_cents ?? 0), 0);
|
||||
}
|
||||
}
|
||||
|
||||
return trip;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a mock ReceiptItem object for use in tests.
|
||||
* @param overrides - An object containing properties to override the default mock values.
|
||||
* @returns A complete and type-safe ReceiptItem object.
|
||||
*/
|
||||
export const createMockReceiptItem = (overrides: Partial<ReceiptItem> = {}): ReceiptItem => {
|
||||
const defaultItem: ReceiptItem = {
|
||||
receipt_item_id: getNextId(),
|
||||
receipt_id: getNextId(),
|
||||
raw_item_description: 'Mock Receipt Item',
|
||||
quantity: 1,
|
||||
price_paid_cents: 199,
|
||||
master_item_id: null,
|
||||
product_id: null,
|
||||
status: 'unmatched',
|
||||
};
|
||||
|
||||
return { ...defaultItem, ...overrides };
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a mock Receipt object for use in tests.
|
||||
* @param overrides - An object containing properties to override the default mock values.
|
||||
* @returns A complete and type-safe Receipt object.
|
||||
*/
|
||||
export const createMockReceipt = (overrides: Omit<Partial<Receipt>, 'items'> & { items?: Partial<ReceiptItem>[] } = {}): Receipt => {
|
||||
const receiptId = overrides.receipt_id ?? getNextId();
|
||||
|
||||
const defaultReceipt: Receipt = {
|
||||
receipt_id: receiptId,
|
||||
user_id: `user-${getNextId()}`,
|
||||
store_id: null,
|
||||
receipt_image_url: `/receipts/mock-receipt-${receiptId}.jpg`,
|
||||
transaction_date: new Date().toISOString(),
|
||||
total_amount_cents: null,
|
||||
status: 'pending',
|
||||
raw_text: null,
|
||||
created_at: new Date().toISOString(),
|
||||
processed_at: null,
|
||||
};
|
||||
|
||||
const { items: itemsOverrides, ...receiptOverrides } = overrides;
|
||||
const receipt = { ...defaultReceipt, ...receiptOverrides };
|
||||
|
||||
if (itemsOverrides) {
|
||||
receipt.items = itemsOverrides.map((item) => createMockReceiptItem({ receipt_id: receiptId, ...item }));
|
||||
}
|
||||
|
||||
return receipt;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a mock DietaryRestriction object for testing.
|
||||
* @param overrides - Optional properties to override the defaults.
|
||||
@@ -374,6 +788,46 @@ export const createMockDietaryRestriction = (overrides: Partial<DietaryRestricti
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a mock UserDietaryRestriction object for use in tests.
|
||||
* @param overrides - An object containing properties to override the default mock values.
|
||||
* Can optionally include `user` and `restriction` objects to link IDs.
|
||||
* @returns A complete and type-safe UserDietaryRestriction object.
|
||||
*/
|
||||
export const createMockUserDietaryRestriction = (
|
||||
overrides: Partial<UserDietaryRestriction> & { user?: Partial<User>; restriction?: Partial<DietaryRestriction> } = {}
|
||||
): UserDietaryRestriction => {
|
||||
const userId = overrides.user_id ?? overrides.user?.user_id ?? `user-${getNextId()}`;
|
||||
const restrictionId = overrides.restriction_id ?? overrides.restriction?.dietary_restriction_id ?? getNextId();
|
||||
|
||||
const defaultUserRestriction: UserDietaryRestriction = {
|
||||
user_id: userId,
|
||||
restriction_id: restrictionId,
|
||||
};
|
||||
|
||||
return { ...defaultUserRestriction, ...overrides };
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a mock UserAppliance object for use in tests.
|
||||
* @param overrides - An object containing properties to override the default mock values.
|
||||
* Can optionally include `user` and `appliance` objects to link IDs.
|
||||
* @returns A complete and type-safe UserAppliance object.
|
||||
*/
|
||||
export const createMockUserAppliance = (
|
||||
overrides: Partial<UserAppliance> & { user?: Partial<User>; appliance?: Partial<Appliance> } = {}
|
||||
): UserAppliance => {
|
||||
const userId = overrides.user_id ?? overrides.user?.user_id ?? `user-${getNextId()}`;
|
||||
const applianceId = overrides.appliance_id ?? overrides.appliance?.appliance_id ?? getNextId();
|
||||
|
||||
const defaultUserAppliance: UserAppliance = {
|
||||
user_id: userId,
|
||||
appliance_id: applianceId,
|
||||
};
|
||||
|
||||
return { ...defaultUserAppliance, ...overrides };
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a mock Address object for use in tests.
|
||||
* @param overrides - An object containing properties to override the default mock values.
|
||||
@@ -381,7 +835,7 @@ export const createMockDietaryRestriction = (overrides: Partial<DietaryRestricti
|
||||
*/
|
||||
export const createMockAddress = (overrides: Partial<Address> = {}): Address => {
|
||||
const defaultAddress: Address = {
|
||||
address_id: Math.floor(Math.random() * 1000),
|
||||
address_id: getNextId(),
|
||||
address_line_1: '123 Mock St',
|
||||
city: 'Mockville',
|
||||
province_state: 'BC',
|
||||
@@ -405,7 +859,7 @@ export const createMockAddress = (overrides: Partial<Address> = {}): Address =>
|
||||
* @returns A complete and type-safe UserWithPasswordHash object.
|
||||
*/
|
||||
export const createMockUserWithPasswordHash = (overrides: Partial<UserWithPasswordHash> = {}): UserWithPasswordHash => {
|
||||
const userId = overrides.user_id ?? `user-${Math.random().toString(36).substring(2, 9)}`;
|
||||
const userId = overrides.user_id ?? `user-${getNextId()}`;
|
||||
|
||||
const defaultUser: UserWithPasswordHash = {
|
||||
user_id: userId,
|
||||
@@ -413,6 +867,9 @@ export const createMockUserWithPasswordHash = (overrides: Partial<UserWithPasswo
|
||||
password_hash: 'hashed_password',
|
||||
failed_login_attempts: 0,
|
||||
last_failed_login: null,
|
||||
last_login_ip: null,
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
};
|
||||
|
||||
return { ...defaultUser, ...overrides };
|
||||
@@ -424,10 +881,11 @@ export const createMockUserWithPasswordHash = (overrides: Partial<UserWithPasswo
|
||||
* @returns A complete and type-safe Profile object.
|
||||
*/
|
||||
export const createMockProfile = (overrides: Partial<Profile> = {}): Profile => {
|
||||
const userId = overrides.user_id ?? `user-${Math.random().toString(36).substring(2, 9)}`;
|
||||
const userId = overrides.user_id ?? `user-${getNextId()}`;
|
||||
|
||||
const defaultProfile: Profile = {
|
||||
user_id: userId,
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
full_name: 'Mock Profile User',
|
||||
avatar_url: null,
|
||||
@@ -435,6 +893,8 @@ export const createMockProfile = (overrides: Partial<Profile> = {}): Profile =>
|
||||
points: 0,
|
||||
role: 'user',
|
||||
preferences: {},
|
||||
created_by: null,
|
||||
updated_by: null,
|
||||
};
|
||||
|
||||
return { ...defaultProfile, ...overrides };
|
||||
@@ -447,11 +907,11 @@ export const createMockProfile = (overrides: Partial<Profile> = {}): Profile =>
|
||||
*/
|
||||
export const createMockWatchedItemDeal = (overrides: Partial<WatchedItemDeal> = {}): WatchedItemDeal => {
|
||||
const defaultDeal: WatchedItemDeal = {
|
||||
master_item_id: Math.floor(Math.random() * 1000),
|
||||
master_item_id: getNextId(),
|
||||
item_name: 'Mock Deal Item',
|
||||
best_price_in_cents: Math.floor(Math.random() * 1000) + 100,
|
||||
best_price_in_cents: 599,
|
||||
store_name: 'Mock Store',
|
||||
flyer_id: Math.floor(Math.random() * 100),
|
||||
flyer_id: getNextId(),
|
||||
valid_to: new Date(Date.now() + 5 * 24 * 60 * 60 * 1000).toISOString(), // 5 days from now
|
||||
};
|
||||
|
||||
@@ -464,14 +924,14 @@ export const createMockWatchedItemDeal = (overrides: Partial<WatchedItemDeal> =
|
||||
* @returns A complete and type-safe LeaderboardUser object.
|
||||
*/
|
||||
export const createMockLeaderboardUser = (overrides: Partial<LeaderboardUser> = {}): LeaderboardUser => {
|
||||
const userId = overrides.user_id ?? `user-${Math.random().toString(36).substring(2, 9)}`;
|
||||
const userId = overrides.user_id ?? `user-${getNextId()}`;
|
||||
|
||||
const defaultUser: LeaderboardUser = {
|
||||
user_id: userId,
|
||||
full_name: 'Leaderboard User',
|
||||
avatar_url: null,
|
||||
points: Math.floor(Math.random() * 1000),
|
||||
rank: String(Math.floor(Math.random() * 100) + 1),
|
||||
points: 500,
|
||||
rank: '10',
|
||||
};
|
||||
|
||||
return { ...defaultUser, ...overrides };
|
||||
@@ -484,13 +944,15 @@ export const createMockLeaderboardUser = (overrides: Partial<LeaderboardUser> =
|
||||
*/
|
||||
export const createMockUnmatchedFlyerItem = (overrides: Partial<UnmatchedFlyerItem> = {}): UnmatchedFlyerItem => {
|
||||
const defaultItem: UnmatchedFlyerItem = {
|
||||
unmatched_flyer_item_id: Math.floor(Math.random() * 1000),
|
||||
unmatched_flyer_item_id: getNextId(),
|
||||
status: 'pending',
|
||||
created_at: new Date().toISOString(),
|
||||
flyer_item_id: Math.floor(Math.random() * 10000),
|
||||
updated_at: new Date().toISOString(),
|
||||
reviewed_at: null,
|
||||
flyer_item_id: getNextId(),
|
||||
flyer_item_name: 'Mystery Product',
|
||||
price_display: '$?.??',
|
||||
flyer_id: Math.floor(Math.random() * 100),
|
||||
flyer_id: getNextId(),
|
||||
store_name: 'Random Store',
|
||||
};
|
||||
|
||||
@@ -503,7 +965,7 @@ export const createMockUnmatchedFlyerItem = (overrides: Partial<UnmatchedFlyerIt
|
||||
* @returns A complete and type-safe AdminUserView object.
|
||||
*/
|
||||
export const createMockAdminUserView = (overrides: Partial<AdminUserView> = {}): AdminUserView => {
|
||||
const userId = overrides.user_id ?? `user-${Math.random().toString(36).substring(2, 9)}`;
|
||||
const userId = overrides.user_id ?? `user-${getNextId()}`;
|
||||
|
||||
const defaultUserView: AdminUserView = {
|
||||
user_id: userId,
|
||||
@@ -524,12 +986,13 @@ export const createMockAdminUserView = (overrides: Partial<AdminUserView> = {}):
|
||||
*/
|
||||
export const createMockNotification = (overrides: Partial<Notification> = {}): Notification => {
|
||||
const defaultNotification: Notification = {
|
||||
notification_id: Math.floor(Math.random() * 1000),
|
||||
user_id: `user-${Math.random().toString(36).substring(2, 9)}`,
|
||||
notification_id: getNextId(),
|
||||
user_id: `user-${getNextId()}`,
|
||||
content: 'This is a mock notification.',
|
||||
link_url: null,
|
||||
is_read: false,
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
};
|
||||
|
||||
return { ...defaultNotification, ...overrides };
|
||||
|
||||
Reference in New Issue
Block a user