massive fixes to stores and addresses
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 18m46s
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 18m46s
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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.',
|
||||||
|
|||||||
@@ -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');
|
||||||
|
|||||||
@@ -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.',
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.',
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user