Tests refactor
This commit is contained in:
parent
245520fb50
commit
99134d8556
165 changed files with 911 additions and 531 deletions
|
|
@ -1,254 +0,0 @@
|
|||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
|
||||
const {
|
||||
mockFind,
|
||||
mockFindOne,
|
||||
mockFindOneAndUpdate,
|
||||
mockFindOneAndDelete,
|
||||
mockSave,
|
||||
mockAggregate,
|
||||
mockUpdateMany,
|
||||
mockFindByIdAndUpdate,
|
||||
} = vi.hoisted(() => ({
|
||||
mockFind: vi.fn(),
|
||||
mockFindOne: vi.fn(),
|
||||
mockFindOneAndUpdate: vi.fn(),
|
||||
mockFindOneAndDelete: vi.fn(),
|
||||
mockSave: vi.fn(),
|
||||
mockAggregate: vi.fn(),
|
||||
mockUpdateMany: vi.fn(),
|
||||
mockFindByIdAndUpdate: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('../../schemas/pantry-item.schema.js', () => {
|
||||
const chain = () => ({
|
||||
sort: vi.fn().mockReturnThis(),
|
||||
limit: vi.fn().mockReturnThis(),
|
||||
lean: vi.fn().mockReturnThis(),
|
||||
exec: mockFind,
|
||||
});
|
||||
|
||||
const findOneChain = () => ({
|
||||
lean: vi.fn().mockReturnThis(),
|
||||
exec: mockFindOne,
|
||||
});
|
||||
|
||||
const updateChain = () => ({
|
||||
lean: vi.fn().mockReturnThis(),
|
||||
exec: mockFindOneAndUpdate,
|
||||
});
|
||||
|
||||
const deleteChain = () => ({
|
||||
exec: mockFindOneAndDelete,
|
||||
});
|
||||
|
||||
const updateByIdChain = () => ({
|
||||
exec: mockFindByIdAndUpdate,
|
||||
});
|
||||
|
||||
const updateManyChain = () => ({
|
||||
exec: mockUpdateMany,
|
||||
});
|
||||
|
||||
const aggChain = () => ({
|
||||
exec: mockAggregate,
|
||||
});
|
||||
|
||||
class FakeModel {
|
||||
data: unknown;
|
||||
constructor(data: unknown) {
|
||||
this.data = data;
|
||||
}
|
||||
save() {
|
||||
mockSave(this.data);
|
||||
return Promise.resolve({ toObject: () => this.data });
|
||||
}
|
||||
static find = vi.fn(() => chain());
|
||||
static findOne = vi.fn(() => findOneChain());
|
||||
static findOneAndUpdate = vi.fn(() => updateChain());
|
||||
static findOneAndDelete = vi.fn(() => deleteChain());
|
||||
static findByIdAndUpdate = vi.fn(() => updateByIdChain());
|
||||
static updateMany = vi.fn(() => updateManyChain());
|
||||
static aggregate = vi.fn(() => aggChain());
|
||||
}
|
||||
|
||||
return { PantryItemModel: FakeModel };
|
||||
});
|
||||
|
||||
import { PantryRepository } from './pantry.repository.js';
|
||||
|
||||
describe(PantryRepository.name, () => {
|
||||
let repo: PantryRepository;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
repo = new PantryRepository();
|
||||
});
|
||||
|
||||
describe('findByHousehold', () => {
|
||||
it('returns paginated results', async () => {
|
||||
const items = [{ _id: { toString: () => 'id1' } }];
|
||||
mockFind.mockResolvedValue(items);
|
||||
|
||||
const result = await repo.findByHousehold('hh1', { limit: 20 });
|
||||
expect(result.data).toHaveLength(1);
|
||||
expect(result.pagination.hasMore).toBe(false);
|
||||
});
|
||||
|
||||
it('handles hasMore', async () => {
|
||||
const items = Array.from({ length: 3 }, (_, i) => ({
|
||||
_id: { toString: () => `id${i}` },
|
||||
}));
|
||||
mockFind.mockResolvedValue(items);
|
||||
|
||||
const result = await repo.findByHousehold('hh1', { limit: 2 });
|
||||
expect(result.data).toHaveLength(2);
|
||||
expect(result.pagination.hasMore).toBe(true);
|
||||
});
|
||||
|
||||
it('applies storageLocation filter', async () => {
|
||||
mockFind.mockResolvedValue([]);
|
||||
await repo.findByHousehold('hh1', { storageLocation: 'fridge', limit: 20 });
|
||||
expect(mockFind).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('applies status filter with single value', async () => {
|
||||
mockFind.mockResolvedValue([]);
|
||||
await repo.findByHousehold('hh1', { status: 'sealed', limit: 20 });
|
||||
expect(mockFind).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('applies status filter with multiple values', async () => {
|
||||
mockFind.mockResolvedValue([]);
|
||||
await repo.findByHousehold('hh1', { status: 'sealed,opened', limit: 20 });
|
||||
expect(mockFind).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('applies urgency filter', async () => {
|
||||
mockFind.mockResolvedValue([]);
|
||||
await repo.findByHousehold('hh1', { urgency: 'urgent,check', limit: 20 });
|
||||
expect(mockFind).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('applies single urgency filter', async () => {
|
||||
mockFind.mockResolvedValue([]);
|
||||
await repo.findByHousehold('hh1', { urgency: 'urgent', limit: 20 });
|
||||
expect(mockFind).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('applies productId filter', async () => {
|
||||
mockFind.mockResolvedValue([]);
|
||||
await repo.findByHousehold('hh1', { productId: 'p1', limit: 20 });
|
||||
expect(mockFind).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('applies cursor', async () => {
|
||||
const cursor = Buffer.from('abc').toString('base64');
|
||||
mockFind.mockResolvedValue([]);
|
||||
await repo.findByHousehold('hh1', { cursor, limit: 20 });
|
||||
expect(mockFind).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('findById', () => {
|
||||
it('returns item', async () => {
|
||||
mockFindOne.mockResolvedValue({ _id: 'id1' });
|
||||
const result = await repo.findById('id1', 'hh1');
|
||||
expect(result).toEqual({ _id: 'id1' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('findExpiringSoon', () => {
|
||||
it('returns items expiring within days', async () => {
|
||||
mockFind.mockResolvedValue([]);
|
||||
const result = await repo.findExpiringSoon('hh1', 7);
|
||||
expect(result.pagination.hasMore).toBe(false);
|
||||
});
|
||||
|
||||
it('supports cursor', async () => {
|
||||
const cursor = Buffer.from('abc').toString('base64');
|
||||
mockFind.mockResolvedValue([]);
|
||||
const result = await repo.findExpiringSoon('hh1', 7, cursor, 20);
|
||||
expect(result.pagination.hasMore).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('findActiveByHousehold', () => {
|
||||
it('returns active items', async () => {
|
||||
mockFind.mockResolvedValue([{ _id: 'id1' }]);
|
||||
const result = await repo.findActiveByHousehold('hh1');
|
||||
expect(result).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('create', () => {
|
||||
it('saves and returns item', async () => {
|
||||
const data = { name: 'test' };
|
||||
const result = await repo.create(data);
|
||||
expect(mockSave).toHaveBeenCalled();
|
||||
expect(result).toEqual(data);
|
||||
});
|
||||
});
|
||||
|
||||
describe('update', () => {
|
||||
it('updates and returns item', async () => {
|
||||
mockFindOneAndUpdate.mockResolvedValue({ _id: 'id1' });
|
||||
const result = await repo.update('id1', 'hh1', { quantity: 3 });
|
||||
expect(result).toEqual({ _id: 'id1' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateFreshness', () => {
|
||||
it('updates freshness estimate', async () => {
|
||||
mockFindByIdAndUpdate.mockResolvedValue(undefined);
|
||||
await repo.updateFreshness('id1', { urgency: 'fresh' });
|
||||
expect(mockFindByIdAndUpdate).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('updates freshness and status', async () => {
|
||||
mockFindByIdAndUpdate.mockResolvedValue(undefined);
|
||||
await repo.updateFreshness('id1', { urgency: 'expired' }, 'expired');
|
||||
expect(mockFindByIdAndUpdate).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('delete', () => {
|
||||
it('deletes item', async () => {
|
||||
mockFindOneAndDelete.mockResolvedValue({ _id: 'id1' });
|
||||
await repo.delete('id1', 'hh1');
|
||||
expect(mockFindOneAndDelete).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getWasteStats', () => {
|
||||
it('returns aggregation result', async () => {
|
||||
mockAggregate.mockResolvedValue([{ totalConsumed: 5, totalDiscarded: 2 }]);
|
||||
const result = await repo.getWasteStats('hh1', new Date(), new Date());
|
||||
expect(result).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTopWastedProducts', () => {
|
||||
it('returns top wasted products', async () => {
|
||||
mockAggregate.mockResolvedValue([{ productId: 'p1', productName: 'Milk', count: 3 }]);
|
||||
const result = await repo.getTopWastedProducts('hh1', new Date(), new Date());
|
||||
expect(result).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('findByIds', () => {
|
||||
it('returns items by ids', async () => {
|
||||
mockFind.mockResolvedValue([{ _id: 'id1' }]);
|
||||
const result = await repo.findByIds(['id1'], 'hh1');
|
||||
expect(result).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('bulkUpdateStatus', () => {
|
||||
it('returns modified count', async () => {
|
||||
mockUpdateMany.mockResolvedValue({ modifiedCount: 2 });
|
||||
const result = await repo.bulkUpdateStatus(['id1', 'id2'], 'hh1', 'consumed' as never);
|
||||
expect(result).toBe(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue