massive fixes to stores and addresses
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 18m46s

This commit is contained in:
2026-01-19 00:34:11 -08:00
parent d2efca8339
commit 795b3d0b28
9 changed files with 60 additions and 53 deletions

View File

@@ -102,7 +102,11 @@ export class AddressRepository {
* @param limit Maximum number of results (default: 10) * @param limit Maximum number of results (default: 10)
* @returns Array of matching Address objects * @returns Array of matching Address objects
*/ */
async searchAddressesByText(query: string, logger: Logger, limit: number = 10): Promise<Address[]> { async searchAddressesByText(
query: string,
logger: Logger,
limit: number = 10,
): Promise<Address[]> {
try { try {
const sql = ` const sql = `
SELECT * FROM public.addresses SELECT * FROM public.addresses

View File

@@ -21,13 +21,13 @@ describe('Deals DB Service', () => {
// Import the Pool type to use for casting the mock instance. // Import the Pool type to use for casting the mock instance.
let dealsRepo: DealsRepository; let dealsRepo: DealsRepository;
const mockDb = { const mockDb = {
query: vi.fn() query: vi.fn(),
}; };
beforeEach(() => { beforeEach(() => {
vi.clearAllMocks(); vi.clearAllMocks();
mockDb.query.mockReset() mockDb.query.mockReset();
// Instantiate the repository with the minimal mock db for each test // Instantiate the repository with the minimal mock db for each test
dealsRepo = new DealsRepository(mockDb); dealsRepo = new DealsRepository(mockDb);
@@ -71,10 +71,9 @@ describe('Deals DB Service', () => {
// Assert // Assert
expect(result).toEqual(mockDeals); expect(result).toEqual(mockDeals);
expect(mockDb.query).toHaveBeenCalledWith( expect(mockDb.query).toHaveBeenCalledWith(expect.stringContaining('FROM flyer_items fi'), [
expect.stringContaining('FROM flyer_items fi'), 'user-123',
['user-123'], ]);
);
expect(mockLogger.debug).toHaveBeenCalledWith( expect(mockLogger.debug).toHaveBeenCalledWith(
{ userId: 'user-123' }, { userId: 'user-123' },
'Finding best prices for watched items.', 'Finding best prices for watched items.',

View File

@@ -45,9 +45,7 @@ describe('StoreRepository', () => {
expect(storeId).toBeGreaterThan(0); expect(storeId).toBeGreaterThan(0);
// Verify it was created // Verify it was created
const result = await pool.query('SELECT * FROM public.stores WHERE store_id = $1', [ const result = await pool.query('SELECT * FROM public.stores WHERE store_id = $1', [storeId]);
storeId,
]);
expect(result.rows).toHaveLength(1); expect(result.rows).toHaveLength(1);
expect(result.rows[0].name).toBe('Test Store'); expect(result.rows[0].name).toBe('Test Store');
}); });
@@ -60,9 +58,7 @@ describe('StoreRepository', () => {
); );
createdStoreIds.push(storeId); createdStoreIds.push(storeId);
const result = await pool.query('SELECT * FROM public.stores WHERE store_id = $1', [ const result = await pool.query('SELECT * FROM public.stores WHERE store_id = $1', [storeId]);
storeId,
]);
expect(result.rows[0].logo_url).toBe('https://example.com/logo.png'); expect(result.rows[0].logo_url).toBe('https://example.com/logo.png');
}); });
@@ -79,9 +75,7 @@ describe('StoreRepository', () => {
const storeId = await repo.createStore('User Store', logger, null, userId); const storeId = await repo.createStore('User Store', logger, null, userId);
createdStoreIds.push(storeId); createdStoreIds.push(storeId);
const result = await pool.query('SELECT * FROM public.stores WHERE store_id = $1', [ const result = await pool.query('SELECT * FROM public.stores WHERE store_id = $1', [storeId]);
storeId,
]);
expect(result.rows[0].created_by).toBe(userId); expect(result.rows[0].created_by).toBe(userId);
// Cleanup user // Cleanup user
@@ -150,11 +144,7 @@ describe('StoreRepository', () => {
const storeId = await repo.createStore('Logo Update Test', logger); const storeId = await repo.createStore('Logo Update Test', logger);
createdStoreIds.push(storeId); createdStoreIds.push(storeId);
await repo.updateStore( await repo.updateStore(storeId, { logo_url: 'https://example.com/new-logo.png' }, logger);
storeId,
{ logo_url: 'https://example.com/new-logo.png' },
logger,
);
const store = await repo.getStoreById(storeId, logger); const store = await repo.getStoreById(storeId, logger);
expect(store.logo_url).toBe('https://example.com/new-logo.png'); expect(store.logo_url).toBe('https://example.com/new-logo.png');

View File

@@ -90,9 +90,15 @@ export class StoreRepository {
const result = await this.db.query<Store>(query); const result = await this.db.query<Store>(query);
return result.rows; return result.rows;
} catch (error) { } catch (error) {
handleDbError(error, logger, 'Database error in getAllStores', {}, { handleDbError(
defaultMessage: 'Failed to retrieve stores.', error,
}); logger,
'Database error in getAllStores',
{},
{
defaultMessage: 'Failed to retrieve stores.',
},
);
} }
} }

View File

@@ -27,11 +27,7 @@ export class StoreLocationRepository {
* @param logger Logger instance * @param logger Logger instance
* @returns The store_location_id of the created link * @returns The store_location_id of the created link
*/ */
async createStoreLocation( async createStoreLocation(storeId: number, addressId: number, logger: Logger): Promise<number> {
storeId: number,
addressId: number,
logger: Logger,
): Promise<number> {
try { try {
const query = ` const query = `
INSERT INTO public.store_locations (store_id, address_id) INSERT INTO public.store_locations (store_id, address_id)
@@ -210,9 +206,15 @@ export class StoreLocationRepository {
const result = await this.db.query<StoreWithLocations>(query); const result = await this.db.query<StoreWithLocations>(query);
return result.rows; return result.rows;
} catch (error) { } catch (error) {
handleDbError(error, logger, 'Database error in getAllStoresWithLocations', {}, { handleDbError(
defaultMessage: 'Failed to retrieve stores with locations.', error,
}); logger,
'Database error in getAllStoresWithLocations',
{},
{
defaultMessage: 'Failed to retrieve stores with locations.',
},
);
} }
} }

View File

@@ -253,7 +253,7 @@ describe('Email Service (Server)', () => {
name: 'email-job', name: 'email-job',
data, data,
attemptsMade: 1, attemptsMade: 1,
} as unknown as Job<EmailJobData>); }) as unknown as Job<EmailJobData>;
it('should call sendMail with job data and log success', async () => { it('should call sendMail with job data and log success', async () => {
const job = createMockJob(mockJobData); const job = createMockJob(mockJobData);

View File

@@ -5,7 +5,11 @@ import { getPool } from '../../services/db/connection.db';
import type { UserProfile } from '../../types'; import type { UserProfile } from '../../types';
import { createAndLoginUser, TEST_EXAMPLE_DOMAIN } from '../utils/testHelpers'; import { createAndLoginUser, TEST_EXAMPLE_DOMAIN } from '../utils/testHelpers';
import { cleanupDb } from '../utils/cleanup'; import { cleanupDb } from '../utils/cleanup';
import { createStoreWithLocation, cleanupStoreLocations, type CreatedStoreLocation } from '../utils/storeHelpers'; import {
createStoreWithLocation,
cleanupStoreLocations,
type CreatedStoreLocation,
} from '../utils/storeHelpers';
/** /**
* @vitest-environment node * @vitest-environment node

View File

@@ -1325,9 +1325,7 @@ export const createMockAddress = (overrides: Partial<Address> = {}): Address =>
* @param overrides - An object containing properties to override the default mock values. * @param overrides - An object containing properties to override the default mock values.
* @returns A complete and type-safe StoreLocation object. * @returns A complete and type-safe StoreLocation object.
*/ */
export const createMockStoreLocation = ( export const createMockStoreLocation = (overrides: Partial<StoreLocation> = {}): StoreLocation => {
overrides: Partial<StoreLocation> = {},
): StoreLocation => {
const defaultStoreLocation: StoreLocation = { const defaultStoreLocation: StoreLocation = {
store_location_id: getNextId(), store_location_id: getNextId(),
store_id: overrides.store_id ?? getNextId(), store_id: overrides.store_id ?? getNextId(),
@@ -1349,7 +1347,9 @@ export const createMockStoreLocation = (
* @returns A complete and type-safe StoreLocationWithAddress object. * @returns A complete and type-safe StoreLocationWithAddress object.
*/ */
export const createMockStoreLocationWithAddress = ( export const createMockStoreLocationWithAddress = (
overrides: Omit<Partial<StoreLocationWithAddress>, 'address'> & { address?: Partial<Address> } = {}, overrides: Omit<Partial<StoreLocationWithAddress>, 'address'> & {
address?: Partial<Address>;
} = {},
): StoreLocationWithAddress => { ): StoreLocationWithAddress => {
// Create the address first, using the address_id from overrides if provided // Create the address first, using the address_id from overrides if provided
const address = createMockAddress({ const address = createMockAddress({
@@ -1380,23 +1380,24 @@ export const createMockStoreLocationWithAddress = (
*/ */
export const createMockStoreWithLocations = ( export const createMockStoreWithLocations = (
overrides: Omit<Partial<StoreWithLocations>, 'locations'> & { overrides: Omit<Partial<StoreWithLocations>, 'locations'> & {
locations?: Array<Omit<Partial<StoreLocationWithAddress>, 'address'> & { address?: Partial<Address> }>; locations?: Array<
Omit<Partial<StoreLocationWithAddress>, 'address'> & { address?: Partial<Address> }
>;
} = {}, } = {},
): StoreWithLocations => { ): StoreWithLocations => {
const store = createMockStore(overrides); const store = createMockStore(overrides);
// If locations are provided, create them; otherwise create one default location // If locations are provided, create them; otherwise create one default location
const locations = const locations = overrides.locations?.map((locOverride) =>
overrides.locations?.map((locOverride) => createMockStoreLocationWithAddress({
createMockStoreLocationWithAddress({ ...locOverride,
...locOverride, store_id: store.store_id,
store_id: store.store_id, }),
}), ) ?? [
) ?? [ createMockStoreLocationWithAddress({
createMockStoreLocationWithAddress({ store_id: store.store_id,
store_id: store.store_id, }),
}), ];
];
return { return {
...store, ...store,

View File

@@ -119,9 +119,10 @@ export async function cleanupStoreLocations(
const addressIds = locations.map((l) => l.addressId); const addressIds = locations.map((l) => l.addressId);
// Delete in reverse order of creation // Delete in reverse order of creation
await pool.query('DELETE FROM public.store_locations WHERE store_location_id = ANY($1::bigint[])', [ await pool.query(
storeLocationIds, 'DELETE FROM public.store_locations WHERE store_location_id = ANY($1::bigint[])',
]); [storeLocationIds],
);
await pool.query('DELETE FROM public.stores WHERE store_id = ANY($1::bigint[])', [storeIds]); await pool.query('DELETE FROM public.stores WHERE store_id = ANY($1::bigint[])', [storeIds]);
await pool.query('DELETE FROM public.addresses WHERE address_id = ANY($1::bigint[])', [ await pool.query('DELETE FROM public.addresses WHERE address_id = ANY($1::bigint[])', [
addressIds, addressIds,