Files
flyer-crawler.projectium.com/src/tests/utils/mockFactories.ts
Torben Sorensen e62739810e
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 57m53s
moar fixes + unit test review of routes
2025-12-19 14:20:22 -08:00

544 lines
20 KiB
TypeScript

// 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';
/**
* Creates a mock UserProfile object for use in tests, ensuring type safety.
*
* @param overrides - An object containing properties to override the default mock values.
* This allows for easy customization of the mock user for specific test cases.
* For example: `createMockUserProfile({ role: 'admin', points: 500 })`
* @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)}`;
const defaultProfile: UserProfile = {
user_id: userId,
role: 'user',
points: 0,
full_name: 'Test User',
avatar_url: null,
preferences: {},
address: null,
user: {
user_id: userId,
email: `${userId}@example.com`,
...overrides.user, // Apply nested user overrides
},
};
return { ...defaultProfile, ...overrides };
};
/**
* Creates a mock Flyer object for use in tests, ensuring type safety.
*
* @param overrides - An object containing properties to override the default mock values,
* including nested properties for the `store`.
* 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);
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,
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,
uploaded_by: null,
store: {
store_id: storeId,
created_at: new Date().toISOString(),
name: 'Mock Store',
logo_url: null,
},
};
// Deep merge the store object and then merge the top-level properties.
return { ...defaultFlyer, ...overrides, store: { ...defaultFlyer.store, ...overrides.store } as Store };
};
/**
* Creates a mock SuggestedCorrection object for use in tests.
* @param overrides - An object containing properties to override the default mock values.
* @returns A complete and type-safe SuggestedCorrection object.
*/
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)}`,
correction_type: 'price',
suggested_value: '$9.99',
status: 'pending',
created_at: new Date().toISOString(),
};
return { ...defaultCorrection, ...overrides };
};
/**
* Creates a mock Brand object for use in tests.
* @param overrides - An object containing properties to override the default mock values.
* @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 defaultBrand: Brand = {
brand_id: brandId,
name: `Brand ${brandId}`,
logo_url: null,
store_id: null,
store_name: null,
};
return { ...defaultBrand, ...overrides };
};
/**
* 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 => {
const defaultItem: FlyerItem = {
flyer_item_id: Math.floor(Math.random() * 10000),
flyer_id: Math.floor(Math.random() * 1000),
created_at: new Date().toISOString(),
item: 'Mock Item',
price_display: '$1.99',
price_in_cents: 199,
quantity: 'each',
view_count: 0,
click_count: 0,
updated_at: new Date().toISOString(),
};
return { ...defaultItem, ...overrides };
};
/**
* Creates a mock Recipe object for use in tests.
* @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);
const defaultRecipe: Recipe = {
recipe_id: recipeId,
user_id: `user-${Math.random().toString(36).substring(2, 9)}`,
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),
status: 'public',
created_at: new Date().toISOString(),
prep_time_minutes: 15,
cook_time_minutes: 30,
servings: 4,
};
return { ...defaultRecipe, ...overrides };
};
/**
* Creates a mock RecipeComment object for use in tests.
* @param overrides - An object containing properties to override the default mock values.
* @returns A complete and type-safe RecipeComment object.
*/
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)}`,
content: 'This is a mock comment.',
status: 'visible',
created_at: new Date().toISOString(),
user_full_name: 'Mock User', // This was correct
user_avatar_url: undefined,
};
return { ...defaultComment, ...overrides };
};
/**
* Creates a mock ActivityLogItem object for use in tests.
* This factory handles the discriminated union nature of the ActivityLogItem type.
* By default, it creates a 'flyer_processed' log item. You can override the 'action'
* and 'details' to create other types of log items.
*
* @param overrides - An object containing properties to override the default mock values.
* e.g., `createMockActivityLogItem({ action: 'user_registered', details: { full_name: 'New User' } })`
* @returns A complete and type-safe ActivityLogItem object.
*/
export const createMockActivityLogItem = (overrides: Partial<ActivityLogItem> = {}): 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)}`,
created_at: new Date().toISOString(),
};
let specificLog: ActivityLogItem;
// Create a default log based on the action, which can then be overridden.
switch (action) {
case 'recipe_created':
specificLog = {
...baseLog,
action: 'recipe_created',
display_text: 'Created a new recipe: Mock Recipe.',
icon: 'chef-hat',
details: { recipe_id: 1, recipe_name: 'Mock Recipe' },
};
break;
case 'user_registered':
specificLog = {
...baseLog,
action: 'user_registered',
display_text: 'A new user has registered.',
icon: 'user-plus',
details: { full_name: 'New Mock User' },
};
break;
case 'list_shared':
specificLog = {
...baseLog,
action: 'list_shared',
display_text: 'A shopping list was shared.',
icon: 'share-2',
details: { list_name: 'Mock List', shopping_list_id: 1, shared_with_name: 'Another User' },
};
break;
case 'flyer_processed':
default:
specificLog = {
...baseLog,
action: 'flyer_processed',
display_text: 'Processed a new flyer for Mock Store.',
icon: 'file-check',
details: { flyer_id: 1, store_name: 'Mock Store' },
};
break;
}
// Merge the generated log with any specific overrides provided.
// This allows for deep merging of the 'details' object.
return { ...specificLog, ...overrides, details: { ...specificLog.details, ...overrides.details } } as ActivityLogItem;
};
/**
* Creates a mock Achievement object for use in tests.
* @param overrides - An object containing properties to override the default mock values.
* @returns A complete and type-safe Achievement object.
*/
export const createMockAchievement = (overrides: Partial<Achievement> = {}): Achievement => {
const defaultAchievement: Achievement = {
achievement_id: Math.floor(Math.random() * 100),
name: 'Mock Achievement',
description: 'A great accomplishment.',
icon: 'star',
points_value: 10,
};
return { ...defaultAchievement, ...overrides };
};
/**
* Creates a mock object representing a joined UserAchievement and Achievement for use in tests.
* @param overrides - An object containing properties to override the default mock values.
* @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 defaultUserAchievement: UserAchievement & Achievement = {
user_id: `user-${Math.random().toString(36).substring(2, 9)}`,
achievement_id: achievementId,
achieved_at: new Date().toISOString(),
// from Achievement
name: 'Mock User Achievement',
description: 'An achievement someone earned.',
icon: 'award',
points_value: 20,
};
return { ...defaultUserAchievement, ...overrides };
};
/**
* Creates a mock Budget object for use in tests.
* @param overrides - An object containing properties to override the default mock values.
* @returns A complete and type-safe Budget object.
*/
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)}`,
name: 'Monthly Groceries',
amount_cents: 50000,
period: 'monthly',
start_date: new Date().toISOString().split('T')[0],
};
return { ...defaultBudget, ...overrides };
};
/**
* Creates a mock SpendingByCategory object for use in tests.
* @param overrides - An object containing properties to override the default mock values.
* @returns A complete and type-safe SpendingByCategory object.
*/
export const createMockSpendingByCategory = (overrides: Partial<SpendingByCategory> = {}): SpendingByCategory => {
const defaultSpending: SpendingByCategory = {
category_id: Math.floor(Math.random() * 20) + 1,
category_name: 'Produce',
total_spent_cents: Math.floor(Math.random() * 20000) + 1000,
};
return { ...defaultSpending, ...overrides };
};
/**
* Creates a mock MasterGroceryItem object for use in tests.
* @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 => {
const defaultItem: MasterGroceryItem = {
master_grocery_item_id: Math.floor(Math.random() * 10000),
created_at: new Date().toISOString(),
name: 'Mock Master Item',
category_id: 1,
category_name: 'Pantry & Dry Goods',
};
return { ...defaultItem, ...overrides };
};
/**
* Creates a mock ShoppingList object for use in tests.
* @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 => {
const defaultList: ShoppingList = {
shopping_list_id: Math.floor(Math.random() * 100),
user_id: `user-${Math.random().toString(36).substring(2, 9)}`,
name: 'My Mock List',
created_at: new Date().toISOString(),
items: [],
};
return { ...defaultList, ...overrides };
};
/**
* Creates a mock ShoppingListItem object for use in tests.
* @param overrides - An object containing properties to override the default mock values.
* @returns A complete and type-safe ShoppingListItem object.
*/
export const createMockShoppingListItem = (overrides: Partial<ShoppingListItem> = {}): ShoppingListItem => {
const defaultItem: ShoppingListItem = {
shopping_list_item_id: Math.floor(Math.random() * 100000),
shopping_list_id: Math.floor(Math.random() * 100),
custom_item_name: 'Mock Shopping List Item',
quantity: 1,
is_purchased: false,
added_at: new Date().toISOString(),
};
return { ...defaultItem, ...overrides };
};
/**
* Creates a mock DietaryRestriction object for testing.
* @param overrides - Optional properties to override the defaults.
* @returns A mock DietaryRestriction object.
*/
export const createMockDietaryRestriction = (overrides: Partial<DietaryRestriction> = {}): DietaryRestriction => {
return {
dietary_restriction_id: 1,
name: 'Vegetarian',
type: 'diet',
...overrides,
};
};
/**
* Creates a mock Address object for use in tests.
* @param overrides - An object containing properties to override the default mock values.
* @returns A complete and type-safe Address object.
*/
export const createMockAddress = (overrides: Partial<Address> = {}): Address => {
const defaultAddress: Address = {
address_id: Math.floor(Math.random() * 1000),
address_line_1: '123 Mock St',
city: 'Mockville',
province_state: 'BC',
postal_code: 'V8T 1A1',
country: 'CA',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
// Optional fields
address_line_2: null,
latitude: null,
longitude: null,
location: null,
};
return { ...defaultAddress, ...overrides };
};
/**
* Creates a mock UserWithPasswordHash object for use in tests.
* @param overrides - An object containing properties to override the default mock values.
* @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 defaultUser: UserWithPasswordHash = {
user_id: userId,
email: `${userId}@example.com`,
password_hash: 'hashed_password',
failed_login_attempts: 0,
last_failed_login: null,
};
return { ...defaultUser, ...overrides };
};
/**
* Creates a mock Profile object for use in tests.
* @param overrides - An object containing properties to override the default mock values.
* @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 defaultProfile: Profile = {
user_id: userId,
updated_at: new Date().toISOString(),
full_name: 'Mock Profile User',
avatar_url: null,
address_id: null,
points: 0,
role: 'user',
preferences: {},
};
return { ...defaultProfile, ...overrides };
};
/**
* Creates a mock WatchedItemDeal object for use in tests.
* @param overrides - An object containing properties to override the default mock values.
* @returns A complete and type-safe WatchedItemDeal object.
*/
export const createMockWatchedItemDeal = (overrides: Partial<WatchedItemDeal> = {}): WatchedItemDeal => {
const defaultDeal: WatchedItemDeal = {
master_item_id: Math.floor(Math.random() * 1000),
item_name: 'Mock Deal Item',
best_price_in_cents: Math.floor(Math.random() * 1000) + 100,
store_name: 'Mock Store',
flyer_id: Math.floor(Math.random() * 100),
valid_to: new Date(Date.now() + 5 * 24 * 60 * 60 * 1000).toISOString(), // 5 days from now
};
return { ...defaultDeal, ...overrides };
};
/**
* Creates a mock LeaderboardUser object for use in tests.
* @param overrides - An object containing properties to override the default mock values.
* @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 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),
};
return { ...defaultUser, ...overrides };
};
/**
* Creates a mock UnmatchedFlyerItem object for use in tests.
* @param overrides - An object containing properties to override the default mock values.
* @returns A complete and type-safe UnmatchedFlyerItem object.
*/
export const createMockUnmatchedFlyerItem = (overrides: Partial<UnmatchedFlyerItem> = {}): UnmatchedFlyerItem => {
const defaultItem: UnmatchedFlyerItem = {
unmatched_flyer_item_id: Math.floor(Math.random() * 1000),
status: 'pending',
created_at: new Date().toISOString(),
flyer_item_id: Math.floor(Math.random() * 10000),
flyer_item_name: 'Mystery Product',
price_display: '$?.??',
flyer_id: Math.floor(Math.random() * 100),
store_name: 'Random Store',
};
return { ...defaultItem, ...overrides };
};
/**
* Creates a mock AdminUserView object for use in tests.
* @param overrides - An object containing properties to override the default mock values.
* @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 defaultUserView: AdminUserView = {
user_id: userId,
email: `${userId}@example.com`,
created_at: new Date().toISOString(),
role: 'user',
full_name: 'Mock User',
avatar_url: null,
};
return { ...defaultUserView, ...overrides };
};
/**
* Creates a mock Notification object for use in tests.
* @param overrides - An object containing properties to override the default mock values.
* @returns A complete and type-safe Notification object.
*/
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)}`,
content: 'This is a mock notification.',
link_url: null,
is_read: false,
created_at: new Date().toISOString(),
};
return { ...defaultNotification, ...overrides };
};
export const createMockAppliance = (overrides: Partial<Appliance> = {}): Appliance => {
return {
appliance_id: 1,
name: 'Oven',
...overrides,
};
};