Tests refactor

This commit is contained in:
Aerilyn Weber 2026-05-19 11:06:03 +09:00
parent 245520fb50
commit 99134d8556
165 changed files with 911 additions and 531 deletions

View file

@ -1,162 +0,0 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { PricesRepository } from './prices.repository.js';
const { mockSave, MockPriceRecordModel } = vi.hoisted(() => {
const mockSave = vi.fn();
function MockModel(this: { save: typeof mockSave }, data: unknown) {
Object.assign(this, data);
this.save = mockSave;
}
Object.assign(MockModel, {
findOne: vi.fn(),
find: vi.fn(),
findOneAndUpdate: vi.fn(),
insertMany: vi.fn(),
aggregate: vi.fn(),
});
return { mockSave, MockPriceRecordModel: MockModel };
});
vi.mock('../../schemas/price-record.schema.js', () => ({
PriceRecordModel: MockPriceRecordModel,
}));
const { PriceRecordModel } = await import('../../schemas/price-record.schema.js');
function makeChain(result: unknown = null) {
return {
sort: vi.fn().mockReturnThis(),
limit: vi.fn().mockReturnThis(),
lean: vi.fn().mockReturnThis(),
exec: vi.fn().mockResolvedValue(result),
};
}
describe(PricesRepository.name, () => {
let repo: PricesRepository;
beforeEach(() => {
vi.clearAllMocks();
repo = new PricesRepository();
});
describe('create', () => {
it('saves and returns new document toObject', async () => {
const data = { householdId: 'h1', productId: 'p1', productName: 'Apple', storeId: 's1', storeName: 'Store', price: 1, currency: 'USD', quantity: 1, unit: 'g', pricePerUnit: 1, date: new Date(), createdBy: 'u1' };
mockSave.mockResolvedValue({ toObject: () => ({ ...data, _id: 'id1' }) });
const result = await repo.create(data);
expect(mockSave).toHaveBeenCalled();
expect(result._id).toBe('id1');
});
});
describe('createMany', () => {
it('inserts multiple records and returns mapped toObjects', async () => {
const inputs = [{ price: 1 }, { price: 2 }];
const returns = inputs.map((x, idx) => ({ ...x, _id: `id${idx}`, toObject: function() { return this; } }));
vi.mocked(PriceRecordModel.insertMany).mockResolvedValue(returns as any);
const result = await repo.createMany(inputs as any);
expect(PriceRecordModel.insertMany).toHaveBeenCalledWith(inputs);
expect(result).toHaveLength(2);
expect(result[0]._id).toBe('id0');
});
});
describe('findByProduct', () => {
it('applies complex filters and pagination cursor decoding/encoding', async () => {
const baseFilter = { householdId: 'h1', productId: 'prod1' };
const startDate = new Date('2026-01-01').toISOString();
const endDate = new Date('2026-01-10').toISOString();
const cursorId = '507f1f77bcf86cd799439011';
const cursorStr = Buffer.from(cursorId).toString('base64');
const mockItems = [
{ _id: '607f1f77bcf86cd799439012', price: 10 },
{ _id: '607f1f77bcf86cd799439013', price: 12 }
];
const chain = makeChain(mockItems);
vi.mocked(PriceRecordModel.find).mockReturnValue(chain as any);
const result = await repo.findByProduct('h1', 'prod1', {
storeId: 'st1',
startDate,
endDate,
cursor: cursorStr,
limit: 2
});
expect(PriceRecordModel.find).toHaveBeenCalledWith({
householdId: 'h1',
productId: 'prod1',
storeId: 'st1',
date: {
$gte: new Date(startDate),
$lte: new Date(endDate),
},
_id: { $lt: cursorId }
});
expect(result.data).toHaveLength(2);
expect(result.pagination.hasMore).toBe(false);
});
it('correctly indicates hasMore and generates next base64 cursor', async () => {
const mockItems = [
{ _id: '607f1f77bcf86cd799439011', price: 10 },
{ _id: '607f1f77bcf86cd799439012', price: 11 },
{ _id: '607f1f77bcf86cd799439013', price: 12 }
];
const chain = makeChain(mockItems);
vi.mocked(PriceRecordModel.find).mockReturnValue(chain as any);
const result = await repo.findByProduct('h1', 'prod1', { limit: 2 });
expect(result.data).toHaveLength(2);
expect(result.pagination.hasMore).toBe(true);
expect(result.pagination.cursor).toBe(Buffer.from('607f1f77bcf86cd799439012').toString('base64'));
});
});
describe('compareStores', () => {
it('runs group/aggregate queries ordered by deviance', async () => {
const mockAggResult = [
{ _id: 's1', storeName: 'Cheap', latestPrice: 10, latestPricePerUnit: 1, currency: 'USD', date: new Date() }
];
vi.mocked(PriceRecordModel.aggregate).mockReturnValue({
exec: vi.fn().mockResolvedValue(mockAggResult)
} as any);
const result = await repo.compareStores('h1', 'p1');
expect(PriceRecordModel.aggregate).toHaveBeenCalled();
expect(result).toHaveLength(1);
expect(result[0].storeId).toBe('s1');
expect(result[0].latestPricePerUnit).toBe(1);
});
});
describe('getLatestForProduct', () => {
it('queries latest pricing document ordered by date descending', async () => {
const chain = makeChain({ _id: 'pr1' });
vi.mocked(PriceRecordModel.findOne).mockReturnValue(chain as any);
await repo.getLatestForProduct('h1', 'p1', 's1');
expect(PriceRecordModel.findOne).toHaveBeenCalledWith({ householdId: 'h1', productId: 'p1', storeId: 's1' });
expect(chain.sort).toHaveBeenCalledWith({ date: -1 });
});
});
describe('getAnalytics', () => {
it('executes Promise.all parallel pipeline aggregations for periods, buckets, categories, and inflation', async () => {
const mockExec = vi.fn().mockResolvedValue([]);
vi.mocked(PriceRecordModel.aggregate).mockReturnValue({
exec: mockExec
} as any);
await repo.getAnalytics('h1');
// 4 explicit pipeline calls should have fired in Promise.all + inflation alert
expect(PriceRecordModel.aggregate).toHaveBeenCalledTimes(4);
});
});
});